xtensa: add XIP kernel support

XIP (eXecute In Place) kernel image is the image that can be run
directly from ROM, using RAM only for writable data.

XIP xtensa kernel differs from regular xtensa kernel in the following
ways:
- it has exception/IRQ vectors merged into text section. No vectors
  relocation takes place at kernel startup.
- .data/.bss location must be specified in the kernel configuration,
  its content is copied there in the _startup function.
- .init.text is merged with the rest of text and is executed from ROM.
- when MMU is used the virtual address where the kernel will be mapped
  must be specified in the kernel configuration. It may be in the KSEG
  or in the KIO, __pa macro is adjusted to be able to handle both.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
This commit is contained in:
Max Filippov 2017-01-03 17:57:51 -08:00
parent 76743c0e09
commit 7af710d988
10 changed files with 257 additions and 5 deletions

View File

@ -19,8 +19,8 @@ config XTENSA
select GENERIC_PCI_IOMAP select GENERIC_PCI_IOMAP
select GENERIC_SCHED_CLOCK select GENERIC_SCHED_CLOCK
select GENERIC_STRNCPY_FROM_USER if KASAN select GENERIC_STRNCPY_FROM_USER if KASAN
select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
select HAVE_ARCH_KASAN if MMU select HAVE_ARCH_KASAN if MMU && !XIP_KERNEL
select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRACEHOOK
select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_CONTIGUOUS select HAVE_DMA_CONTIGUOUS
@ -299,6 +299,9 @@ config XTENSA_CALIBRATE_CCOUNT
config SERIAL_CONSOLE config SERIAL_CONSOLE
def_bool n def_bool n
config PLATFORM_HAVE_XIP
def_bool n
menu "Platform options" menu "Platform options"
choice choice
@ -325,6 +328,7 @@ config XTENSA_PLATFORM_XTFPGA
select PLATFORM_WANT_DEFAULT_MEM if !MMU select PLATFORM_WANT_DEFAULT_MEM if !MMU
select SERIAL_CONSOLE select SERIAL_CONSOLE
select XTENSA_CALIBRATE_CCOUNT select XTENSA_CALIBRATE_CCOUNT
select PLATFORM_HAVE_XIP
help help
XTFPGA is the name of Tensilica board family (LX60, LX110, LX200, ML605). XTFPGA is the name of Tensilica board family (LX60, LX110, LX200, ML605).
This hardware is capable of running a full Linux distribution. This hardware is capable of running a full Linux distribution.
@ -478,6 +482,27 @@ config INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
If in doubt, say Y. If in doubt, say Y.
config XIP_KERNEL
bool "Kernel Execute-In-Place from ROM"
depends on PLATFORM_HAVE_XIP
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 Image" or "make uImage". The final kernel binary to put in
ROM memory will be arch/xtensa/boot/xipImage.
If unsure, say N.
config MEMMAP_CACHEATTR config MEMMAP_CACHEATTR
hex "Cache attributes for the memory address space" hex "Cache attributes for the memory address space"
depends on !MMU depends on !MMU
@ -522,6 +547,16 @@ config KSEG_PADDR
If unsure, leave the default value here. If unsure, leave the default value here.
config KERNEL_VIRTUAL_ADDRESS
hex "Kernel virtual address"
depends on MMU && XIP_KERNEL
default 0xd0003000
help
This is the virtual address where the XIP kernel is mapped.
XIP kernel may be mapped into KSEG or KIO region, virtual address
provided here must match kernel load address provided in
KERNEL_LOAD_ADDRESS.
config KERNEL_LOAD_ADDRESS config KERNEL_LOAD_ADDRESS
hex "Kernel load address" hex "Kernel load address"
default 0x60003000 if !MMU default 0x60003000 if !MMU
@ -537,12 +572,21 @@ config KERNEL_LOAD_ADDRESS
config VECTORS_OFFSET config VECTORS_OFFSET
hex "Kernel vectors offset" hex "Kernel vectors offset"
default 0x00003000 default 0x00003000
depends on !XIP_KERNEL
help help
This is the offset of the kernel image from the relocatable vectors This is the offset of the kernel image from the relocatable vectors
base. base.
If unsure, leave the default value here. If unsure, leave the default value here.
config XIP_DATA_ADDR
hex "XIP kernel data virtual address"
depends on XIP_KERNEL
default 0x00000000
help
This is the virtual address where XIP kernel data is copied.
It must be within KSEG if MMU is used.
config PLATFORM_WANT_DEFAULT_MEM config PLATFORM_WANT_DEFAULT_MEM
def_bool n def_bool n

