Unverified Commit 44c92257 authored by Vitaly Wool's avatar Vitaly Wool Committed by Palmer Dabbelt
Browse files

RISC-V: enable XIP



Introduce XIP (eXecute In Place) support for RISC-V platforms.
It allows code to be executed directly from non-volatile storage
directly addressable by the CPU, such as QSPI NOR flash which can
be found on many RISC-V platforms. This makes way for significant
optimization of RAM footprint. The XIP kernel is not compressed
since it has to run directly from flash, so it will occupy more
space on the non-volatile storage. The physical flash address used
to link the kernel object files and for storing it has to be known
at compile time and is represented by a Kconfig option.

XIP on RISC-V will for the time being only work on MMU-enabled
kernels.

Signed-off-by: default avatarVitaly Wool <vitaly.wool@konsulko.com>
[Alex: Rebase on top of "Move kernel mapping outside the linear mapping" ]
Signed-off-by: default avatarAlexandre Ghiti <alex@ghiti.fr>
[Palmer: disable XIP for allyesconfig]
Signed-off-by: default avatarPalmer Dabbelt <palmerdabbelt@google.com>
parent 56409750
Loading
Loading
Loading
Loading
+56 −4
Original line number Diff line number Diff line
@@ -28,8 +28,8 @@ config RISCV
	select ARCH_HAS_PTE_SPECIAL
	select ARCH_HAS_SET_DIRECT_MAP
	select ARCH_HAS_SET_MEMORY
	select ARCH_HAS_STRICT_KERNEL_RWX if MMU
	select ARCH_HAS_STRICT_MODULE_RWX if MMU
	select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL
	select ARCH_HAS_STRICT_MODULE_RWX if MMU && !XIP_KERNEL
	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
	select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX
	select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
@@ -468,7 +468,7 @@ config EFI_STUB

config EFI
	bool "UEFI runtime support"
	depends on OF
	depends on OF && !XIP_KERNEL
	select LIBFDT
	select UCS2_STRING
	select EFI_PARAMS_FROM_FDT
@@ -492,11 +492,63 @@ config STACKPROTECTOR_PER_TASK
	def_bool y
	depends on STACKPROTECTOR && CC_HAVE_STACKPROTECTOR_TLS

config PHYS_RAM_BASE_FIXED
	bool "Explicitly specified physical RAM address"
	default n

config PHYS_RAM_BASE
	hex "Platform Physical RAM address"
	depends on PHYS_RAM_BASE_FIXED
	default "0x80000000"
	help
	  This is the physical address of RAM in the system. It has to be
	  explicitly specified to run early relocations of read-write data
	  from flash to RAM.

config XIP_KERNEL
	bool "Kernel Execute-In-Place from ROM"
	depends on MMU && SPARSEMEM
	# This prevents XIP from being enabled by all{yes,mod}config, which
	# fail to build since XIP doesn't support large kernels.
	depends on !COMPILE_TEST
	select PHYS_RAM_BASE_FIXED
	help
	  Execute-In-Place allows the kernel to run from non-volatile storage
	  directly addressable by the CPU, such as NOR flash. This saves RAM
	  space since the text section of the kernel is not loaded from flash
	  to RAM.  Read-write sections, such as the data section and stack,
	  are still copied to RAM.  The XIP kernel is not compressed since
	  it has to run directly from flash, so it will take more space to
	  store it.  The flash address used to link the kernel object files,
	  and for storing it, is configuration dependent. Therefore, if you
	  say Y here, you must know the proper physical address where to
	  store the kernel image depending on your own flash memory usage.

	  Also note that the make target becomes "make xipImage" rather than
	  "make zImage" or "make Image".  The final kernel binary to put in
	  ROM memory will be arch/riscv/boot/xipImage.

	  SPARSEMEM is required because the kernel text and rodata that are
	  flash resident are not backed by memmap, then any attempt to get
	  a struct page on those regions will trigger a fault.

	  If unsure, say N.

config XIP_PHYS_ADDR
	hex "XIP Kernel Physical Location"
	depends on XIP_KERNEL
	default "0x21000000"
	help
	  This is the physical address in your flash memory the kernel will
	  be linked for and stored to.  This address is dependent on your
	  own flash usage.

endmenu

config BUILTIN_DTB
	def_bool n
	bool
	depends on OF
	default y if XIP_KERNEL

menu "Power management options"

+7 −1
Original line number Diff line number Diff line
@@ -82,7 +82,11 @@ CHECKFLAGS += -D__riscv -D__riscv_xlen=$(BITS)

# Default target when executing plain make
boot		:= arch/riscv/boot
ifeq ($(CONFIG_XIP_KERNEL),y)
KBUILD_IMAGE := $(boot)/xipImage
else
KBUILD_IMAGE	:= $(boot)/Image.gz
endif

head-y := arch/riscv/kernel/head.o

@@ -96,12 +100,14 @@ PHONY += vdso_install
vdso_install:
	$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@

