xtensa: add XIP kernel support
authorMax Filippov <jcmvbkbc@gmail.com>
Wed, 4 Jan 2017 01:57:51 +0000 (17:57 -0800)
committerMax Filippov <jcmvbkbc@gmail.com>
Tue, 26 Nov 2019 19:33:38 +0000 (11:33 -0800)
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>
arch/xtensa/Kconfig
arch/xtensa/Makefile
arch/xtensa/boot/Makefile
arch/xtensa/configs/xip_kc705_defconfig [new file with mode: 0644]
arch/xtensa/include/asm/cache.h
arch/xtensa/include/asm/page.h
arch/xtensa/include/asm/vectors.h
arch/xtensa/kernel/head.S
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/vmlinux.lds.S

index ea9f63c..bf492f9 100644 (file)
@@ -19,8 +19,8 @@ config XTENSA
        select GENERIC_PCI_IOMAP
        select GENERIC_SCHED_CLOCK
        select GENERIC_STRNCPY_FROM_USER if KASAN
-       select HAVE_ARCH_JUMP_LABEL
-       select HAVE_ARCH_KASAN if MMU
+       select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
+       select HAVE_ARCH_KASAN if MMU && !XIP_KERNEL
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_CONTIGUOUS
@@ -299,6 +299,9 @@ config XTENSA_CALIBRATE_CCOUNT
 config SERIAL_CONSOLE
        def_bool n
 
+config PLATFORM_HAVE_XIP
+       def_bool n
+
 menu "Platform options"
 
 choice
@@ -325,6 +328,7 @@ config XTENSA_PLATFORM_XTFPGA
        select PLATFORM_WANT_DEFAULT_MEM if !MMU
        select SERIAL_CONSOLE
        select XTENSA_CALIBRATE_CCOUNT
+       select PLATFORM_HAVE_XIP
        help
          XTFPGA is the name of Tensilica board family (LX60, LX110, LX200, ML605).
          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.
 
+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
        hex "Cache attributes for the memory address space"
        depends on !MMU
@@ -522,6 +547,16 @@ config KSEG_PADDR
 
          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
        hex "Kernel load address"
        default 0x60003000 if !MMU
@@ -537,12 +572,21 @@ config KERNEL_LOAD_ADDRESS
 config VECTORS_OFFSET
        hex "Kernel vectors offset"
        default 0x00003000
+       depends on !XIP_KERNEL
        help
          This is the offset of the kernel image from the relocatable vectors
          base.
 
          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
        def_bool n
 
index 1542018..67a7d15 100644 (file)
@@ -87,7 +87,7 @@ drivers-$(CONFIG_OPROFILE)    += arch/xtensa/oprofile/
 
 boot           := arch/xtensa/boot
 
-all Image zImage uImage: vmlinux
+all Image zImage uImage xipImage: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $@
 
 archheaders:
@@ -97,4 +97,5 @@ define archhelp
   @echo '* Image       - Kernel ELF image with reset vector'
   @echo '* zImage      - Compressed kernel image (arch/xtensa/boot/images/zImage.*)'
   @echo '* uImage      - U-Boot wrapped image'
+  @echo '  xipImage    - XIP image'
 endef
index 2948461..efb91bf 100644 (file)
@@ -29,6 +29,7 @@ all: $(boot-y)
 Image: boot-elf
 zImage: boot-redboot
 uImage: $(obj)/uImage
+xipImage: $(obj)/xipImage
 
 boot-elf boot-redboot: $(addprefix $(obj)/,$(subdir-y))
        $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS)
@@ -50,3 +51,7 @@ UIMAGE_COMPRESSION = gzip
 $(obj)/uImage: vmlinux.bin.gz FORCE
        $(call if_changed,uimage)
        $(Q)$(kecho) '  Kernel: $@ is ready'
+
+$(obj)/xipImage: vmlinux FORCE
+       $(call if_changed,objcopy)
+       $(Q)$(kecho) '  Kernel: $@ is ready'
diff --git a/arch/xtensa/configs/xip_kc705_defconfig b/arch/xtensa/configs/xip_kc705_defconfig
new file mode 100644 (file)
index 0000000..f9e85c0
--- /dev/null
@@ -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
index b21fd13..54e147a 100644 (file)
 
 #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 */