View File

@ -87,7 +87,7 @@ drivers-$(CONFIG_OPROFILE) += arch/xtensa/oprofile/
boot := arch/xtensa/boot boot := arch/xtensa/boot
all Image zImage uImage: vmlinux all Image zImage uImage xipImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $@ $(Q)$(MAKE) $(build)=$(boot) $@
archheaders: archheaders:
@ -97,4 +97,5 @@ define archhelp
@echo '* Image - Kernel ELF image with reset vector' @echo '* Image - Kernel ELF image with reset vector'
@echo '* zImage - Compressed kernel image (arch/xtensa/boot/images/zImage.*)' @echo '* zImage - Compressed kernel image (arch/xtensa/boot/images/zImage.*)'
@echo '* uImage - U-Boot wrapped image' @echo '* uImage - U-Boot wrapped image'
@echo ' xipImage - XIP image'
endef endef

View File

@ -29,6 +29,7 @@ all: $(boot-y)
Image: boot-elf Image: boot-elf
zImage: boot-redboot zImage: boot-redboot
uImage: $(obj)/uImage uImage: $(obj)/uImage
xipImage: $(obj)/xipImage
boot-elf boot-redboot: $(addprefix $(obj)/,$(subdir-y)) boot-elf boot-redboot: $(addprefix $(obj)/,$(subdir-y))
$(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS) $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS)
@ -50,3 +51,7 @@ UIMAGE_COMPRESSION = gzip
$(obj)/uImage: vmlinux.bin.gz FORCE $(obj)/uImage: vmlinux.bin.gz FORCE
$(call if_changed,uimage) $(call if_changed,uimage)
$(Q)$(kecho) ' Kernel: $@ is ready' $(Q)$(kecho) ' Kernel: $@ is ready'
$(obj)/xipImage: vmlinux FORCE
$(call if_changed,objcopy)
$(Q)$(kecho) ' Kernel: $@ is ready'

View File

@ -0,0 +1,119 @@
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_MEMCG=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_DEBUG=y
CONFIG_NAMESPACES=y
CONFIG_SCHED_AUTOGROUP=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_PROFILING=y
CONFIG_XTENSA_VARIANT_DC233C=y
CONFIG_XTENSA_UNALIGNED_USER=y
CONFIG_XIP_KERNEL=y
CONFIG_XIP_DATA_ADDR=0xd0000000
CONFIG_KERNEL_VIRTUAL_ADDRESS=0xe6000000
CONFIG_KERNEL_LOAD_ADDRESS=0xf6000000
CONFIG_XTENSA_KSEG_512M=y
CONFIG_HIGHMEM=y
CONFIG_XTENSA_PLATFORM_XTFPGA=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE="earlycon=uart8250,mmio32native,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug memmap=0x38000000@0"
CONFIG_USE_OF=y
CONFIG_BUILTIN_DTB_SOURCE="kc705"
# CONFIG_PARSE_BOOTPARAM is not set
CONFIG_OPROFILE=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_COMPACTION is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_STANDALONE is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_ARC is not set
# CONFIG_NET_VENDOR_AURORA is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_SAMSUNG is not set
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_NET_VENDOR_VIA is not set
# CONFIG_NET_VENDOR_WIZNET is not set
CONFIG_MARVELL_PHY=y
# CONFIG_WLAN is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
CONFIG_DEVKMEM=y
CONFIG_SERIAL_8250=y
# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
CONFIG_SOFT_WATCHDOG=y
# CONFIG_VGA_CONSOLE is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT3_FS=y
CONFIG_FANOTIFY=y
CONFIG_VFAT_FS=y
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_NFS_FS=y
CONFIG_NFS_V4=y
CONFIG_NFS_SWAP=y
CONFIG_ROOT_NFS=y
CONFIG_SUNRPC_DEBUG=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_CRYPTO_ECHAINIV=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_ANSI_CPRNG=y
CONFIG_PRINTK_TIME=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_INFO=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DETECT_HUNG_TASK=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_ATOMIC_SLEEP=y
CONFIG_STACKTRACE=y
CONFIG_RCU_TRACE=y
# CONFIG_FTRACE is not set
# CONFIG_S32C1I_SELFTEST is not set