ifneq ($(CONFIG_XIP_KERNEL),y)
ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_CANAAN),yy)
KBUILD_IMAGE := $(boot)/loader.bin
else
KBUILD_IMAGE := $(boot)/Image.gz
endif
BOOT_TARGETS := Image Image.gz loader loader.bin
endif
BOOT_TARGETS := Image Image.gz loader loader.bin xipImage

all:	$(notdir $(KBUILD_IMAGE))

+13 −0
Original line number Diff line number Diff line
@@ -17,8 +17,21 @@
KCOV_INSTRUMENT := n

OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
OBJCOPYFLAGS_xipImage :=-O binary -R .note -R .note.gnu.build-id -R .comment -S

targets := Image Image.* loader loader.o loader.lds loader.bin
targets := Image Image.* loader loader.o loader.lds loader.bin xipImage

ifeq ($(CONFIG_XIP_KERNEL),y)

quiet_cmd_mkxip = $(quiet_cmd_objcopy)
cmd_mkxip = $(cmd_objcopy)

$(obj)/xipImage: vmlinux FORCE
	$(call if_changed,mkxip)
	@$(kecho) '  Physical Address of xipImage: $(CONFIG_XIP_PHYS_ADDR)'

endif

$(obj)/Image: vmlinux FORCE
	$(call if_changed,objcopy)
+21 −0
Original line number Diff line number Diff line
@@ -93,6 +93,9 @@ extern unsigned long va_pa_offset;
#ifdef CONFIG_64BIT
extern unsigned long va_kernel_pa_offset;
#endif
#ifdef CONFIG_XIP_KERNEL
extern unsigned long va_kernel_xip_pa_offset;
#endif
extern unsigned long pfn_base;
#define ARCH_PFN_OFFSET		(pfn_base)
#else
@@ -107,11 +110,29 @@ extern unsigned long pfn_base;
extern unsigned long kernel_virt_addr;

#define linear_mapping_pa_to_va(x)	((void *)((unsigned long)(x) + va_pa_offset))
#ifdef CONFIG_XIP_KERNEL
#define kernel_mapping_pa_to_va(y)	({						\
	unsigned long _y = y;								\
	(_y >= CONFIG_PHYS_RAM_BASE) ?							\
		(void *)((unsigned long)(_y) + va_kernel_pa_offset + XIP_OFFSET) :	\
		(void *)((unsigned long)(_y) + va_kernel_xip_pa_offset);		\
	})
#else
#define kernel_mapping_pa_to_va(x)	((void *)((unsigned long)(x) + va_kernel_pa_offset))
#endif
#define __pa_to_va_nodebug(x)		linear_mapping_pa_to_va(x)

#define linear_mapping_va_to_pa(x)	((unsigned long)(x) - va_pa_offset)
#ifdef CONFIG_XIP_KERNEL
#define kernel_mapping_va_to_pa(y) ({						\
	unsigned long _y = y;							\
	(_y < kernel_virt_addr + XIP_OFFSET) ?					\
		((unsigned long)(_y) - va_kernel_xip_pa_offset) :		\
		((unsigned long)(_y) - va_kernel_pa_offset - XIP_OFFSET);	\
	})
#else
#define kernel_mapping_va_to_pa(x)	((unsigned long)(x) - va_kernel_pa_offset)
#endif
#define __va_to_pa_nodebug(x)	({						\
	unsigned long _x = x;							\
	(_x < kernel_virt_addr) ?						\
+23 −2
Original line number Diff line number Diff line
@@ -72,6 +72,19 @@
#define FIXADDR_SIZE     PGDIR_SIZE
#endif
#define FIXADDR_START    (FIXADDR_TOP - FIXADDR_SIZE)

#ifdef CONFIG_XIP_KERNEL
#define XIP_OFFSET		SZ_8M
#define XIP_FIXUP(addr) ({							\
	uintptr_t __a = (uintptr_t)(addr);					\
	(__a >= CONFIG_XIP_PHYS_ADDR && __a < CONFIG_XIP_PHYS_ADDR + SZ_16M) ?	\
		__a - CONFIG_XIP_PHYS_ADDR + CONFIG_PHYS_RAM_BASE - XIP_OFFSET :\
		__a;								\
	})
#else
#define XIP_FIXUP(addr)		(addr)
#endif /* CONFIG_XIP_KERNEL */

#endif

#ifndef __ASSEMBLY__
@@ -507,8 +520,16 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
#define kern_addr_valid(addr)   (1) /* FIXME */

extern char _start[];
extern void *dtb_early_va;
extern uintptr_t dtb_early_pa;
extern void *_dtb_early_va;
extern uintptr_t _dtb_early_pa;
#if defined(CONFIG_XIP_KERNEL) && defined(CONFIG_MMU)
#define dtb_early_va	(*(void **)XIP_FIXUP(&_dtb_early_va))
#define dtb_early_pa	(*(uintptr_t *)XIP_FIXUP(&_dtb_early_pa))
#else
#define dtb_early_va	_dtb_early_va
#define dtb_early_pa	_dtb_early_pa
#endif /* CONFIG_XIP_KERNEL */

void setup_bootmem(void);
void paging_init(void);
void misc_mem_init(void);
Loading