linux/arch/x86/include/asm/imr.h

61 lines
1.8 KiB
C
Raw Normal View History

x86/intel/quark: Add Isolated Memory Regions for Quark X1000 Intel's Quark X1000 SoC contains a set of registers called Isolated Memory Regions. IMRs are accessed over the IOSF mailbox interface. IMRs are areas carved out of memory that define read/write access rights to the various system agents within the Quark system. For a given agent in the system it is possible to specify if that agent may read or write an area of memory defined by an IMR with a granularity of 1 KiB. Quark_SecureBootPRM_330234_001.pdf section 4.5 details the concept of IMRs quark-x1000-datasheet.pdf section 12.7.4 details the implementation of IMRs in silicon. eSRAM flush, CPU Snoop write-only, CPU SMM Mode, CPU non-SMM mode, RMU and PCIe Virtual Channels (VC0 and VC1) can have individual read/write access masks applied to them for a given memory region in Quark X1000. This enables IMRs to treat each memory transaction type listed above on an individual basis and to filter appropriately based on the IMR access mask for the memory region. Quark supports eight IMRs. Since all of the DMA capable SoC components in the X1000 are mapped to VC0 it is possible to define sections of memory as invalid for DMA write operations originating from Ethernet, USB, SD and any other DMA capable south-cluster component on VC0. Similarly it is possible to mark kernel memory as non-SMM mode read/write only or to mark BIOS runtime memory as SMM mode accessible only depending on the particular memory footprint on a given system. On an IMR violation Quark SoC X1000 systems are configured to reset the system, so ensuring that the IMR memory map is consistent with the EFI provided memory map is critical to ensure no IMR violations reset the system. The API for accessing IMRs is based on MTRR code but doesn't provide a /proc or /sys interface to manipulate IMRs. Defining the size and extent of IMRs is exclusively the domain of in-kernel code. Quark firmware sets up a series of locked IMRs around pieces of memory that firmware owns such as ACPI runtime data. During boot a series of unlocked IMRs are placed around items in memory to guarantee no DMA modification of those items can take place. Grub also places an unlocked IMR around the kernel boot params data structure and compressed kernel image. It is necessary for the kernel to tear down all unlocked IMRs in order to ensure that the kernel's view of memory passed via the EFI memory map is consistent with the IMR memory map. Without tearing down all unlocked IMRs on boot transitory IMRs such as those used to protect the compressed kernel image will cause IMR violations and system reboots. The IMR init code tears down all unlocked IMRs and sets a protective IMR around the kernel .text and .rodata as one contiguous block. This sanitizes the IMR memory map with respect to the EFI memory map and protects the read-only portions of the kernel from unwarranted DMA access. Tested-by: Ong, Boon Leong <boon.leong.ong@intel.com> Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie> Reviewed-by: Andy Shevchenko <andy.schevchenko@gmail.com> Reviewed-by: Darren Hart <dvhart@linux.intel.com> Reviewed-by: Ong, Boon Leong <boon.leong.ong@intel.com> Cc: andy.shevchenko@gmail.com Cc: dvhart@infradead.org Link: http://lkml.kernel.org/r/1422635379-12476-2-git-send-email-pure.logic@nexus-software.ie Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-01-31 00:29:38 +08:00
/*
* imr.h: Isolated Memory Region API
*
* Copyright(c) 2013 Intel Corporation.
* Copyright(c) 2015 Bryan O'Donoghue <pure.logic@nexus-software.ie>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License.
*/
#ifndef _IMR_H
#define _IMR_H
#include <linux/types.h>
/*
* IMR agent access mask bits
* See section 12.7.4.7 from quark-x1000-datasheet.pdf for register
* definitions.
*/
#define IMR_ESRAM_FLUSH BIT(31)
#define IMR_CPU_SNOOP BIT(30) /* Applicable only to write */
#define IMR_RMU BIT(29)
#define IMR_VC1_SAI_ID3 BIT(15)
#define IMR_VC1_SAI_ID2 BIT(14)
#define IMR_VC1_SAI_ID1 BIT(13)
#define IMR_VC1_SAI_ID0 BIT(12)
#define IMR_VC0_SAI_ID3 BIT(11)
#define IMR_VC0_SAI_ID2 BIT(10)
#define IMR_VC0_SAI_ID1 BIT(9)
#define IMR_VC0_SAI_ID0 BIT(8)
#define IMR_CPU_0 BIT(1) /* SMM mode */
#define IMR_CPU BIT(0) /* Non SMM mode */
#define IMR_ACCESS_NONE 0
/*
* Read/Write access-all bits here include some reserved bits
* These are the values firmware uses and are accepted by hardware.
* The kernel defines read/write access-all in the same way as firmware
* in order to have a consistent and crisp definition across firmware,
* bootloader and kernel.
*/
#define IMR_READ_ACCESS_ALL 0xBFFFFFFF
#define IMR_WRITE_ACCESS_ALL 0xFFFFFFFF
/* Number of IMRs provided by Quark X1000 SoC */
#define QUARK_X1000_IMR_MAX 0x08
#define QUARK_X1000_IMR_REGBASE 0x40
/* IMR alignment bits - only bits 31:10 are checked for IMR validity */
#define IMR_ALIGN 0x400
#define IMR_MASK (IMR_ALIGN - 1)
int imr_add_range(phys_addr_t base, size_t size,
unsigned int rmask, unsigned int wmask, bool lock);
int imr_remove_range(phys_addr_t base, size_t size);
#endif /* _IMR_H */