View File

@ -31,4 +31,10 @@
#define ARCH_DMA_MINALIGN L1_CACHE_BYTES #define ARCH_DMA_MINALIGN L1_CACHE_BYTES
/*
* R/O after init is actually writable, it cannot go to .rodata
* according to vmlinux linker script.
*/
#define __ro_after_init __read_mostly
#endif /* _XTENSA_CACHE_H */ #endif /* _XTENSA_CACHE_H */

View File

@ -169,7 +169,18 @@ static inline unsigned long ___pa(unsigned long va)
if (off >= XCHAL_KSEG_SIZE) if (off >= XCHAL_KSEG_SIZE)
off -= XCHAL_KSEG_SIZE; off -= XCHAL_KSEG_SIZE;
#ifndef CONFIG_XIP_KERNEL
return off + PHYS_OFFSET; return off + PHYS_OFFSET;
#else
if (off < XCHAL_KSEG_SIZE)
return off + PHYS_OFFSET;
off -= XCHAL_KSEG_SIZE;
if (off >= XCHAL_KIO_SIZE)
off -= XCHAL_KIO_SIZE;
return off + XCHAL_KIO_PADDR;
#endif
} }
#define __pa(x) ___pa((unsigned long)(x)) #define __pa(x) ___pa((unsigned long)(x))
#else #else

View File

@ -22,9 +22,13 @@
#include <asm/kmem_layout.h> #include <asm/kmem_layout.h>
#if defined(CONFIG_MMU) && XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY #if defined(CONFIG_MMU) && XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
#ifdef CONFIG_KERNEL_VIRTUAL_ADDRESS
#define KERNELOFFSET CONFIG_KERNEL_VIRTUAL_ADDRESS
#else
#define KERNELOFFSET (CONFIG_KERNEL_LOAD_ADDRESS + \ #define KERNELOFFSET (CONFIG_KERNEL_LOAD_ADDRESS + \
XCHAL_KSEG_CACHED_VADDR - \ XCHAL_KSEG_CACHED_VADDR - \
XCHAL_KSEG_PADDR) XCHAL_KSEG_PADDR)
#endif
#else #else
#define KERNELOFFSET CONFIG_KERNEL_LOAD_ADDRESS #define KERNELOFFSET CONFIG_KERNEL_LOAD_ADDRESS
#endif #endif

View File

@ -260,6 +260,13 @@ ENTRY(_startup)
___invalidate_icache_all a2 a3 ___invalidate_icache_all a2 a3
isync isync
#ifdef CONFIG_XIP_KERNEL
/* Setup bootstrap CPU stack in XIP kernel */
movi a1, start_info
l32i a1, a1, 0
#endif
movi a6, 0 movi a6, 0
xsr a6, excsave1 xsr a6, excsave1

View File