index 09c56cb..f4771c2 100644 (file)
@@ -169,7 +169,18 @@ static inline unsigned long ___pa(unsigned long va)
        if (off >= XCHAL_KSEG_SIZE)
                off -= XCHAL_KSEG_SIZE;
 
+#ifndef CONFIG_XIP_KERNEL
        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))
 #else
index 4220c6d..fd99b25 100644 (file)
 #include <asm/kmem_layout.h>
 
 #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 + \
                                         XCHAL_KSEG_CACHED_VADDR - \
                                         XCHAL_KSEG_PADDR)
+#endif
 #else
 #define KERNELOFFSET                   CONFIG_KERNEL_LOAD_ADDRESS
 #endif
index 2cec13a..e0c1fac 100644 (file)
@@ -260,6 +260,13 @@ ENTRY(_startup)
        ___invalidate_icache_all a2 a3
        isync
 
+#ifdef CONFIG_XIP_KERNEL
+       /* Setup bootstrap CPU stack in XIP kernel */
+
+       movi    a1, start_info
+       l32i    a1, a1, 0
+#endif
+
        movi    a6, 0
        xsr     a6, excsave1
 
index e0e1e18..0f93b67 100644 (file)
@@ -308,6 +308,10 @@ extern char _Level6InterruptVector_text_end;
 extern char _SecondaryResetVector_text_start;
 extern char _SecondaryResetVector_text_end;
 #endif
+#ifdef CONFIG_XIP_KERNEL
+extern char _xip_start[];
+extern char _xip_end[];
+#endif
 
 static inline int __init_memblock mem_reserve(unsigned long start,
                                              unsigned long end)
@@ -339,6 +343,9 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        mem_reserve(__pa(_stext), __pa(_end));
+#ifdef CONFIG_XIP_KERNEL
+       mem_reserve(__pa(_xip_start), __pa(_xip_end));
+#endif
 
 #ifdef CONFIG_VECTORS_OFFSET
        mem_reserve(__pa(&_WindowVectors_text_start),
index 943f106..01e3112 100644 (file)
@@ -134,6 +134,9 @@ SECTIONS
   NOTES
   /* Data section */
 
+#ifdef CONFIG_XIP_KERNEL
+  INIT_TEXT_SECTION(PAGE_SIZE)
+#else
   _sdata = .;
   RW_DATA_SECTION(XCHAL_ICACHE_LINESIZE, PAGE_SIZE, THREAD_SIZE)
   _edata = .;
@@ -147,6 +150,11 @@ SECTIONS
   .init.data :
   {
     INIT_DATA
+  }
+#endif
+
+  .init.rodata :
+  {
     . = ALIGN(0x4);
     __tagtable_begin = .;
     *(.taglist)
@@ -187,12 +195,16 @@ SECTIONS
     RELOCATE_ENTRY(_DebugInterruptVector_text,
                   .DebugInterruptVector.text);
 #endif
+#ifdef CONFIG_XIP_KERNEL
+    RELOCATE_ENTRY(_xip_data, .data);
+    RELOCATE_ENTRY(_xip_init_data, .init.data);
+#else
 #if defined(CONFIG_SMP)
     RELOCATE_ENTRY(_SecondaryResetVector_text,
                   .SecondaryResetVector.text);
 #endif
+#endif
 
-  
     __boot_reloc_table_end = ABSOLUTE(.) ;
 
     INIT_SETUP(XCHAL_ICACHE_LINESIZE)
@@ -278,7 +290,7 @@ SECTIONS
   . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3;
 
 #endif
-#if defined(CONFIG_SMP)
+#if !defined(CONFIG_XIP_KERNEL) && defined(CONFIG_SMP)
 
   SECTION_VECTOR (_SecondaryResetVector_text,
                  .SecondaryResetVector.text,
@@ -291,12 +303,48 @@ SECTIONS
 
   . = ALIGN(PAGE_SIZE);
 
+#ifndef CONFIG_XIP_KERNEL
   __init_end = .;
 
   BSS_SECTION(0, 8192, 0)
+#endif
 
   _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
 
   .xt.prop 0 : { KEEP(*(.xt.prop .xt.prop.* .gnu.linkonce.prop.*)) }