@ -308,6 +308,10 @@ extern char _Level6InterruptVector_text_end;
extern char _SecondaryResetVector_text_start; extern char _SecondaryResetVector_text_start;
extern char _SecondaryResetVector_text_end; extern char _SecondaryResetVector_text_end;
#endif #endif
#ifdef CONFIG_XIP_KERNEL
extern char _xip_start[];
extern char _xip_end[];
#endif
static inline int __init_memblock mem_reserve(unsigned long start, static inline int __init_memblock mem_reserve(unsigned long start,
unsigned long end) unsigned long end)
@ -339,6 +343,9 @@ void __init setup_arch(char **cmdline_p)
#endif #endif
mem_reserve(__pa(_stext), __pa(_end)); mem_reserve(__pa(_stext), __pa(_end));
#ifdef CONFIG_XIP_KERNEL
mem_reserve(__pa(_xip_start), __pa(_xip_end));
#endif
#ifdef CONFIG_VECTORS_OFFSET #ifdef CONFIG_VECTORS_OFFSET
mem_reserve(__pa(&_WindowVectors_text_start), mem_reserve(__pa(&_WindowVectors_text_start),

View File

@ -134,6 +134,9 @@ SECTIONS
NOTES NOTES
/* Data section */ /* Data section */
#ifdef CONFIG_XIP_KERNEL
INIT_TEXT_SECTION(PAGE_SIZE)
#else
_sdata = .; _sdata = .;
RW_DATA_SECTION(XCHAL_ICACHE_LINESIZE, PAGE_SIZE, THREAD_SIZE) RW_DATA_SECTION(XCHAL_ICACHE_LINESIZE, PAGE_SIZE, THREAD_SIZE)
_edata = .; _edata = .;
@ -147,6 +150,11 @@ SECTIONS
.init.data : .init.data :
{ {
INIT_DATA INIT_DATA
}
#endif
.init.rodata :
{
. = ALIGN(0x4); . = ALIGN(0x4);
__tagtable_begin = .; __tagtable_begin = .;
*(.taglist) *(.taglist)
@ -187,12 +195,16 @@ SECTIONS
RELOCATE_ENTRY(_DebugInterruptVector_text, RELOCATE_ENTRY(_DebugInterruptVector_text,
.DebugInterruptVector.text); .DebugInterruptVector.text);
#endif #endif
#ifdef CONFIG_XIP_KERNEL
RELOCATE_ENTRY(_xip_data, .data);
RELOCATE_ENTRY(_xip_init_data, .init.data);
#else
#if defined(CONFIG_SMP) #if defined(CONFIG_SMP)
RELOCATE_ENTRY(_SecondaryResetVector_text, RELOCATE_ENTRY(_SecondaryResetVector_text,
.SecondaryResetVector.text); .SecondaryResetVector.text);
#endif
#endif #endif
__boot_reloc_table_end = ABSOLUTE(.) ; __boot_reloc_table_end = ABSOLUTE(.) ;
INIT_SETUP(XCHAL_ICACHE_LINESIZE) INIT_SETUP(XCHAL_ICACHE_LINESIZE)
@ -278,7 +290,7 @@ SECTIONS
. = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3; . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3;
#endif #endif
#if defined(CONFIG_SMP) #if !defined(CONFIG_XIP_KERNEL) && defined(CONFIG_SMP)
SECTION_VECTOR (_SecondaryResetVector_text, SECTION_VECTOR (_SecondaryResetVector_text,
.SecondaryResetVector.text, .SecondaryResetVector.text,
@ -291,12 +303,48 @@ SECTIONS
. = ALIGN(PAGE_SIZE); . = ALIGN(PAGE_SIZE);
#ifndef CONFIG_XIP_KERNEL
__init_end = .; __init_end = .;
BSS_SECTION(0, 8192, 0) BSS_SECTION(0, 8192, 0)
#endif
_end = .; _end = .;
#ifdef CONFIG_XIP_KERNEL
. = CONFIG_XIP_DATA_ADDR;
_xip_start = .;
#undef LOAD_OFFSET
#define LOAD_OFFSET \
(CONFIG_XIP_DATA_ADDR - (LOADADDR(.dummy) + SIZEOF(.dummy) + 3) & ~ 3)
_xip_data_start = .;
_sdata = .;
RW_DATA_SECTION(XCHAL_ICACHE_LINESIZE, PAGE_SIZE, THREAD_SIZE)
_edata = .;
_xip_data_end = .;
/* Initialization data: */
STRUCT_ALIGN();
_xip_init_data_start = .;
__init_begin = .;
.init.data :
{
INIT_DATA
}
_xip_init_data_end = .;
__init_end = .;
BSS_SECTION(0, 8192, 0)
_xip_end = .;
#undef LOAD_OFFSET
#endif
DWARF_DEBUG DWARF_DEBUG
.xt.prop 0 : { KEEP(*(.xt.prop .xt.prop.* .gnu.linkonce.prop.*)) } .xt.prop 0 : { KEEP(*(.xt.prop .xt.prop.* .gnu.linkonce.prop.*)) }