diff --git a/Documentation/platforms/x86_64/intel64/boards/qemu-intel64/index.rst b/Documentation/platforms/x86_64/intel64/boards/qemu-intel64/index.rst index 3978e576e1e8b..3d7f37288847e 100644 --- a/Documentation/platforms/x86_64/intel64/boards/qemu-intel64/index.rst +++ b/Documentation/platforms/x86_64/intel64/boards/qemu-intel64/index.rst @@ -181,6 +181,34 @@ Basic command to run the image without additional PCI devices attached:: qemu-system-x86_64 -m 2G -cpu host -smp 4 -enable-kvm \ -kernel nuttx -nographic -serial mon:stdio + +knsh_romfs +---------- + +This is similar to the ``nsh`` configuration except that NuttX +is built as a kernel-mode, monolithic module, and the user applications +are built separately. It uses ROMFS to load the user-space applications. +This is intended to run on QEMU with COM serial port support. + +Steps to build kernel image with user-space apps in ROMFS:: + + ./tools/configure.sh qemu-intel64/knsh_romfs + make -j + make export -j + pushd ../apps + ./tools/mkimport.sh -z -x ../nuttx/nuttx-export-*.tar.gz + make import -j + ./tools/mkromfsimg.sh + mv boot_romfsimg.h ../nuttx/arch/x86_64/src/board/romfs_boot.c + popd + make -j + +knsh_romfs_pci +-------------- + +This is similar to the ``knsh_romfs`` configuration except that it is intended +to run on a bare metal Intel hardware with PCI serial port support. + lvgl ---- diff --git a/Documentation/platforms/x86_64/intel64/index.rst b/Documentation/platforms/x86_64/intel64/index.rst index d151207877a06..add50be65667c 100644 --- a/Documentation/platforms/x86_64/intel64/index.rst +++ b/Documentation/platforms/x86_64/intel64/index.rst @@ -80,6 +80,15 @@ and use ``-cdrom boot.iso`` (multiboot2 framebuffer doesn't work with Also, your GRUB configuration (``grub.cfg``) should insert the appropriate video module, in many cases ``insmod all_video`` should be enough. +Kernel build +------------ + +Kernel build is supported. + +.. warning:: + IMPORTANT: the current implementation doesn't include any protection against + speculative execution vulnerabilities (Spectre, Meltdown and others) ! + Creating a bootable disk ======================== diff --git a/arch/Kconfig b/arch/Kconfig index 3f805ab1ddaca..978a2e2901bbc 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -145,7 +145,7 @@ config ARCH_X86_64 select LIBC_ARCH_ELF_64BIT if LIBC_ARCH_ELF select ARCH_TOOLCHAIN_GNU select ARCH_HAVE_BACKTRACE - select ARCH_HAVE_FORK + select ARCH_HAVE_FORK if !BUILD_KERNEL select ARCH_HAVE_SETJMP select ARCH_HAVE_PERF_EVENTS ---help--- diff --git a/arch/x86_64/include/intel64/arch.h b/arch/x86_64/include/intel64/arch.h index 1d0cff6057a19..103cc1fb23197 100644 --- a/arch/x86_64/include/intel64/arch.h +++ b/arch/x86_64/include/intel64/arch.h @@ -41,232 +41,273 @@ * Pre-processor Definitions ****************************************************************************/ -#define X86_64_LOAD_OFFSET 0x100000000 +#define X86_64_LOAD_OFFSET 0x100000000 /* Page pool configuration for CONFIG_ARCH_PGPOOL_MAPPING=n */ #ifndef CONFIG_ARCH_X86_64_PGPOOL_SIZE -# define X86_64_PGPOOL_SIZE (0) +# define X86_64_PGPOOL_SIZE (0) #else # if CONFIG_ARCH_X86_64_PGPOOL_SIZE % CONFIG_MM_PGSIZE != 0 # error CONFIG_ARCH_X86_64_PGPOOL_SIZE must be multiple of page size # endif -# define X86_64_PGPOOL_SIZE (CONFIG_ARCH_X86_64_PGPOOL_SIZE) +# define X86_64_PGPOOL_SIZE (CONFIG_ARCH_X86_64_PGPOOL_SIZE) #endif -#define X86_64_PGPOOL_BASE (CONFIG_RAM_SIZE - X86_64_PGPOOL_SIZE) +#define X86_64_PGPOOL_BASE (CONFIG_RAM_SIZE - X86_64_PGPOOL_SIZE) /* RFLAGS bits */ -#define X86_64_RFLAGS_CF (1 << 0) /* Bit 0: Carry Flag */ - /* Bit 1: Reserved */ -#define X86_64_RFLAGS_PF (1 << 2) /* Bit 2: Parity Flag */ - /* Bit 3: Reserved */ -#define X86_64_RFLAGS_AF (1 << 4) /* Bit 4: Auxiliary carry Flag */ - /* Bit 5: Reserved */ -#define X86_64_RFLAGS_ZF (1 << 6) /* Bit 6: Zero Flag */ -#define X86_64_RFLAGS_SF (1 << 7) /* Bit 7: Sign Flag */ -#define X86_64_RFLAGS_TF (1 << 8) /* Bit 8: Trap Flag */ -#define X86_64_RFLAGS_IF (1 << 9) /* Bit 9: Interrupt Flag */ -#define X86_64_RFLAGS_DF (1 << 10) /* Bit 10: Direction Flag */ -#define X86_64_RFLAGS_OF (1 << 11) /* Bit 11: Overflow Flag */ -#define X86_64_RFLAGS_IOPL_SHIFT (12) /* Bits 12-13: IOPL mask (286+ only)*/ -#define X86_64_RFLAGS_IOPL_MASK (3 << X86_64_RFLAGS_IOPL_SHIFT) -#define X86_64_RFLAGS_NT (1 << 14) /* Bit 14: Nested Task */ - /* Bit 15: Reserved */ -#define X86_64_RFLAGS_RF (1 << 16) /* Bit 16: Resume Flag (386+ only) */ -#define X86_64_RFLAGS_VM (1 << 17) /* Bit 17: Virtual Mode (386+ only) */ -#define X86_64_RFLAGS_AC (1 << 18) /* Bit 18: Alignment Check (486SX+ only) */ -#define X86_64_RFLAGS_VIF (1 << 19) /* Bit 19: Virtual Interrupt Flag (Pentium+) */ -#define X86_64_RFLAGS_VIP (1 << 20) /* Bit 20: Virtual Interrupt Pending (Pentium+) */ -#define X86_64_RFLAGS_ID (1 << 21) /* Bit 21: CPUID detection flag (Pentium+) */ +#define X86_64_RFLAGS_CF (1 << 0) /* Bit 0: Carry Flag */ + /* Bit 1: Reserved */ +#define X86_64_RFLAGS_PF (1 << 2) /* Bit 2: Parity Flag */ + /* Bit 3: Reserved */ +#define X86_64_RFLAGS_AF (1 << 4) /* Bit 4: Auxiliary carry Flag */ + /* Bit 5: Reserved */ +#define X86_64_RFLAGS_ZF (1 << 6) /* Bit 6: Zero Flag */ +#define X86_64_RFLAGS_SF (1 << 7) /* Bit 7: Sign Flag */ +#define X86_64_RFLAGS_TF (1 << 8) /* Bit 8: Trap Flag */ +#define X86_64_RFLAGS_IF (1 << 9) /* Bit 9: Interrupt Flag */ +#define X86_64_RFLAGS_DF (1 << 10) /* Bit 10: Direction Flag */ +#define X86_64_RFLAGS_OF (1 << 11) /* Bit 11: Overflow Flag */ +#define X86_64_RFLAGS_IOPL_SHIFT (12) /* Bits 12-13: IOPL mask (286+ only)*/ +#define X86_64_RFLAGS_IOPL_MASK (3 << X86_64_RFLAGS_IOPL_SHIFT) +#define X86_64_RFLAGS_NT (1 << 14) /* Bit 14: Nested Task */ + /* Bit 15: Reserved */ +#define X86_64_RFLAGS_RF (1 << 16) /* Bit 16: Resume Flag (386+ only) */ +#define X86_64_RFLAGS_VM (1 << 17) /* Bit 17: Virtual Mode (386+ only) */ +#define X86_64_RFLAGS_AC (1 << 18) /* Bit 18: Alignment Check (486SX+ only) */ +#define X86_64_RFLAGS_VIF (1 << 19) /* Bit 19: Virtual Interrupt Flag (Pentium+) */ +#define X86_64_RFLAGS_VIP (1 << 20) /* Bit 20: Virtual Interrupt Pending (Pentium+) */ +#define X86_64_RFLAGS_ID (1 << 21) /* Bit 21: CPUID detection flag (Pentium+) */ /* GDT Definitions */ -/* Starting from third selector to confirm the syscall interface */ - -#define X86_GDT_ENTRY_SIZE 0x8 - -#define X86_GDT_CODE_SEL_NUM 1 -# define X86_GDT_CODE_SEL (X86_GDT_CODE_SEL_NUM * X86_GDT_ENTRY_SIZE) +/* Selector configuration must compy with the requirements of SYSCALL + * and SYSRET instructions. These definitions must match the GDT format + * in intel64_head.S:g_gdt64_low. + * + * For details look at the comment in intel64_cpu.c about MSR_STAT write. + */ -#define X86_GDT_DATA_SEL_NUM 2 -# define X86_GDT_DATA_SEL (X86_GDT_DATA_SEL_NUM * X86_GDT_ENTRY_SIZE) +#define X86_GDT_ENTRY_SIZE 0x8 -/* The first TSS entry */ +#define X86_GDT_CODE_SEL_NUM 1 +# define X86_GDT_CODE_SEL (X86_GDT_CODE_SEL_NUM * X86_GDT_ENTRY_SIZE) -#define X86_GDT_ISTL_SEL_NUM 6 -#define X86_GDT_ISTH_SEL_NUM (X86_GDT_ISTL_SEL_NUM + 1) +#define X86_GDT_DATA_SEL_NUM 2 +# define X86_GDT_DATA_SEL (X86_GDT_DATA_SEL_NUM * X86_GDT_ENTRY_SIZE) -#define X86_GDT_BASE 0x0000000000000000 -#define X86_GDT_LIMIT 0x000f00000000ffff +#define X86_GDT_USERDATA_SEL_NUM 6 +# define X86_GDT_USERDATA_SEL (X86_GDT_USERDATA_SEL_NUM * X86_GDT_ENTRY_SIZE) -#define X86_GDT_FLAG_LONG 0x0020000000000000 +#define X86_GDT_USERCODE_SEL_NUM 7 +# define X86_GDT_USERCODE_SEL (X86_GDT_USERCODE_SEL_NUM * X86_GDT_ENTRY_SIZE) -#define X86_GDT_ACC_PR 0x0000800000000000 -#define X86_GDT_ACC_SEG 0x0000100000000000 -#define X86_GDT_ACC_EX 0x0000080000000000 -#define X86_GDT_ACC_WR 0x0000020000000000 +/* The first TSS entry */ -#define X86_GDT_CODE64_ENTRY (X86_GDT_BASE + X86_GDT_LIMIT + X86_GDT_FLAG_LONG + X86_GDT_ACC_PR + X86_GDT_ACC_SEG + X86_GDT_ACC_EX) -#define X86_GDT_CODE32_ENTRY (X86_GDT_BASE + X86_GDT_LIMIT + X86_GDT_ACC_PR + X86_GDT_ACC_SEG + X86_GDT_ACC_EX) -#define X86_GDT_DATA_ENTRY (X86_GDT_BASE + X86_GDT_LIMIT + X86_GDT_ACC_PR + X86_GDT_ACC_SEG + X86_GDT_ACC_WR) +#define X86_GDT_ISTL_SEL_NUM 8 +#define X86_GDT_ISTH_SEL_NUM (X86_GDT_ISTL_SEL_NUM + 1) + +/* Stack selector for ISR and IRQ (offset in Interrupt Stack Table) */ + +#define X86_GDT_IST_ISR 2 +#define X86_GDT_IST_IRQ 1 + +#define X86_GDT_BASE 0x0000000000000000 +#define X86_GDT_LIMIT 0x000f00000000ffff + +#define X86_GDT_FLAG_LONG 0x0020000000000000 + +#define X86_GDT_ACC_PR 0x0000800000000000 +#define X86_GDT_ACC_USER 0x0000600000000000 +#define X86_GDT_ACC_SEG 0x0000100000000000 +#define X86_GDT_ACC_EX 0x0000080000000000 +#define X86_GDT_ACC_WR 0x0000020000000000 + +#define X86_GDT_CODE64_ENTRY (X86_GDT_BASE + X86_GDT_LIMIT + \ + X86_GDT_FLAG_LONG + X86_GDT_ACC_PR + \ + X86_GDT_ACC_SEG + X86_GDT_ACC_EX) +#define X86_GDT_CODE32_ENTRY (X86_GDT_BASE + X86_GDT_LIMIT + \ + X86_GDT_ACC_PR + X86_GDT_ACC_SEG + \ + X86_GDT_ACC_EX) +#define X86_GDT_DATA_ENTRY (X86_GDT_BASE + X86_GDT_LIMIT + \ + X86_GDT_ACC_PR + X86_GDT_ACC_SEG + \ + X86_GDT_ACC_WR) +#define X86_GDT_CODEUSER_ENTRY (X86_GDT_BASE + X86_GDT_LIMIT + \ + X86_GDT_FLAG_LONG + X86_GDT_ACC_PR + \ + X86_GDT_ACC_SEG + X86_GDT_ACC_EX + \ + X86_GDT_ACC_USER) +#define X86_GDT_DATAUSER_ENTRY (X86_GDT_BASE + X86_GDT_LIMIT + \ + X86_GDT_ACC_PR + X86_GDT_ACC_SEG + \ + X86_GDT_ACC_WR + X86_GDT_ACC_USER) /* CR0 Definitions */ -#define X86_CR0_PE 0x00000001 -#define X86_CR0_MP 0x00000002 -#define X86_CR0_EM 0x00000004 -#define X86_CR0_WP 0x00010000 -#define X86_CR0_PG 0x80000000 +#define X86_CR0_PE 0x00000001 +#define X86_CR0_MP 0x00000002 +#define X86_CR0_EM 0x00000004 +#define X86_CR0_WP 0x00010000 +#define X86_CR0_PG 0x80000000 /* CR4 Definitions */ -#define X86_CR4_PAE 0x00000020 -#define X86_CR4_PGE 0x00000080 -#define X86_CR4_OSXFSR 0x00000200 -#define X86_CR4_XMMEXCPT 0x00000400 -#define X86_CR4_FGSBASE 0x00010000 -#define X86_CR4_PCIDE 0x00020000 -#define X86_CR4_OSXSAVE 0x00040000 +#define X86_CR4_PAE 0x00000020 +#define X86_CR4_PGE 0x00000080 +#define X86_CR4_OSXFSR 0x00000200 +#define X86_CR4_XMMEXCPT 0x00000400 +#define X86_CR4_FGSBASE 0x00010000 +#define X86_CR4_PCIDE 0x00020000 +#define X86_CR4_OSXSAVE 0x00040000 /* XCR0 */ -#define X86_XCR0_X87 (1 << 0) -#define X86_XCR0_SSE (1 << 1) -#define X86_XCR0_AVX (1 << 2) -#define X86_XCR0_BNDREG (1 << 3) -#define X86_XCR0_BNDCSR (1 << 4) -#define X86_XCR0_OPMASK (1 << 5) -#define X86_XCR0_HI256 (1 << 6) -#define X86_XCR0_HI16 (1 << 7) -#define X86_XCR0_PT (1 << 8) -#define X86_XCR0_PKRU (1 << 9) -#define X86_XCR0_PASID (1 << 10) -#define X86_XCR0_CETU (1 << 11) -#define X86_XCR0_CETS (1 << 12) -#define X86_XCR0_HDC (1 << 13) -#define X86_XCR0_UINTR (1 << 14) -#define X86_XCR0_LBR (1 << 15) -#define X86_XCR0_HWP (1 << 16) -#define X86_XCR0_XTILECFG (1 << 17) -#define X86_XCR0_XTILEDATA (1 << 18) -#define X86_XCR0_APX (1 << 19) +#define X86_XCR0_X87 (1 << 0) +#define X86_XCR0_SSE (1 << 1) +#define X86_XCR0_AVX (1 << 2) +#define X86_XCR0_BNDREG (1 << 3) +#define X86_XCR0_BNDCSR (1 << 4) +#define X86_XCR0_OPMASK (1 << 5) +#define X86_XCR0_HI256 (1 << 6) +#define X86_XCR0_HI16 (1 << 7) +#define X86_XCR0_PT (1 << 8) +#define X86_XCR0_PKRU (1 << 9) +#define X86_XCR0_PASID (1 << 10) +#define X86_XCR0_CETU (1 << 11) +#define X86_XCR0_CETS (1 << 12) +#define X86_XCR0_HDC (1 << 13) +#define X86_XCR0_UINTR (1 << 14) +#define X86_XCR0_LBR (1 << 15) +#define X86_XCR0_HWP (1 << 16) +#define X86_XCR0_XTILECFG (1 << 17) +#define X86_XCR0_XTILEDATA (1 << 18) +#define X86_XCR0_APX (1 << 19) /* PAGE TABLE ENTRY Definitions */ -#define X86_PAGE_PRESENT (1 << 0) -#define X86_PAGE_WR (1 << 1) -#define X86_PAGE_USER (1 << 2) -#define X86_PAGE_WRTHR (1 << 3) -#define X86_PAGE_NOCACHE (1 << 4) -#define X86_PAGE_HUGE (1 << 7) -#define X86_PAGE_GLOBAL (1 << 8) -#define X86_PAGE_NX (1 << 63) +#define X86_PAGE_PRESENT (1 << 0) +#define X86_PAGE_WR (1 << 1) +#define X86_PAGE_USER (1 << 2) +#define X86_PAGE_WRTHR (1 << 3) +#define X86_PAGE_NOCACHE (1 << 4) +#define X86_PAGE_HUGE (1 << 7) +#define X86_PAGE_GLOBAL (1 << 8) +#define X86_PAGE_NX (1 << 63) -#define X86_PAGE_ENTRY_SIZE 8 -#define X86_NUM_PAGE_ENTRY (PAGE_SIZE / X86_PAGE_ENTRY_SIZE) +#define X86_PAGE_ENTRY_SIZE 8 +#define X86_NUM_PAGE_ENTRY (PAGE_SIZE / X86_PAGE_ENTRY_SIZE) -#define PAGE_SIZE (0x1000) -# define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_SIZE (0x1000) +# define PAGE_MASK (~(PAGE_SIZE - 1)) -#define HUGE_PAGE_SIZE (0x200000) -# define HUGE_PAGE_MASK (~(HUGE_PAGE_SIZE - 1)) +#define HUGE_PAGE_SIZE (0x200000) +# define HUGE_PAGE_MASK (~(HUGE_PAGE_SIZE - 1)) /* Kernel mapping - lower 1GB maps to 4GB-5GB */ -#define X86_PDPT_KERNEL_MAP (X86_PAGE_GLOBAL | X86_PAGE_WR | \ - X86_PAGE_PRESENT | X86_PAGE_HUGE) +#define X86_PDPT_KERNEL_MAP (X86_PAGE_GLOBAL | X86_PAGE_WR | \ + X86_PAGE_PRESENT | X86_PAGE_HUGE) /* CPUID Leaf Definitions */ -#define X86_64_CPUID_VENDOR 0x00 -#define X86_64_CPUID_CAP 0x01 -# define X86_64_CPUID_01_SSE3 (1 << 0) -# define X86_64_CPUID_01_SSSE3 (1 << 9) -# define X86_64_CPUID_01_FMA (1 << 12) -# define X86_64_CPUID_01_PCID (1 << 17) -# define X86_64_CPUID_01_SSE41 (1 << 19) -# define X86_64_CPUID_01_SSE42 (1 << 20) -# define X86_64_CPUID_01_X2APIC (1 << 21) -# define X86_64_CPUID_01_TSCDEA (1 << 24) -# define X86_64_CPUID_01_XSAVE (1 << 26) -# define X86_64_CPUID_01_AVX (1 << 28) -# define X86_64_CPUID_01_RDRAND (1 << 30) -# define X86_64_CPUID_01_APICID(ebx) ((ebx) >> 24) -#define X86_64_CPUID_EXTCAP 0x07 -# define X86_64_CPUID_07_AVX2 (1 << 5) -# define X86_64_CPUID_07_AVX512F (1 << 16) -# define X86_64_CPUID_07_AVX512DQ (1 << 17) -# define X86_64_CPUID_07_SMAP (1 << 20) -# define X86_64_CPUID_07_AVX512IFMA (1 << 21) -# define X86_64_CPUID_07_CLWB (1 << 24) -# define X86_64_CPUID_07_AVX512PF (1 << 26) -# define X86_64_CPUID_07_AVX512ER (1 << 27) -# define X86_64_CPUID_07_AVX512CD (1 << 28) -# define X86_64_CPUID_07_AVX512BW (1 << 30) -# define X86_64_CPUID_07_AVX512VL (1 << 31) -#define X86_64_CPUID_XSAVE 0x0d -#define X86_64_CPUID_TSC 0x15 -#define X86_64_CPUID_EXTINFO 0x80000001 -# define X86_64_CPUID_EXTINFO_RDTSCP (1 << 27) +#define X86_64_CPUID_VENDOR 0x00 +#define X86_64_CPUID_CAP 0x01 +# define X86_64_CPUID_01_SSE3 (1 << 0) +# define X86_64_CPUID_01_SSSE3 (1 << 9) +# define X86_64_CPUID_01_FMA (1 << 12) +# define X86_64_CPUID_01_PCID (1 << 17) +# define X86_64_CPUID_01_SSE41 (1 << 19) +# define X86_64_CPUID_01_SSE42 (1 << 20) +# define X86_64_CPUID_01_X2APIC (1 << 21) +# define X86_64_CPUID_01_TSCDEA (1 << 24) +# define X86_64_CPUID_01_XSAVE (1 << 26) +# define X86_64_CPUID_01_AVX (1 << 28) +# define X86_64_CPUID_01_RDRAND (1 << 30) +# define X86_64_CPUID_01_APICID(ebx) ((ebx) >> 24) +#define X86_64_CPUID_EXTCAP 0x07 +# define X86_64_CPUID_07_AVX2 (1 << 5) +# define X86_64_CPUID_07_AVX512F (1 << 16) +# define X86_64_CPUID_07_AVX512DQ (1 << 17) +# define X86_64_CPUID_07_SMAP (1 << 20) +# define X86_64_CPUID_07_AVX512IFMA (1 << 21) +# define X86_64_CPUID_07_CLWB (1 << 24) +# define X86_64_CPUID_07_AVX512PF (1 << 26) +# define X86_64_CPUID_07_AVX512ER (1 << 27) +# define X86_64_CPUID_07_AVX512CD (1 << 28) +# define X86_64_CPUID_07_AVX512BW (1 << 30) +# define X86_64_CPUID_07_AVX512VL (1 << 31) +#define X86_64_CPUID_XSAVE 0x0d +#define X86_64_CPUID_TSC 0x15 +#define X86_64_CPUID_EXTINFO 0x80000001 +# define X86_64_CPUID_EXTINFO_RDTSCP (1 << 27) /* MSR Definitions */ -#define MSR_FS_BASE 0xc0000100 /* 64bit FS base */ - -#define MSR_EFER 0xc0000080 -# define EFER_LME 0x00000100 - -#define MSR_MTRR_DEF_TYPE 0x000002ff -# define MTRR_ENABLE 0x00000800 - -#define MSR_IA32_TSC_DEADLINE 0x6e0 - -#define MSR_IA32_APIC_BASE 0x01b -# define MSR_IA32_APIC_EN 0x800 -# define MSR_IA32_APIC_X2APIC 0x400 -# define MSR_IA32_APIC_BSP 0x100 - -#define MSR_X2APIC_ID 0x802 -#define MSR_X2APIC_VER 0x803 -#define MSR_X2APIC_TPR 0x808 -#define MSR_X2APIC_PPR 0x80a -#define MSR_X2APIC_EOI 0x80b -#define MSR_X2APIC_LDR 0x80d - -#define MSR_X2APIC_SPIV 0x80f -# define MSR_X2APIC_SPIV_EN 0x100 - -#define MSR_X2APIC_ISR0 0x810 -#define MSR_X2APIC_ISR1 0x811 -#define MSR_X2APIC_ISR2 0x812 -#define MSR_X2APIC_ISR3 0x813 -#define MSR_X2APIC_ISR4 0x814 -#define MSR_X2APIC_ISR5 0x815 -#define MSR_X2APIC_ISR6 0x816 -#define MSR_X2APIC_ISR7 0x817 - -#define MSR_X2APIC_TMR0 0x818 -#define MSR_X2APIC_TMR1 0x819 -#define MSR_X2APIC_TMR2 0x81a -#define MSR_X2APIC_TMR3 0x81b -#define MSR_X2APIC_TMR4 0x81c -#define MSR_X2APIC_TMR5 0x81d -#define MSR_X2APIC_TMR6 0x81e -#define MSR_X2APIC_TMR7 0x81f - -#define MSR_X2APIC_IRR0 0x820 -#define MSR_X2APIC_IRR1 0x821 -#define MSR_X2APIC_IRR2 0x822 -#define MSR_X2APIC_IRR3 0x823 -#define MSR_X2APIC_IRR4 0x824 -#define MSR_X2APIC_IRR5 0x825 -#define MSR_X2APIC_IRR6 0x826 -#define MSR_X2APIC_IRR7 0x827 - -#define MSR_X2APIC_ESR 0x828 -#define MSR_X2APIC_ICR 0x830 +#define MSR_STAR 0xc0000081 +#define MSR_STAR_CSSYSCALL(x) (((uint64_t)x) << 32) +#define MSR_STAR_CSSYSRET(x) (((uint64_t)x) << 48) + +#define MSR_LSTAR 0xc0000082 /* Target RIP for PM64 callers */ +#define MSR_CSTAR 0xc0000083 /* Target RIP for CM callers */ +#define MSR_FMASK 0xc0000084 /* RFLAGS mask for SYSCALL */ + +#define MSR_FS_BASE 0xc0000100 /* 64bit FS base */ +#define MSR_GS_BASE 0xc0000101 /* 64bit GS base */ +#define MSR_KERNELGS_BASE 0xc0000102 /* kernel GS base (for SWAPGS) */ + +#define MSR_EFER 0xc0000080 +# define EFER_SCE 0x00000001 +# define EFER_LME 0x00000100 + +#define MSR_MTRR_DEF_TYPE 0x000002ff +# define MTRR_ENABLE 0x00000800 + +#define MSR_IA32_TSC_DEADLINE 0x6e0 + +#define MSR_IA32_APIC_BASE 0x01b +# define MSR_IA32_APIC_EN 0x800 +# define MSR_IA32_APIC_X2APIC 0x400 +# define MSR_IA32_APIC_BSP 0x100 + +#define MSR_X2APIC_ID 0x802 +#define MSR_X2APIC_VER 0x803 +#define MSR_X2APIC_TPR 0x808 +#define MSR_X2APIC_PPR 0x80a +#define MSR_X2APIC_EOI 0x80b +#define MSR_X2APIC_LDR 0x80d + +#define MSR_X2APIC_SPIV 0x80f +# define MSR_X2APIC_SPIV_EN 0x100 + +#define MSR_X2APIC_ISR0 0x810 +#define MSR_X2APIC_ISR1 0x811 +#define MSR_X2APIC_ISR2 0x812 +#define MSR_X2APIC_ISR3 0x813 +#define MSR_X2APIC_ISR4 0x814 +#define MSR_X2APIC_ISR5 0x815 +#define MSR_X2APIC_ISR6 0x816 +#define MSR_X2APIC_ISR7 0x817 + +#define MSR_X2APIC_TMR0 0x818 +#define MSR_X2APIC_TMR1 0x819 +#define MSR_X2APIC_TMR2 0x81a +#define MSR_X2APIC_TMR3 0x81b +#define MSR_X2APIC_TMR4 0x81c +#define MSR_X2APIC_TMR5 0x81d +#define MSR_X2APIC_TMR6 0x81e +#define MSR_X2APIC_TMR7 0x81f + +#define MSR_X2APIC_IRR0 0x820 +#define MSR_X2APIC_IRR1 0x821 +#define MSR_X2APIC_IRR2 0x822 +#define MSR_X2APIC_IRR3 0x823 +#define MSR_X2APIC_IRR4 0x824 +#define MSR_X2APIC_IRR5 0x825 +#define MSR_X2APIC_IRR6 0x826 +#define MSR_X2APIC_IRR7 0x827 + +#define MSR_X2APIC_ESR 0x828 +#define MSR_X2APIC_ICR 0x830 # define MSR_X2APIC_ICR_INIT 0x00000500 /* INIT/RESET */ # define MSR_X2APIC_ICR_STARTUP 0x00000600 /* Startup IPI */ # define MSR_X2APIC_ICR_DELIVS 0x00001000 /* Delivery status */ @@ -278,93 +319,93 @@ # define MSR_X2APIC_ICR_BUSY 0x00001000 # define MSR_X2APIC_ICR_FIXED 0x00000000 # define MSR_X2APIC_DESTINATION(d) ((d) << 32) -#define MSR_X2APIC_LVTT 0x832 +#define MSR_X2APIC_LVTT 0x832 # define MSR_X2APIC_LVTT_X1 0x0000000B /* divide counts by 1 */ # define MSR_X2APIC_LVTT_PERIODIC 0x00020000 /* Periodic */ # define MSR_X2APIC_LVTT_TSC_DEADLINE 0x00040000 /* Enable TSC DEADLINE One-shot timer */ -#define MSR_X2APIC_LVTTHER 0x833 -#define MSR_X2APIC_LVTPMR 0x834 -#define MSR_X2APIC_LINT0 0x835 -#define MSR_X2APIC_LINT1 0x836 -#define MSR_X2APIC_LERR 0x837 +#define MSR_X2APIC_LVTTHER 0x833 +#define MSR_X2APIC_LVTPMR 0x834 +#define MSR_X2APIC_LINT0 0x835 +#define MSR_X2APIC_LINT1 0x836 +#define MSR_X2APIC_LERR 0x837 # define MSR_X2APIC_MASKED 0x00010000 /* Interrupt masked */ -#define MSR_X2APIC_TMICT 0x838 -#define MSR_X2APIC_TMCCT 0x839 -#define MSR_X2APIC_TDCR 0x83e -#define MSR_IA32_XSS 0xda0 +#define MSR_X2APIC_TMICT 0x838 +#define MSR_X2APIC_TMCCT 0x839 +#define MSR_X2APIC_TDCR 0x83e +#define MSR_IA32_XSS 0xda0 /* IOAPIC related Definitions */ -#define IOAPIC_BASE 0xfec00000 -#define IOAPIC_REG_INDEX 0x00 -#define IOAPIC_REG_DATA 0x10 -# define IOAPIC_REG_ID 0x00 /* Register index: ID */ -# define IOAPIC_REG_VER 0x01 /* Register index: version */ -# define IOAPIC_REG_TABLE 0x10 /* Redirection table base */ -# define IOAPIC_PIN_DISABLE (1 << 16) /* Disable */ +#define IOAPIC_BASE 0xfec00000 +#define IOAPIC_REG_INDEX 0x00 +#define IOAPIC_REG_DATA 0x10 +# define IOAPIC_REG_ID 0x00 /* Register index: ID */ +# define IOAPIC_REG_VER 0x01 /* Register index: version */ +# define IOAPIC_REG_TABLE 0x10 /* Redirection table base */ +# define IOAPIC_PIN_DISABLE (1 << 16) /* Disable */ /* PIC related Definitions */ -#define X86_IO_PORT_PIC1_CMD 0x20 -#define X86_IO_PORT_PIC1_DATA (X86_IO_PORT_PIC1_CMD + 1) -#define X86_IO_PORT_PIC2_CMD 0xA0 -#define X86_IO_PORT_PIC2_DATA (X86_IO_PORT_PIC2_CMD + 2) +#define X86_IO_PORT_PIC1_CMD 0x20 +#define X86_IO_PORT_PIC1_DATA (X86_IO_PORT_PIC1_CMD + 1) +#define X86_IO_PORT_PIC2_CMD 0xA0 +#define X86_IO_PORT_PIC2_DATA (X86_IO_PORT_PIC2_CMD + 2) -#define X86_PIC_INIT 0x11 -#define X86_PIC1_CASCADE 4 -#define X86_PIC2_CASCADE 2 -#define X86_PIC_8086 1 -#define X86_PIC_EOI 0x20 +#define X86_PIC_INIT 0x11 +#define X86_PIC1_CASCADE 4 +#define X86_PIC2_CASCADE 2 +#define X86_PIC_8086 1 +#define X86_PIC_EOI 0x20 -#define BITS_PER_LONG 64 +#define BITS_PER_LONG 64 /* Interrupt Stack Table size */ -#define X86_IST_SIZE 104 -#define X86_TSS_SIZE (104 + 8) +#define X86_IST_SIZE 104 +#define X86_TSS_SIZE (104 + 8) /* Reset Control Register (RST_CNT) */ -#define X86_RST_CNT_REG 0xcf9 -# define X86_RST_CNT_SYS_RST 0x02 -# define X86_RST_CNT_CPU_RST 0x04 -# define X86_RST_CNT_FULL_RST 0x08 +#define X86_RST_CNT_REG 0xcf9 +# define X86_RST_CNT_SYS_RST 0x02 +# define X86_RST_CNT_CPU_RST 0x04 +# define X86_RST_CNT_FULL_RST 0x08 /* XSAVE state component bitmap */ -#define X86_XSAVE_X87 (1 << 0) /* Bit 0: X87 state */ -#define X86_XSAVE_SSE (1 << 1) /* Bit 1: SSE state (512 bytes) */ -#define X86_XSAVE_AVX (1 << 2) /* Bit 2: AVX state (256 bytes) */ -#define X86_XSAVE_MPX_BNDREGS (1 << 3) /* Bit 3: MPX BNDREGS (64 bytes) */ -#define X86_XSAVE_MPX_BNDCSR (1 << 4) /* Bit 4: MPX BNDCSR (16 bytes) */ -#define X86_XSAVE_AVX512_OPMASK (1 << 5) /* Bit 5: AVX-512 opmask (64 bytes) */ -#define X86_XSAVE_AVX512_HI256 (1 << 6) /* Bit 6: AVX-512 ZMM_Hi256 (512 bytes) */ -#define X86_XSAVE_AVX512_HI16 (1 << 7) /* Bit 7: AVX-512 Hi16_ZMM (1024 bytes) */ -#define X86_XSAVE_PT (1 << 8) /* Bit 8: PT (72 bytes) */ -#define X86_XSAVE_PKRU (1 << 9) /* Bit 9: PKRU (4 bytes) */ -#define X86_XSAVE_PASID (1 << 10) /* Bit 10: PASID state */ -#define X86_XSAVE_CET_U (1 << 11) /* Bit 11: CET_U state */ -#define X86_XSAVE_CET_S (1 << 12) /* Bit 12: CET_S state */ -#define X86_XSAVE_HDC (1 << 13) /* Bit 13: HDC */ -#define X86_XSAVE_UINTR (1 << 14) /* Bit 14: UINTR state */ -#define X86_XSAVE_LBR (1 << 15) /* Bit 15: LBR state */ -#define X86_XSAVE_HWP (1 << 16) /* Bit 16: HWP state */ -#define X86_XSAVE_AMX_TILECFG (1 << 17) /* Bit 17: AMX TILECFG state (64 bytes) */ -#define X86_XSAVE_AMX_TILEDATA (1 << 18) /* Bit 18: AMX TILEDATA state (8192 bytes) */ +#define X86_XSAVE_X87 (1 << 0) /* Bit 0: X87 state */ +#define X86_XSAVE_SSE (1 << 1) /* Bit 1: SSE state (512 bytes) */ +#define X86_XSAVE_AVX (1 << 2) /* Bit 2: AVX state (256 bytes) */ +#define X86_XSAVE_MPX_BNDREGS (1 << 3) /* Bit 3: MPX BNDREGS (64 bytes) */ +#define X86_XSAVE_MPX_BNDCSR (1 << 4) /* Bit 4: MPX BNDCSR (16 bytes) */ +#define X86_XSAVE_AVX512_OPMASK (1 << 5) /* Bit 5: AVX-512 opmask (64 bytes) */ +#define X86_XSAVE_AVX512_HI256 (1 << 6) /* Bit 6: AVX-512 ZMM_Hi256 (512 bytes) */ +#define X86_XSAVE_AVX512_HI16 (1 << 7) /* Bit 7: AVX-512 Hi16_ZMM (1024 bytes) */ +#define X86_XSAVE_PT (1 << 8) /* Bit 8: PT (72 bytes) */ +#define X86_XSAVE_PKRU (1 << 9) /* Bit 9: PKRU (4 bytes) */ +#define X86_XSAVE_PASID (1 << 10) /* Bit 10: PASID state */ +#define X86_XSAVE_CET_U (1 << 11) /* Bit 11: CET_U state */ +#define X86_XSAVE_CET_S (1 << 12) /* Bit 12: CET_S state */ +#define X86_XSAVE_HDC (1 << 13) /* Bit 13: HDC */ +#define X86_XSAVE_UINTR (1 << 14) /* Bit 14: UINTR state */ +#define X86_XSAVE_LBR (1 << 15) /* Bit 15: LBR state */ +#define X86_XSAVE_HWP (1 << 16) /* Bit 16: HWP state */ +#define X86_XSAVE_AMX_TILECFG (1 << 17) /* Bit 17: AMX TILECFG state (64 bytes) */ +#define X86_XSAVE_AMX_TILEDATA (1 << 18) /* Bit 18: AMX TILEDATA state (8192 bytes) */ /* XSAVE area size */ -#define XSAVE_LEGACY_SIZE (512) /* X87 + SSE */ -#define XSAVE_HEADER_SIZE (64) /* XSAVE header */ -#define XSAVE_AVX_SIZE (256) -#define XSAVE_MXP_BNDREGS_SIZE (64) -#define XSAVE_MXP_BNDCSR_SIZE (16) -#define XSAVE_AVX512OPMASK_SIZE (64) -#define XSAVE_AVX512HI256_SIZE (512) -#define XSAVE_AVX512HI16_SIZE (1024) -#define XSAVE_PT_SIZE (72) -#define XSAVE_PKRU_SIZE (4) -#define XSAVE_HDC_SIZE (8) +#define XSAVE_LEGACY_SIZE (512) /* X87 + SSE */ +#define XSAVE_HEADER_SIZE (64) /* XSAVE header */ +#define XSAVE_AVX_SIZE (256) +#define XSAVE_MXP_BNDREGS_SIZE (64) +#define XSAVE_MXP_BNDCSR_SIZE (16) +#define XSAVE_AVX512OPMASK_SIZE (64) +#define XSAVE_AVX512HI256_SIZE (512) +#define XSAVE_AVX512HI16_SIZE (1024) +#define XSAVE_PT_SIZE (72) +#define XSAVE_PKRU_SIZE (4) +#define XSAVE_HDC_SIZE (8) #ifndef __ASSEMBLY__ @@ -508,6 +549,7 @@ void x86_64_check_and_enable_capability(void); extern void __enable_sse_avx(void); extern void __revoke_low_memory(void); extern void __enable_pcid(void); +extern void x86_64_syscall_entry(void); #ifdef __cplusplus #define EXTERN extern "C" diff --git a/arch/x86_64/include/intel64/irq.h b/arch/x86_64/include/intel64/irq.h index 38e1e335ce554..c21694d7716b3 100644 --- a/arch/x86_64/include/intel64/irq.h +++ b/arch/x86_64/include/intel64/irq.h @@ -359,6 +359,10 @@ #define IRQ_MSI_START IRQ32 +/* Use IRQ17 for TLB shootdown */ + +#define SMP_IPI_TLBSHOOTDOWN_IRQ IRQ17 + /* Common register save structure created by up_saveusercontext() and by * ISR/IRQ interrupt processing. */ @@ -499,10 +503,27 @@ enum ioapic_trigger_mode TRIGGER_LEVEL_ACTIVE_LOW = (1 << 15) | (1 << 13), }; +/* This structure represents the return state from a system call */ + +#ifdef CONFIG_LIB_SYSCALL +struct xcpt_syscall_s +{ + uintptr_t sysreturn; /* The return address */ +}; +#endif + /* This struct defines the way the registers are stored */ struct xcptcontext { +#ifdef CONFIG_BUILD_KERNEL + /* This is the saved address to use when returning from a user-space + * signal handler. + */ + + uintptr_t sigreturn; +#endif + /* These are saved copies of instruction pointer and EFLAGS used during * signal processing. */ @@ -511,9 +532,35 @@ struct xcptcontext uint64_t saved_rflags; uint64_t saved_rsp; +#ifdef CONFIG_ARCH_KERNEL_STACK + /* For kernel stack enabled we can't use tcb->xcp.regs[REG_RSP] as it may + * point to kernel stack if signaled task is waiting now in + * up_switch_context() + */ + + uint64_t saved_ursp; +#endif + /* Register save area - allocated from stack in up_initial_state() */ uint64_t *regs; + +#ifdef CONFIG_ARCH_ADDRENV +# ifdef CONFIG_ARCH_KERNEL_STACK + /* In this configuration, all syscalls execute from an internal kernel + * stack. Why? Because when we instantiate and initialize the address + * environment of the new user process, we will temporarily lose the + * address environment of the old user process, including its stack + * contents. The kernel C logic will crash immediately with no valid + * stack in place. + */ + + uintptr_t *ustkptr; /* Saved user stack pointer */ + uintptr_t *kstack; /* Allocate base of the (aligned) kernel stack */ + uintptr_t *ktopstk; /* Top of kernel stack */ + uintptr_t *kstkptr; /* Saved kernel stack pointer */ +# endif +#endif }; #endif @@ -571,7 +618,7 @@ static inline void set_pcid(uint64_t pcid) static inline void set_cr3(uint64_t cr3) { - __asm__ volatile("mov %0, %%cr3" : "=rm"(cr3) : : "memory"); + __asm__ volatile("mov %0, %%cr3" :: "r"(cr3)); } static inline uint64_t get_cr3(void) diff --git a/arch/x86_64/include/irq.h b/arch/x86_64/include/irq.h index 13cd9ead59f67..f46544a1c8151 100644 --- a/arch/x86_64/include/irq.h +++ b/arch/x86_64/include/irq.h @@ -45,6 +45,14 @@ # include #endif +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define X86_64_CPUPRIV_USTACK_OFFSET (16) +#define X86_64_CPUPRIV_UVBASE_OFFSET (24) +#define X86_64_CPUPRIV_KTOPSTK_OFFSET (32) + /**************************************************************************** * Public Data ****************************************************************************/ @@ -65,6 +73,29 @@ struct intel64_cpu_s */ uint64_t *current_regs; + +#ifdef CONFIG_LIB_SYSCALL + /* Current user RSP for syscall */ + + uint64_t *ustack; + + /* Userspace virtual address */ + + uint64_t *uvbase; +#endif + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Kernel stack pointer. + * + * We have to track the current kernel stack pointer to handle + * syscalls in kernel mode. All registers are occupied when entering + * syscall, so we cannot get this value from tcb in syscall handler. + * We keep referenve to kernel stack in CPU private data and update it + * at each context switch. + */ + + uint64_t *ktopstk; +#endif }; /**************************************************************************** diff --git a/arch/x86_64/include/syscall.h b/arch/x86_64/include/syscall.h index 6e35fc0bb9410..7fc567b10515a 100644 --- a/arch/x86_64/include/syscall.h +++ b/arch/x86_64/include/syscall.h @@ -36,6 +36,52 @@ * Pre-processor Definitions ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_BUILD_FLAT +# define CONFIG_SYS_RESERVED 4 +#else +# define CONFIG_SYS_RESERVED 0 +#endif + +/* system calls */ + +#ifndef CONFIG_BUILD_FLAT +/* SYS call 0: + * + * void up_task_start(main_t taskentry, int argc, char *argv[]) + * noreturn_function; + */ + +# define SYS_task_start (0) + +/* SYS call 1: + * + * void up_pthread_start((pthread_startroutine_t startup, + * pthread_startroutine_t entrypt, pthread_addr_t arg) + * noreturn_function + */ + +# define SYS_pthread_start (1) + +/* SYS call 2: + * + * void signal_handler(_sa_sigaction_t sighand, + * int signo, siginfo_t *info, + * void *ucontext); + */ + +# define SYS_signal_handler (2) + +/* SYS call 3: + * + * void signal_handler_return(void); + */ + +# define SYS_signal_handler_return (3) + +#endif /* !CONFIG_BUILD_FLAT */ + /**************************************************************************** * Public Types ****************************************************************************/ @@ -57,15 +103,6 @@ extern "C" #define EXTERN extern #endif -void enable_syscall(void); -void syscall_entry(void); -uint64_t syscall_handler(unsigned long nbr, uintptr_t parm1, uintptr_t parm2, - uintptr_t parm3, uintptr_t parm4, uintptr_t parm5, - uintptr_t parm6); -uint64_t linux_interface(unsigned long nbr, uintptr_t parm1, uintptr_t parm2, - uintptr_t parm3, uintptr_t parm4, uintptr_t parm5, - uintptr_t parm6); - /* SWI with SYS_ call number and six parameters */ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, @@ -126,24 +163,33 @@ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, uintptr_t parm4, uintptr_t parm5, uintptr_t parm6) { - register uint64_t reg0 __asm__("rax") = (uint64_t)(nbr); - register uint64_t reg1 __asm__("rdi") = (uint64_t)(parm1); - register uint64_t reg2 __asm__("rsi") = (uint64_t)(parm2); - register uint64_t reg3 __asm__("rdx") = (uint64_t)(parm3); - register uint64_t reg4 __asm__("r10") = (uint64_t)(parm4); - register uint64_t reg5 __asm__("r8") = (uint64_t)(parm5); - register uint64_t reg6 __asm__("r9") = (uint64_t)(parm6); - - __asm__ __volatile__ + uint64_t ret; + + /* Registers modified by syscall instruction: + * RCX = RIP + * R11 = RFLAGS + * RIP = IA32_LSTAR (x86_64_syscall_entry) + */ + + __asm__ volatile ( - "syscall" - : "=r"(reg0) - : "r"(reg0), "r"(reg1), "r"(reg2), - "r"(reg3), "r"(reg4), "r"(reg5), "r"(reg6) - : "memory" + "movq %1, %%rax\n" + "movq %2, %%rdi\n" + "movq %3, %%rsi\n" + "movq %4, %%rdx\n" + "movq %5, %%r10\n" + "movq %6, %%r8\n" + "movq %7, %%r9\n" + "syscall\n" + "movq %%rax, %0\n" + : "=r"(ret) + : "rm"(nbr), "rm"(parm1), "rm"(parm2), + "rm"(parm3), "rm"(parm4), "rm"(parm5), + "rm"(parm6) + : "memory", "rcx", "r11" ); - return reg0; + return ret; } #undef EXTERN diff --git a/arch/x86_64/src/common/CMakeLists.txt b/arch/x86_64/src/common/CMakeLists.txt index 37d8dc1f3abec..e8e12d88fc9ec 100644 --- a/arch/x86_64/src/common/CMakeLists.txt +++ b/arch/x86_64/src/common/CMakeLists.txt @@ -29,12 +29,17 @@ set(SRCS x86_64_modifyreg32.c x86_64_nputs.c x86_64_switchcontext.c - x86_64_tcbinfo.c) + x86_64_tcbinfo.c + x86_64_tlb.c) if(CONFIG_ARCH_HAVE_FORK) list(APPEND SRCS x86_64_fork.c fork.S) endif() +if(CONFIG_LIB_SYSCALL) + list(APPEND SRCS x86_64_syscall.c) +endif() + if(CONFIG_PCI) list(APPEND SRCS x86_64_pci.c) endif() @@ -52,11 +57,25 @@ if(CONFIG_ARCH_USE_MMU) endif() if(CONFIG_ARCH_ADDRENV) - list(APPEND SRCS x86_64_addrenv.c x86_64_addrenv_perms.c) + list(APPEND SRCS x86_64_addrenv.c x86_64_pgalloc.c x86_64_addrenv_perms.c) +endif() + +if(NOT CONFIG_BUILD_FLAT) + list(APPEND SRCS x86_64_task_start.c x86_64_pthread_start.c + x86_64_signal_dispatch.c) endif() if(NOT CONFIG_ALARM_ARCH) list(APPEND SRCS x86_64_udelay.c x86_64_mdelay.c) endif() +if(CONFIG_ARCH_KERNEL_STACK) + list(APPEND SRCS x86_64_addrenv_kstack.c) +endif() + +if(NOT CONFIG_BUILD_FLAT) + list(APPEND SRCS x86_64_task_start.c x86_64_pthread_start.c + x86_64_signal_dispatch.c) +endif() + target_sources(arch PRIVATE ${SRCS}) diff --git a/arch/x86_64/src/common/Make.defs b/arch/x86_64/src/common/Make.defs index 52c74c6ba4ff8..29f770b7a97a6 100644 --- a/arch/x86_64/src/common/Make.defs +++ b/arch/x86_64/src/common/Make.defs @@ -18,18 +18,29 @@ # ############################################################################ +ifeq ($(CONFIG_BUILD_KERNEL),y) +crt0$(OBJEXT): crt0.c + $(CC) $(CFLAGS) -c common$(DELIM)crt0.c -o crt0$(OBJEXT) + +STARTUP_OBJS = crt0$(OBJEXT) +endif + # Common x86_64 files CMN_CSRCS += x86_64_allocateheap.c x86_64_copystate.c x86_64_exit.c CMN_CSRCS += x86_64_getintstack.c x86_64_initialize.c x86_64_nputs.c CMN_CSRCS += x86_64_modifyreg8.c x86_64_modifyreg16.c x86_64_modifyreg32.c -CMN_CSRCS += x86_64_switchcontext.c +CMN_CSRCS += x86_64_switchcontext.c x86_64_tlb.c ifeq ($(CONFIG_ARCH_HAVE_FORK),y) CMN_CSRCS += x86_64_fork.c CMN_ASRCS += fork.S endif +ifeq ($(CONFIG_LIB_SYSCALL),y) +CMN_CSRCS += x86_64_syscall.c +endif + ifeq ($(CONFIG_PCI),y) CMN_CSRCS += x86_64_pci.c endif @@ -47,7 +58,18 @@ CMN_CSRCS += x86_64_mmu.c endif ifeq ($(CONFIG_ARCH_ADDRENV),y) -CMN_CSRCS += x86_64_addrenv.c x86_64_addrenv_perms.c +CMN_CSRCS += x86_64_addrenv.c x86_64_pgalloc.c x86_64_addrenv_perms.c +endif + +ifeq ($(CONFIG_ARCH_KERNEL_STACK),y) +CMN_CSRCS += x86_64_addrenv_kstack.c +endif + +ifneq ($(CONFIG_BUILD_FLAT),y) +CMN_CSRCS += x86_64_task_start.c +CMN_CSRCS += x86_64_pthread_start.c +CMN_CSRCS += x86_64_signal_dispatch.c +CMN_UASRCS += x86_64_signal_handler.S endif ifndef CONFIG_ALARM_ARCH diff --git a/arch/x86_64/src/common/Toolchain.defs b/arch/x86_64/src/common/Toolchain.defs index 77ecc2825ca9b..5a57c775298c3 100644 --- a/arch/x86_64/src/common/Toolchain.defs +++ b/arch/x86_64/src/common/Toolchain.defs @@ -241,7 +241,7 @@ LDMODULEFLAGS = -r -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld) CELFFLAGS = $(CFLAGS) -fvisibility=hidden CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden -LDELFFLAGS = -r -e main --gc-sections +LDELFFLAGS = -r -e main LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)modlib$(DELIM)gnu-elf.ld) # -fno-pic to avoid GOT relocations diff --git a/arch/x86_64/src/common/crt0.c b/arch/x86_64/src/common/crt0.c new file mode 100644 index 0000000000000..cdd3321e76d9f --- /dev/null +++ b/arch/x86_64/src/common/crt0.c @@ -0,0 +1,121 @@ +/**************************************************************************** + * arch/x86_64/src/common/crt0.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include + +#ifdef CONFIG_BUILD_KERNEL + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int main(int argc, char *argv[]); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_signal_handler + * + * Description: + * This function is the user-space, signal handler trampoline function. It + * is called from up_signal_dispatch() in user-mode. + * + * Returned Value: + * None. This function does not return in the normal sense. It returns + * via the SYS_signal_handler_return (see syscall.h) + * + ****************************************************************************/ + +static void sig_trampoline(void) naked_function; +static void sig_trampoline(void) +{ + /* RDI = signal + * RSI = info + * RDX = ucontext + * R10 = sighand + * RAX = syscall ID + */ + + __asm__ volatile + ( + "call *%%r10\n" + "movq %0, %%rax\n" + "syscall\n" + :: "i"(SYS_signal_handler_return) + ); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: __start + * + * Description: + * This function is the low level entry point into the main thread of + * execution of a task. It receives initial control when the task is + * started and calls main entry point of the newly started task. + * + * Input Parameters: + * argc - The number of parameters being passed. + * argv - The parameters being passed. These lie in kernel-space memory + * and will have to be reallocated in user-space memory. + * + * Returned Value: + * This function should not return. It should call the user-mode start-up + * main() function. If that function returns, this function will call + * exit. + * + ****************************************************************************/ + +void __start(int argc, char *argv[]) +{ + int ret; + + /* Initialize the reserved area at the beginning of the .bss/.data region + * that is visible to the RTOS. + */ + + ARCH_DATA_RESERVE->ar_sigtramp = (addrenv_sigtramp_t)sig_trampoline; + + /* Call the main() entry point passing argc and argv. */ + + ret = main(argc, argv); + + /* Call exit() if/when the main() returns */ + + exit(ret); +} + +#endif /* CONFIG_BUILD_KERNEL */ diff --git a/arch/x86_64/src/common/pgalloc.h b/arch/x86_64/src/common/pgalloc.h index e85d4ee8b5e70..e1f7531b5a3b9 100644 --- a/arch/x86_64/src/common/pgalloc.h +++ b/arch/x86_64/src/common/pgalloc.h @@ -93,6 +93,28 @@ static inline uintptr_t x86_64_pgpaddr(uintptr_t vaddr) return 0; } +/**************************************************************************** + * Name: x86_64_uservaddr + * + * Description: + * Return true if the virtual address, vaddr, lies in the user address + * space. + * + ****************************************************************************/ + +static inline bool x86_64_uservaddr(uintptr_t vaddr) +{ + /* Check if this address is within the range of the virtualized .bss/.data, + * heap, or stack regions. + */ + + return ((vaddr >= ARCH_ADDRENV_VBASE && vaddr < ARCH_ADDRENV_VEND) +#ifdef CONFIG_ARCH_VMA_MAPPING + || (vaddr >= CONFIG_ARCH_SHM_VBASE && vaddr < ARCH_SHM_VEND) +#endif + ); +} + /**************************************************************************** * Name: x86_64_pgwipe * diff --git a/arch/x86_64/src/common/x86_64_addrenv.c b/arch/x86_64/src/common/x86_64_addrenv.c index 4d2cc30fa3539..df5ea2b710d7e 100644 --- a/arch/x86_64/src/common/x86_64_addrenv.c +++ b/arch/x86_64/src/common/x86_64_addrenv.c @@ -460,6 +460,10 @@ int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize, SP_DSB(); SP_DMB(); +#ifdef CONFIG_SMP + x86_64_tlb_shootdown(); +#endif + return OK; errout: @@ -554,6 +558,10 @@ int up_addrenv_destroy(arch_addrenv_t *addrenv) SP_DSB(); SP_DMB(); +#ifdef CONFIG_SMP + x86_64_tlb_shootdown(); +#endif + memset(addrenv, 0, sizeof(arch_addrenv_t)); return OK; } diff --git a/arch/x86_64/src/common/x86_64_addrenv_kstack.c b/arch/x86_64/src/common/x86_64_addrenv_kstack.c new file mode 100644 index 0000000000000..6a56bf7ca650f --- /dev/null +++ b/arch/x86_64/src/common/x86_64_addrenv_kstack.c @@ -0,0 +1,109 @@ +/**************************************************************************** + * arch/x86_64/src/common/x86_64_addrenv_kstack.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "addrenv.h" + +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_KERNEL_STACK) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_addrenv_kstackalloc + * + * Description: + * This function is called when a new thread is created to allocate + * the new thread's kernel stack. This function may be called for certain + * terminating threads which have no kernel stack. It must be tolerant of + * that case. + * + * Input Parameters: + * tcb - The TCB of the thread that requires the kernel stack. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int up_addrenv_kstackalloc(struct tcb_s *tcb) +{ + DEBUGASSERT(tcb && tcb->xcp.kstack == NULL); + + /* Allocate the kernel stack */ + + tcb->xcp.kstack = kmm_memalign(STACK_ALIGNMENT, ARCH_KERNEL_STACKSIZE); + if (!tcb->xcp.kstack) + { + berr("ERROR: Failed to allocate the kernel stack\n"); + return -ENOMEM; + } + + return OK; +} + +/**************************************************************************** + * Name: up_addrenv_kstackfree + * + * Description: + * This function is called when any thread exits. This function frees + * the kernel stack. + * + * Input Parameters: + * tcb - The TCB of the thread that no longer requires the kernel stack. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int up_addrenv_kstackfree(struct tcb_s *tcb) +{ + DEBUGASSERT(tcb); + + /* Does the exiting thread have a kernel stack? */ + + if (tcb->xcp.kstack) + { + /* Yes.. Free the kernel stack */ + + kmm_free(tcb->xcp.kstack); + tcb->xcp.kstack = NULL; + } + + return OK; +} + +#endif /* CONFIG_ARCH_ADDRENV && CONFIG_ARCH_KERNEL_STACK */ diff --git a/arch/x86_64/src/common/x86_64_allocateheap.c b/arch/x86_64/src/common/x86_64_allocateheap.c index 0dbfc9a7f90e1..0623f8fe398a4 100644 --- a/arch/x86_64/src/common/x86_64_allocateheap.c +++ b/arch/x86_64/src/common/x86_64_allocateheap.c @@ -93,7 +93,11 @@ const uintptr_t g_idle_topstack[CONFIG_SMP_NCPUS] = * ****************************************************************************/ +#ifdef CONFIG_BUILD_KERNEL +void up_allocate_kheap(void **heap_start, size_t *heap_size) +#else void up_allocate_heap(void **heap_start, size_t *heap_size) +#endif /* CONFIG_BUILD_KERNEL */ { uintptr_t hstart; uintptr_t topstack; diff --git a/arch/x86_64/src/common/x86_64_exit.c b/arch/x86_64/src/common/x86_64_exit.c index 093f60fcac955..eccaa89e2a6dc 100644 --- a/arch/x86_64/src/common/x86_64_exit.c +++ b/arch/x86_64/src/common/x86_64_exit.c @@ -89,6 +89,12 @@ void up_exit(int status) restore_critical_section(tcb, this_cpu()); +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Update kernel stack top pointer */ + + x86_64_set_ktopstk(tcb->xcp.ktopstk); +#endif + /* Then switch contexts */ x86_64_fullcontextrestore(tcb->xcp.regs); diff --git a/arch/x86_64/src/common/x86_64_internal.h b/arch/x86_64/src/common/x86_64_internal.h index 878fe73b81938..9825e1063d11e 100644 --- a/arch/x86_64/src/common/x86_64_internal.h +++ b/arch/x86_64/src/common/x86_64_internal.h @@ -32,6 +32,7 @@ # include # include # include +# include # include #endif @@ -191,15 +192,34 @@ extern uint8_t _stbss[]; /* Start of .tbss */ extern uint8_t _etbss[]; /* End+1 of .tbss */ #endif +#ifndef __ASSEMBLY__ + /**************************************************************************** * Inline Functions ****************************************************************************/ +#ifdef CONFIG_ARCH_KERNEL_STACK +static inline_function uint64_t *x86_64_get_ktopstk(void) +{ + uint64_t *ktopstk; + __asm__ volatile("movq %%gs:(%c1), %0" + : "=rm" (ktopstk) + : "i" (offsetof(struct intel64_cpu_s, ktopstk))); + return ktopstk; +} + +static inline_function void x86_64_set_ktopstk(uint64_t *ktopstk) +{ + __asm__ volatile("movq %0, %%gs:(%c1)" + :: "r" (ktopstk), "i" (offsetof(struct intel64_cpu_s, + ktopstk))); +} +#endif + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ -#ifndef __ASSEMBLY__ /* Atomic modification of registers */ void modifyreg8(unsigned int addr, uint8_t clearbits, uint8_t setbits); @@ -232,7 +252,7 @@ void x86_64_lowputs(const char *str); void x86_64_restore_auxstate(struct tcb_s *rtcb); void x86_64_checktasks(void); -void x86_64_syscall(uint64_t *regs); +uint64_t *x86_64_syscall(uint64_t *regs); #ifdef CONFIG_ARCH_MULTIBOOT2 void x86_64_mb2_fbinitialize(struct multiboot_tag_framebuffer *tag); @@ -286,6 +306,11 @@ size_t x86_64_stack_check(void *stackbase, size_t nbytes); void x86_64_stack_color(void *stackbase, size_t nbytes); #endif +/* TLB shootdown */ + +int x86_64_tlb_handler(int irq, void *c, void *arg); +void x86_64_tlb_shootdown(void); + #endif /* __ASSEMBLY__ */ #endif /* __ARCH_X86_64_SRC_COMMON_UP_INTERNAL_H */ diff --git a/arch/x86_64/src/common/x86_64_pgalloc.c b/arch/x86_64/src/common/x86_64_pgalloc.c new file mode 100644 index 0000000000000..75db0cbe70379 --- /dev/null +++ b/arch/x86_64/src/common/x86_64_pgalloc.c @@ -0,0 +1,232 @@ +/**************************************************************************** + * arch/x86_64/src/common/x86_64_pgalloc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "addrenv.h" +#include "pgalloc.h" +#include "x86_64_mmu.h" + +#ifdef CONFIG_BUILD_KERNEL + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Last PGT level */ + +#define PGT_LAST (X86_MMU_PT_LEVELS) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: x86_64_get_pgtable + * + * Description: + * Get the physical address of the final level page table corresponding to + * 'vaddr'. If one does not exist, it will be allocated. + * + * Input Parameters: + * addrenv - Pointer to a structure describing the address environment + * vaddr - Virtual address to query for + * + * Returned Value: + * The physical address of the corresponding final level page table, or + * NULL if one does not exist, and there is no free memory to allocate one + * + ****************************************************************************/ + +uintptr_t x86_64_get_pgtable(arch_addrenv_t *addrenv, uintptr_t vaddr) +{ + uintptr_t paddr; + uintptr_t ptprev; + uint32_t ptlevel; + uint32_t flags; + + /* Get the current level MAX_LEVELS-1 entry corresponding to this vaddr */ + + ptlevel = ARCH_SPGTS; + ptprev = x86_64_pgvaddr(addrenv->spgtables[ARCH_SPGTS - 1]); + if (!ptprev) + { + /* Something is very wrong */ + + return 0; + } + + /* Find the physical address of the final level page table */ + + paddr = mmu_pte_to_paddr(mmu_ln_getentry(ptlevel, ptprev, vaddr)); + if (!paddr) + { + /* No page table has been allocated... allocate one now */ + + paddr = mm_pgalloc(1); + if (paddr) + { + /* Determine page table flags */ + + if (x86_64_uservaddr(vaddr)) + { + flags = MMU_UPGT_FLAGS; + } + else + { + flags = MMU_KPGT_FLAGS; + } + + /* Wipe the page and assign it */ + + x86_64_pgwipe(paddr); + mmu_ln_setentry(ptlevel, ptprev, paddr, vaddr, flags); + } + } + + /* Flush the data cache, so the changes are committed to memory */ + + SP_DMB(); + + return paddr; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pgalloc + * + * Description: + * If there is a page allocator in the configuration and if and MMU is + * available to map physical addresses to virtual address, then function + * must be provided by the platform-specific code. This is part of the + * implementation of sbrk(). This function will allocate the requested + * number of pages using the page allocator and map them into consecutive + * virtual addresses beginning with 'brkaddr' + * + * NOTE: This function does not use the up_ naming standard because it + * is indirectly callable from user-space code via a system trap. + * Therefore, it is a system interface and follows a different naming + * convention. + * + * Input Parameters: + * brkaddr - The heap break address. The next page will be allocated and + * mapped to this address. Must be page aligned. If the memory manager + * has not yet been initialized and this is the first block requested for + * the heap, then brkaddr should be zero. pgalloc will then assigned the + * well-known virtual address of the beginning of the heap. + * npages - The number of pages to allocate and map. Mapping of pages + * will be contiguous beginning beginning at 'brkaddr' + * + * Returned Value: + * The (virtual) base address of the mapped page will returned on success. + * Normally this will be the same as the 'brkaddr' input. However, if + * the 'brkaddr' input was zero, this will be the virtual address of the + * beginning of the heap. Zero is returned on any failure. + * + ****************************************************************************/ + +uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages) +{ + struct tcb_s *tcb = nxsched_self(); + struct arch_addrenv_s *addrenv; + uintptr_t ptlast; + uintptr_t paddr; + uintptr_t vaddr; + + DEBUGASSERT(tcb && tcb->addrenv_own); + addrenv = &tcb->addrenv_own->addrenv; + + /* The current implementation only supports extending the user heap + * region as part of the implementation of user sbrk(). This function + * needs to be expanded to also handle (1) extending the user stack + * space and (2) extending the kernel memory regions as well. + */ + + /* brkaddr = 0 means that no heap has yet been allocated */ + + if (!brkaddr) + { + brkaddr = addrenv->heapvbase; + } + + /* Start mapping from the old heap break address */ + + vaddr = brkaddr; + + /* Sanity checks */ + + DEBUGASSERT(brkaddr >= addrenv->heapvbase); + DEBUGASSERT(MM_ISALIGNED(brkaddr)); + + for (; npages > 0; npages--) + { + /* Get the address of the last level page table */ + + ptlast = x86_64_pgvaddr(x86_64_get_pgtable(addrenv, vaddr)); + if (!ptlast) + { + return 0; + } + + /* Allocate physical memory for the new heap */ + + paddr = mm_pgalloc(1); + if (!paddr) + { + return 0; + } + + /* Wipe the memory */ + + x86_64_pgwipe(paddr); + + /* Then add the reference */ + + mmu_ln_setentry(PGT_LAST, ptlast, paddr, vaddr, MMU_UDATA_FLAGS); + vaddr += MM_PGSIZE; + } + + /* Flush the data cache, so the changes are committed to memory */ + + SP_DMB(); + + return brkaddr; +} + +#endif /* CONFIG_BUILD_KERNEL */ diff --git a/arch/x86_64/src/common/x86_64_pthread_start.c b/arch/x86_64/src/common/x86_64_pthread_start.c new file mode 100644 index 0000000000000..de09eef41b595 --- /dev/null +++ b/arch/x86_64/src/common/x86_64_pthread_start.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * arch/x86_64/src/common/x86_64_pthread_start.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include "sched/sched.h" + +#include + +#include "x86_64_internal.h" + +#if !defined(CONFIG_BUILD_FLAT) && defined(__KERNEL__) && \ + !defined(CONFIG_DISABLE_PTHREAD) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_pthread_start + * + * Description: + * In this kernel mode build, this function will be called to execute a + * pthread in user-space. When the pthread is first started, a kernel-mode + * stub will first run to perform some housekeeping functions. This + * kernel-mode stub will then be called transfer control to the user-mode + * pthread. + * + * Normally the a user-mode start-up stub will also execute before the + * pthread actually starts. See libc/pthread/pthread_create.c + * + * Input Parameters: + * startup - The user-space pthread startup function + * entrypt - The user-space address of the pthread entry point + * arg - Standard argument for the pthread entry point + * + * Returned Value: + * This function should not return. It should call the user-mode start-up + * stub and that stub should call pthread_exit if/when the user pthread + * terminates. + * + ****************************************************************************/ + +void up_pthread_start(pthread_trampoline_t startup, + pthread_startroutine_t entrypt, pthread_addr_t arg) +{ +#ifdef CONFIG_ARCH_KERNEL_STACK + struct tcb_s *tcb = this_task(); + + /* Make sure that kernel stack is set for current CPU */ + + if (x86_64_get_ktopstk() == NULL) + { + x86_64_set_ktopstk(tcb->xcp.ktopstk); + } +#endif + + /* Let sys_call3() do all of the work */ + + sys_call3(SYS_pthread_start, (uintptr_t)startup, (uintptr_t)entrypt, + (uintptr_t)arg); + + PANIC(); +} + +#endif /* !CONFIG_BUILD_FLAT && __KERNEL__ && !CONFIG_DISABLE_PTHREAD */ diff --git a/arch/x86_64/src/common/x86_64_signal_dispatch.c b/arch/x86_64/src/common/x86_64_signal_dispatch.c new file mode 100644 index 0000000000000..3a5bcc12bd7e4 --- /dev/null +++ b/arch/x86_64/src/common/x86_64_signal_dispatch.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * arch/x86_64/src/common/x86_64_signal_dispatch.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include + +#include "x86_64_internal.h" + +#if !defined(CONFIG_BUILD_FLAT) && defined(__KERNEL__) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_signal_dispatch + * + * Description: + * In the kernel mode build, this function will be called to execute a + * a signal handler in user-space. When the signal is delivered, a + * kernel-mode stub will first run to perform some housekeeping functions. + * This kernel-mode stub will then be called transfer control to the user + * mode signal handler by calling this function. + * + * Normally the user-mode signaling handling stub will also execute + * before the ultimate signal handler is called. See + * arch/x86_64/src/common/x86_64_signal_handler.S. This function is the + * user-space, signal handler trampoline function. It is called from + * up_signal_dispatch() in user-mode. + * + * Input Parameters: + * sighand - The address user-space signal handling function + * signo, info, and ucontext - Standard arguments to be passed to the + * signal handling function. + * + * Returned Value: + * None. This function does not return in the normal sense. It returns + * via an architecture specific system call made by up_signal_handler(). + * However, this will look like a normal return by the caller of + * up_signal_dispatch. + * + ****************************************************************************/ + +void up_signal_dispatch(_sa_sigaction_t sighand, int signo, + siginfo_t *info, void *ucontext) +{ + /* Let sys_call4() do all of the work */ + + sys_call4(SYS_signal_handler, (uintptr_t)sighand, (uintptr_t)signo, + (uintptr_t)info, (uintptr_t)ucontext); +} + +#endif /* !CONFIG_BUILD_FLAT && __KERNEL__ */ diff --git a/arch/x86_64/src/common/x86_64_switchcontext.c b/arch/x86_64/src/common/x86_64_switchcontext.c index cb461e870883b..d7e0883b17132 100644 --- a/arch/x86_64/src/common/x86_64_switchcontext.c +++ b/arch/x86_64/src/common/x86_64_switchcontext.c @@ -59,6 +59,12 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) { int cpu; +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Update kernel stack top pointer */ + + x86_64_set_ktopstk(tcb->xcp.ktopstk); +#endif + /* Are we in an interrupt handler? */ if (up_interrupt_context()) diff --git a/arch/x86_64/src/common/x86_64_syscall.c b/arch/x86_64/src/common/x86_64_syscall.c new file mode 100644 index 0000000000000..d00a1f324ad38 --- /dev/null +++ b/arch/x86_64/src/common/x86_64_syscall.c @@ -0,0 +1,331 @@ +/**************************************************************************** + * arch/x86_64/src/common/x86_64_syscall.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "x86_64_internal.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Syscall function */ + +typedef uintptr_t (*syscall_stub_t)(int nbr, + uintptr_t parm1, uintptr_t parm2, + uintptr_t parm3, uintptr_t parm4, + uintptr_t parm5, uintptr_t parm6); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dump_syscall + * + * Description: + * Dump the syscall registers + * + ****************************************************************************/ + +static void dump_syscall(const char *tag, uint64_t *regs) +{ + unsigned int cmd = regs[REG_RAX]; + +#ifdef CONFIG_LIB_SYSCALL + if (cmd >= CONFIG_SYS_RESERVED) + { + svcinfo("SYSCALL %s: cmd: %d name: %s\n", tag, + cmd, g_funcnames[cmd - CONFIG_SYS_RESERVED]); + } + else +#endif + { + svcinfo("SYSCALL %s: cmd: %d\n", tag, cmd); + } + + svcinfo(" RSP: %" PRIx64 " RCX: %" PRIx64 "\n", + regs[REG_RSP], regs[REG_RCX]); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: x86_64_syscall + * + * Description: + * Syscall handler called from x86_64_syscall_entry(). + * Current registers stored in regs argument. + * The syscall is called with: + * + * - RAX = system call command, and + * - RDI, RSI, RDX, R10, R8, R9 = variable number of arguments depending + * on the system call. + * + ****************************************************************************/ + +uint64_t *x86_64_syscall(uint64_t *regs) +{ + unsigned int cmd = regs[REG_RAX]; + uint64_t arg1 = regs[REG_RDI]; + uint64_t arg2 = regs[REG_RSI]; + uint64_t arg3 = regs[REG_RDX]; + uint64_t arg4 = regs[REG_R10]; + uint64_t arg5 = regs[REG_R8]; + uint64_t arg6 = regs[REG_R9]; + uintptr_t ret = 0; + + /* The syscall command is in RAX on entry */ + + dump_syscall("Entry", regs); + + /* Handle the syscall according to the command in RAX */ + + switch (cmd) + { +#ifdef CONFIG_BUILD_KERNEL + /* cmd=SYS_task_start: This a user task start + * + * void up_task_start(main_t taskentry, int argc, char *argv[]) + * noreturn_function; + * + * At this point, the following values are saved in context: + * + * cmd = SYS_task_start + * arg1 = taskentry + * arg2 = argc + * arg3 = argv + */ + + case SYS_task_start: + { + /* Set up to return to the user-space _start function in + * unprivileged mode. We need: + * + * RDI = argc + * RSI = argv + * RCX = taskentry (SYSRETQ return address) + * + */ + + regs[REG_RDI] = arg2; + regs[REG_RSI] = arg3; + regs[REG_RCX] = arg1; + + break; + } + + /* cmd=SYS_pthread_start: This a user pthread start + * + * void up_pthread_start(pthread_startroutine_t entrypt, + * pthread_addr_t arg) noreturn_function; + * + * At this point, the following values are saved in context: + * + * cmd = SYS_pthread_start + * arg1 = startup + * arg2 = entrypt + * arg3 = arg + */ + + case SYS_pthread_start: + { + /* Set up to enter the user-space pthread start-up function in + * unprivileged mode. We need: + * + * RDI = entrypt + * RSI = arg + * RCX = startup (SYSRETQ return address) + */ + + regs[REG_RDI] = arg2; + regs[REG_RSI] = arg3; + regs[REG_RCX] = arg1; + + break; + } + + /* cmd=SYS_signal_handler: This a user signal handler callback + * + * void signal_handler(_sa_sigaction_t sighand, int signo, + * siginfo_t *info, void *ucontext); + * + * At this point, the following values are saved in context: + * + * cmd = SYS_signal_handler + * arg1 = sighand + * arg2 = signo + * arg3 = info + * arg4 = ucontext (on the stack) + */ + + case SYS_signal_handler: + { + struct tcb_s *rtcb = nxsched_self(); + + /* Remember the caller's return address */ + + DEBUGASSERT(rtcb->xcp.sigreturn == 0); + rtcb->xcp.sigreturn = regs[REG_RCX]; + + /* Set up to return to the user-space trampoline function in + * unprivileged mode. + */ + + regs[REG_RCX] = (uint64_t)ARCH_DATA_RESERVE->ar_sigtramp; + + /* Change the parameter ordering to match the expectation of struct + * userpace_s signal_handler. + */ + + regs[REG_RDI] = arg2; /* signal */ + regs[REG_RSI] = arg3; /* info */ + regs[REG_RDX] = arg4; /* ucontext */ + regs[REG_R10] = arg1; /* sighand */ + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* If we are signalling a user process, then we must be operating + * on the kernel stack now. We need to switch back to the user + * stack before dispatching the signal handler to the user code. + * The existence of an allocated kernel stack is sufficient + * information to make this decision. + */ + + if (rtcb->xcp.kstack != NULL) + { + uint64_t usp; + + /* Copy "info" into user stack */ + + usp = rtcb->xcp.saved_ursp - 8; + + /* Create a frame for info and copy the kernel info */ + + usp = usp - sizeof(siginfo_t); + memcpy((void *)usp, (void *)regs[REG_RSI], sizeof(siginfo_t)); + + /* Now set the updated SP and user copy of "info" to RSI */ + + regs[REG_RSP] = usp; + regs[REG_RSI] = usp; + } +#endif + + break; + } + + /* cmd=SYS_signal_handler_return: This a user signal handler callback + * + * void signal_handler_return(void); + * + * At this point, the following values are saved in context: + * + * cmd = SYS_signal_handler_return + */ + + case SYS_signal_handler_return: + { + /* Set up to return to the user-space. We need: + * + * RCX = taskentry (SYSRETQ return address) + * + */ + + struct tcb_s *rtcb = nxsched_self(); + + /* Set up to return to the kernel-mode signal dispatching logic. */ + + DEBUGASSERT(rtcb->xcp.sigreturn != 0); + + regs[REG_RCX] = rtcb->xcp.sigreturn; + regs[REG_RSP] = rtcb->xcp.saved_rsp; + rtcb->xcp.sigreturn = 0; + + /* For kernel mode, we should be already on a correct kernel stack + * which was recovered in x86_64_syscall_entry. + */ + + break; + } +#endif /* CONFIG_BUILD_KERNEL */ + + /* This is not an architecture-specific system call. If NuttX is + * built as a standalone kernel with a system call interface, then + * all of the additional system calls must be handled as in the + * default case. + */ + + default: + { + int nbr = cmd - CONFIG_SYS_RESERVED; + struct tcb_s *rtcb = nxsched_self(); + syscall_stub_t stub = (syscall_stub_t)g_stublookup[nbr]; + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Store reference to user RSP for signals */ + + rtcb->xcp.saved_ursp = regs[REG_RSP]; +#endif + + /* Re-enable interrupts if enabled before. + * Current task RFLAGS are stored in R11. + */ + + if (regs[REG_R11] & X86_64_RFLAGS_IF) + { + up_irq_restore(X86_64_RFLAGS_IF); + } + + /* Call syscall function */ + + ret = stub(nbr, arg1, arg2, arg3, arg4, arg5, arg6); + + break; + } + } + + dump_syscall("Exit", regs); + + /* Store return value in RAX register */ + + regs[REG_RAX] = ret; + + /* Return pointer to regs */ + + return regs; +} diff --git a/arch/x86_64/src/common/x86_64_task_start.c b/arch/x86_64/src/common/x86_64_task_start.c new file mode 100644 index 0000000000000..8e12802032cb8 --- /dev/null +++ b/arch/x86_64/src/common/x86_64_task_start.c @@ -0,0 +1,87 @@ +/**************************************************************************** + * arch/x86_64/src/common/x86_64_task_start.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "sched/sched.h" + +#include + +#include "x86_64_internal.h" + +#ifndef CONFIG_BUILD_FLAT + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_task_start + * + * Description: + * In this kernel mode build, this function will be called to execute a + * task in user-space. When the task is first started, a kernel-mode + * stub will first run to perform some housekeeping functions. This + * kernel-mode stub will then be called transfer control to the user-mode + * task. + * + * Normally the a user-mode start-up stub will also execute before the + * task actually starts. See libc/sched/task_startup.c + * + * Input Parameters: + * taskentry - The user-space entry point of the task. + * argc - The number of parameters being passed. + * argv - The parameters being passed. These lie in kernel-space memory + * and will have to be reallocated in user-space memory. + * + * Returned Value: + * This function should not return. It should call the user-mode start-up + * stub and that stub should call exit if/when the user task terminates. + * + ****************************************************************************/ + +void up_task_start(main_t taskentry, int argc, char *argv[]) +{ +#ifdef CONFIG_ARCH_KERNEL_STACK + struct tcb_s *tcb = this_task(); + + /* Make sure that kernel stack is set for current CPU */ + + if (x86_64_get_ktopstk() == NULL) + { + x86_64_set_ktopstk(tcb->xcp.ktopstk); + } +#endif + + /* Let sys_call3() do all of the work */ + + sys_call3(SYS_task_start, (uintptr_t)taskentry, (uintptr_t)argc, + (uintptr_t)argv); + + PANIC(); +} + +#endif /* !CONFIG_BUILD_FLAT */ diff --git a/arch/x86_64/src/common/x86_64_tlb.c b/arch/x86_64/src/common/x86_64_tlb.c new file mode 100644 index 0000000000000..fb65b5b946f3f --- /dev/null +++ b/arch/x86_64/src/common/x86_64_tlb.c @@ -0,0 +1,70 @@ +/**************************************************************************** + * arch/x86_64/src/common/x86_64_tlb.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sched/sched.h" + +#include "x86_64_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: x86_64_tlb_handler + * + * Description: + * Reload CR3 to invalidate the TLB. + * + ****************************************************************************/ + +int x86_64_tlb_handler(int irq, void *c, void *arg) +{ + volatile uint64_t cr3 = get_cr3(); + + set_cr3(cr3); + + UNUSED(irq); + UNUSED(c); + UNUSED(arg); + + return OK; +} + +/**************************************************************************** + * Name: x86_64_tlb_shootdown + ****************************************************************************/ + +void x86_64_tlb_shootdown(void) +{ + cpu_set_t cpuset = ((1 << CONFIG_SMP_NCPUS) - 1); + + CPU_CLR(this_cpu(), &cpuset); + + up_trigger_irq(SMP_IPI_TLBSHOOTDOWN_IRQ, cpuset); +} diff --git a/arch/x86_64/src/intel64/intel64_cpu.c b/arch/x86_64/src/intel64/intel64_cpu.c index 30fcd95f3205a..d17f68a4a84fc 100644 --- a/arch/x86_64/src/intel64/intel64_cpu.c +++ b/arch/x86_64/src/intel64/intel64_cpu.c @@ -242,6 +242,13 @@ void x86_64_cpu_init(void) g_cpu_priv[i].loapic_id = lapic->apic_id; g_cpu_priv[i].id = i; g_cpu_priv[i].ready = false; +#ifdef CONFIG_LIB_SYSCALL + g_cpu_priv[i].ustack = NULL; + g_cpu_priv[i].uvbase = (uint64_t *)CONFIG_ARCH_TEXT_VBASE; +#endif +#ifdef CONFIG_ARCH_KERNEL_STACK + g_cpu_priv[i].ktopstk = NULL; +#endif /* Store private CPU in TSS */ @@ -380,4 +387,46 @@ void x86_64_cpu_priv_set(uint8_t cpu) /* Store private data pointer to GSBASE */ write_gsbase((uintptr_t)&g_cpu_priv[cpu]); + +#ifdef CONFIG_LIB_SYSCALL + /* Configure SYSCALL instruction entry point */ + + write_msr(MSR_LSTAR, (uintptr_t)x86_64_syscall_entry); + + /* Configure CS selection for SYSCALL (kernel) and SYSRET (userspace). + * + * Segment selection for SYSCALL works like this: + * + * CS.Selector = IA32_STAR[47:32] + * SS.Selector := IA32_STAR[47:32] + 8 + * + * This require that we have to fill GDT with kernel code segment + * first and after that we can put kernel data segment. + * + * Segment selection for SYSRET has a really weird setup for 64-bit + * operand size: + * + * CS.Selector = IA32_STAR[63:48]+16 + * SS.Selector = IA32_STAR[63:48]+8 + * + * This require that we have to fill GDT with user data segment + * first and after that we can put user code segment (differently + * than for kernel segments). Then this instruction needs to + * set CS segment for SYSRET at (USERDATA_SEL - 8) to work + * correctly. + */ + + write_msr(MSR_STAR, MSR_STAR_CSSYSCALL(X86_GDT_CODE_SEL) | + MSR_STAR_CSSYSRET(X86_GDT_USERDATA_SEL - 8)); + + /* Mask applied to RFLAGS when making a syscall */ + + write_msr(MSR_FMASK, X86_64_RFLAGS_IF | X86_64_RFLAGS_DF); +#endif + +#ifdef CONFIG_SMP + /* Attach TLB shootdown handler */ + + irq_attach(SMP_IPI_TLBSHOOTDOWN_IRQ, x86_64_tlb_handler, NULL); +#endif } diff --git a/arch/x86_64/src/intel64/intel64_fullcontextrestore.S b/arch/x86_64/src/intel64/intel64_fullcontextrestore.S index 55b1ee871de45..79b9d64308efd 100644 --- a/arch/x86_64/src/intel64/intel64_fullcontextrestore.S +++ b/arch/x86_64/src/intel64/intel64_fullcontextrestore.S @@ -130,9 +130,12 @@ x86_64_fullcontextrestore: movq (8*REG_RAX)(%rdi), %rax - /* Restore the correct value of EAX and then return */ + /* Restore the correct value of RDI */ popq %rdi + + /* Pops 5 things at once: RIP, CS, RFLAGS RSP and SS */ + iretq .size x86_64_fullcontextrestore, . - x86_64_fullcontextrestore .end diff --git a/arch/x86_64/src/intel64/intel64_head.S b/arch/x86_64/src/intel64/intel64_head.S index d9b8f16ba955e..6fa98b60aad86 100644 --- a/arch/x86_64/src/intel64/intel64_head.S +++ b/arch/x86_64/src/intel64/intel64_head.S @@ -53,6 +53,12 @@ # define X86_CR4_FPU_VAL (X86_CR4_OSXFSR | X86_CR4_XMMEXCPT) #endif +/* XSAVE header data offset */ + +#define X86_XSAVE_XSTATEBV_OFFSET 512 +#define X86_XSAVE_XCOMPBC_OFFSET 520 +#define X86_XSAVE_RESERVED0_OFFSET 528 + /* Memory Map: _sbss is the start of the BSS region (see ld.script) _ebss is * the end of the BSS region (see ld.script). The idle task stack starts at * the end of BSS and is of size CONFIG_IDLETHREAD_STACKSIZE. The IDLE thread @@ -72,6 +78,10 @@ .global __enable_sse_avx .global __enable_pcid .global __revoke_low_memory +#ifdef CONFIG_LIB_SYSCALL + .global x86_64_syscall_entry + .global x86_64_syscall +#endif .global __nxstart /* __nxstart is defined elsewhere */ .global nx_start /* nx_start is defined elsewhere */ .global x86_64_ap_boot /* x86_64_ap_boot is defined elsewhere */ @@ -336,7 +346,11 @@ start64_init: movl $MSR_EFER, %ecx rdmsr +#ifdef CONFIG_LIB_SYSCALL + or $(EFER_LME | EFER_SCE), %eax +#else or $EFER_LME, %eax +#endif wrmsr /* Enable paging related bits in CR0 */ @@ -517,6 +531,173 @@ __enable_pcid: .size __enable_pcid, . - __enable_pcid +#ifdef CONFIG_LIB_SYSCALL + /**************************************************************************** + * Name: x86_64_syscall_entry + * + * Description: + * Landing point for syscall instruction. + * + * At this point RFLAGS are masked with MSR_FMASK + * - IF=0 (interrupts are disabled) + * - DF=0 + * + ****************************************************************************/ + + .type x86_64_syscall_entry, @function +x86_64_syscall_entry: + /* Store current RSP on CPU private data first */ + movq %rsp, %gs:X86_64_CPUPRIV_USTACK_OFFSET + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* If current RSP is greater than kernel stack, we have to switch stack. + * Otherwise we are in nested syscall and we can't modify stack pointer + */ + cmp %gs:X86_64_CPUPRIV_UVBASE_OFFSET, %rsp + jb no_kstack_switch + + /* Change to kernel stack */ + movq %gs:X86_64_CPUPRIV_KTOPSTK_OFFSET, %rsp +no_kstack_switch: +#endif + + /* Store some registers on stack. + * We need some free registers here to handle stored registers alignment + * and kernel stack for nested syscalls but at this point we don't have any + * + * RDI is needed only for CONFIG_ARCH_KERNEL_STACK=y but to simplify + * the logic here - we always release it. + */ + pushq %rcx + pushq %rdi + + /* Get original kernel stack for this call */ + + movq %rsp, %rdi + add $16, %rdi + + /* Get aligned registers area */ + movq %rsp, %rcx + sub $8, %rcx + sub $((XCPTCONTEXT_REGS + 8) * 8), %rcx + add $(0x3f), %rcx + and $(0xffffffffffffffc0), %rcx + + /* Syscall arguments */ + movq %rax, (8*REG_RAX)(%rcx) + movq %rsi, (8*REG_RSI)(%rcx) + movq %rdx, (8*REG_RDX)(%rcx) + movq %r10, (8*REG_R10)(%rcx) + movq %r8, (8*REG_R8)(%rcx) + movq %r9, (8*REG_R9)(%rcx) + + /* Callee registers */ + movq %rbx, (8*REG_RBX)(%rcx) + movq %r11, (8*REG_R11)(%rcx) + movq %r12, (8*REG_R12)(%rcx) + movq %r13, (8*REG_R13)(%rcx) + movq %r14, (8*REG_R14)(%rcx) + movq %r15, (8*REG_R15)(%rcx) + movq %rbp, (8*REG_RBP)(%rcx) + +#ifndef CONFIG_ARCH_X86_64_HAVE_XSAVE + /* Save xmm registers */ + fxsaveq (%rcx) +#else +# ifdef CONFIG_ARCH_CHIP_INTEL64_QEMU + /* BUGFIX for QEMU: make sure that xsave header is zeroed! + * QEMU desn't clear these fields during xsave, so if the memory region + * for xsave state was not cleared before use, there may be junk data there, + * that cause xrstor to crash later. + */ + movq $0, (X86_XSAVE_XSTATEBV_OFFSET)(%rcx) + movq $0, (X86_XSAVE_XCOMPBC_OFFSET)(%rcx) + movq $0, (X86_XSAVE_RESERVED0_OFFSET)(%rcx) +# endif + + movl $XSAVE_STATE_COMPONENTS, %eax + xor %edx, %edx + xsave (%rcx) +#endif + + /* Save RDI and RCX which are on stack now */ + popq (8*REG_RDI)(%rcx) + popq (8*REG_RCX)(%rcx) + + /* Store user stack pointer. We can't movq directly here. + * NOTE: for nested syscalls this value points to kernel stack. + */ + pushq %gs:X86_64_CPUPRIV_USTACK_OFFSET + popq (8*REG_RSP)(%rcx) + + /* Move stack pointer after registers area */ + movq %rcx, %rsp + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Update stored kernel stack */ + movq %rsp, %gs:X86_64_CPUPRIV_KTOPSTK_OFFSET + + /* Store original kernel stack on stack which is now in RDI */ + pushq %rdi +#endif + + /* Return value from syscall stored in rax */ + movq %rcx, %rdi + call x86_64_syscall + movq %rax, %rdi + +#ifndef CONFIG_ARCH_X86_64_HAVE_XSAVE + /* Restore xmm registers */ + fxrstorq (%rdi) +#else + movl $XSAVE_STATE_COMPONENTS, %eax + xor %edx, %edx + xrstor (%rdi) +#endif + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Restore original kernel stack */ + popq %gs:X86_64_CPUPRIV_KTOPSTK_OFFSET +#endif + + /* Restore original user RSP */ + movq (8*REG_RSP)(%rdi), %rsp + + /* Restore CPU registers - regs are on RDI now */ + movq (8*REG_RBX)(%rdi), %rbx + movq (8*REG_R11)(%rdi), %r11 + movq (8*REG_R12)(%rdi), %r12 + movq (8*REG_R13)(%rdi), %r13 + movq (8*REG_R14)(%rdi), %r14 + movq (8*REG_R15)(%rdi), %r15 + movq (8*REG_RBP)(%rdi), %rbp + + movq (8*REG_RAX)(%rdi), %rax + movq (8*REG_RSI)(%rdi), %rsi + movq (8*REG_RDX)(%rdi), %rdx + movq (8*REG_R10)(%rdi), %r10 + movq (8*REG_RCX)(%rdi), %rcx + + movq (8*REG_R11)(%rdi), %r11 + movq (8*REG_RDI)(%rdi), %rdi + +# ifdef CONFIG_BUILD_KERNEL + /* Do not return to RING3 if this is nested syscall */ + cmp %gs:X86_64_CPUPRIV_UVBASE_OFFSET, %rcx + jb syscall_no_ring3 + + /* Return to user code pointed in RCX */ + sysretq + +syscall_no_ring3: +# endif + /* Return to address pointed in RCX - must be on stack */ + pushq %rcx + ret + + .size x86_64_syscall_entry, . - x86_64_syscall_entry +#endif + /**************************************************************************** * .data ****************************************************************************/ @@ -534,12 +715,18 @@ g_ist64_low: /* GDT for 64 bit long mode */ .align(16) g_gdt64_low: - .quad 0 - .quad X86_GDT_CODE64_ENTRY - .quad X86_GDT_DATA_ENTRY - .quad X86_GDT_CODE32_ENTRY - .quad X86_GDT_DATA_ENTRY - .quad X86_GDT_CODE64_ENTRY + /* Must be in sequence required by SYSCALL and SYSRET. + * For details look at the comment in intel64_cpu.c about MSR_STAT write. + */ + .quad 0 /* 0x00: null descriptor */ + .quad X86_GDT_CODE64_ENTRY /* 0x08: kernel code 64 */ + .quad X86_GDT_DATA_ENTRY /* 0x10: kernel data */ + .quad X86_GDT_CODE32_ENTRY /* 0x18: kernel code 32 */ + .quad X86_GDT_DATA_ENTRY /* 0x20: kernel data */ + .quad X86_GDT_CODE64_ENTRY /* 0x28: kernel code 64 */ + .quad X86_GDT_DATAUSER_ENTRY /* 0x30: user data */ + .quad X86_GDT_CODEUSER_ENTRY /* 0x38: user code */ + g_gdt64_ist_low: /* TSS segment low + segment high per CPU */ .fill CONFIG_SMP_NCPUS * 16, 1, 0 diff --git a/arch/x86_64/src/intel64/intel64_initialstate.c b/arch/x86_64/src/intel64/intel64_initialstate.c index 0b0ad138f5935..81f324ec4b1e6 100644 --- a/arch/x86_64/src/intel64/intel64_initialstate.c +++ b/arch/x86_64/src/intel64/intel64_initialstate.c @@ -45,6 +45,12 @@ # error XCPTCONTEXT_SIZE must be aligned to XCPTCONTEXT_ALIGN ! #endif +/* Aligned size of the kernel stack */ + +#ifdef CONFIG_ARCH_KERNEL_STACK +# define ARCH_KERNEL_STACKSIZE STACK_ALIGN_UP(CONFIG_ARCH_KERNEL_STACKSIZE) +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -65,6 +71,10 @@ void up_initial_state(struct tcb_s *tcb) { struct xcptcontext *xcp = &tcb->xcp; + uint64_t topstack; +#ifdef CONFIG_ARCH_KERNEL_STACK + uintptr_t *kstack = xcp->kstack; +#endif /* Initialize the idle thread stack */ @@ -102,11 +112,11 @@ void up_initial_state(struct tcb_s *tcb) #ifndef CONFIG_ARCH_X86_64_HAVE_XSAVE /* Set the FCW to 1f80 */ - xcp->regs[1] = (uint64_t)0x0000037f00000000; + xcp->regs[1] = (uint64_t)0x0000037f00000000; /* Set the MXCSR to 1f80 */ - xcp->regs[3] = (uint64_t)0x0000000000001f80; + xcp->regs[3] = (uint64_t)0x0000000000001f80; #else /* Initialize XSAVE region with a valid state */ @@ -116,25 +126,49 @@ void up_initial_state(struct tcb_s *tcb) : "memory"); #endif + topstack = (uint64_t)xcp->regs - 8; + /* Save the initial stack pointer... the value of the stackpointer before * the "interrupt occurs." */ - xcp->regs[REG_RSP] = (uint64_t)xcp->regs - 8; - xcp->regs[REG_RBP] = 0; + xcp->regs[REG_RSP] = topstack; + xcp->regs[REG_RBP] = 0; + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Use the process kernel stack to store context for user processes + * in syscalls. + */ + + if (kstack) + { + xcp->kstack = kstack; + xcp->ustkptr = (uintptr_t *)topstack; + topstack = (uintptr_t)kstack + ARCH_KERNEL_STACKSIZE; + xcp->ktopstk = (uintptr_t *)topstack; + xcp->kstkptr = xcp->ktopstk; + + /* Initialize kernel stack top reference */ + + if (x86_64_get_ktopstk() == NULL) + { + x86_64_set_ktopstk(tcb->xcp.ktopstk); + } + } +#endif /* Save the task entry point */ - xcp->regs[REG_RIP] = (uint64_t)tcb->start; + xcp->regs[REG_RIP] = (uint64_t)tcb->start; /* Set up the segment registers... assume the same segment as the caller. * That is not a good assumption in the long run. */ - xcp->regs[REG_DS] = up_getds(); - xcp->regs[REG_CS] = up_getcs(); - xcp->regs[REG_SS] = up_getss(); - xcp->regs[REG_ES] = up_getes(); + xcp->regs[REG_DS] = up_getds(); + xcp->regs[REG_CS] = up_getcs(); + xcp->regs[REG_SS] = up_getss(); + xcp->regs[REG_ES] = up_getes(); /* FS used by for TLS * used by some libc for TLS and segment reference @@ -156,17 +190,6 @@ void up_initial_state(struct tcb_s *tcb) xcp->regs[REG_GS] = 0; - /* Set supervisor- or user-mode, depending on how NuttX is configured and - * what kind of thread is being started. Disable FIQs in any event - * - * If the kernel build is not selected, then all threads run in - * supervisor-mode. - */ - -#ifdef CONFIG_BUILD_KERNEL -# error "Missing logic for the CONFIG_BUILD_KERNEL build" -#endif - /* Enable or disable interrupts, based on user configuration. If the IF * bit is set, maskable interrupts will be enabled. */ diff --git a/arch/x86_64/src/intel64/intel64_irq.c b/arch/x86_64/src/intel64/intel64_irq.c index baa6e6fd5d1f0..7e71341e874bd 100644 --- a/arch/x86_64/src/intel64/intel64_irq.c +++ b/arch/x86_64/src/intel64/intel64_irq.c @@ -344,11 +344,12 @@ static void up_idtentry(unsigned int index, uint64_t base, uint16_t sel, entry->sel = sel; entry->zero = 0; - /* We must uncomment the OR below when we get to using user-mode. It sets - * the interrupt gate's privilege level to 3. + /* We don't use software interrupts from user-space (INT) so DPL level + * can be set to privilage level 0. DPL bits have no effect on hardware + * interrupts. */ - entry->flags = flags; /* | 0x60 */ + entry->flags = flags; } /**************************************************************************** @@ -367,6 +368,8 @@ static inline void up_idtinit(void) size_t offset = 0; uint64_t vector = 0; int irq = 0; + uint16_t sel = X86_GDT_CODE_SEL; + uint8_t ist = X86_GDT_IST_ISR; memset(&g_idt_entries, 0, sizeof(g_idt_entries)); @@ -375,48 +378,49 @@ static inline void up_idtinit(void) * interrupts enabled when the IRS/IRQ handler is entered. */ - up_idtentry(ISR0, (uint64_t)vector_isr0 , 0x08, 0x8e, 0x2); - up_idtentry(ISR1, (uint64_t)vector_isr1 , 0x08, 0x8e, 0x2); - up_idtentry(ISR2, (uint64_t)vector_isr2 , 0x08, 0x8e, 0x2); - up_idtentry(ISR3, (uint64_t)vector_isr3 , 0x08, 0x8e, 0x2); - up_idtentry(ISR4, (uint64_t)vector_isr4 , 0x08, 0x8e, 0x2); - up_idtentry(ISR5, (uint64_t)vector_isr5 , 0x08, 0x8e, 0x2); - up_idtentry(ISR6, (uint64_t)vector_isr6 , 0x08, 0x8e, 0x2); - up_idtentry(ISR7, (uint64_t)vector_isr7 , 0x08, 0x8e, 0x2); - up_idtentry(ISR8, (uint64_t)vector_isr8 , 0x08, 0x8e, 0x2); - up_idtentry(ISR9, (uint64_t)vector_isr9 , 0x08, 0x8e, 0x2); - up_idtentry(ISR10, (uint64_t)vector_isr10, 0x08, 0x8e, 0x2); - up_idtentry(ISR11, (uint64_t)vector_isr11, 0x08, 0x8e, 0x2); - up_idtentry(ISR12, (uint64_t)vector_isr12, 0x08, 0x8e, 0x2); - up_idtentry(ISR13, (uint64_t)vector_isr13, 0x08, 0x8e, 0x2); - up_idtentry(ISR14, (uint64_t)vector_isr14, 0x08, 0x8e, 0x2); - up_idtentry(ISR15, (uint64_t)vector_isr15, 0x08, 0x8e, 0x2); - up_idtentry(ISR16, (uint64_t)vector_isr16, 0x08, 0x8e, 0x2); - up_idtentry(ISR17, (uint64_t)vector_isr17, 0x08, 0x8e, 0x2); - up_idtentry(ISR18, (uint64_t)vector_isr18, 0x08, 0x8e, 0x2); - up_idtentry(ISR19, (uint64_t)vector_isr19, 0x08, 0x8e, 0x2); - up_idtentry(ISR20, (uint64_t)vector_isr20, 0x08, 0x8e, 0x2); - up_idtentry(ISR21, (uint64_t)vector_isr21, 0x08, 0x8e, 0x2); - up_idtentry(ISR22, (uint64_t)vector_isr22, 0x08, 0x8e, 0x2); - up_idtentry(ISR23, (uint64_t)vector_isr23, 0x08, 0x8e, 0x2); - up_idtentry(ISR24, (uint64_t)vector_isr24, 0x08, 0x8e, 0x2); - up_idtentry(ISR25, (uint64_t)vector_isr25, 0x08, 0x8e, 0x2); - up_idtentry(ISR26, (uint64_t)vector_isr26, 0x08, 0x8e, 0x2); - up_idtentry(ISR27, (uint64_t)vector_isr27, 0x08, 0x8e, 0x2); - up_idtentry(ISR28, (uint64_t)vector_isr28, 0x08, 0x8e, 0x2); - up_idtentry(ISR29, (uint64_t)vector_isr29, 0x08, 0x8e, 0x2); - up_idtentry(ISR30, (uint64_t)vector_isr30, 0x08, 0x8e, 0x2); - up_idtentry(ISR31, (uint64_t)vector_isr31, 0x08, 0x8e, 0x2); - - /* Set all IRQ vectors */ - + up_idtentry(ISR0, (uint64_t)vector_isr0 , sel, 0x8e, ist); + up_idtentry(ISR1, (uint64_t)vector_isr1 , sel, 0x8e, ist); + up_idtentry(ISR2, (uint64_t)vector_isr2 , sel, 0x8e, ist); + up_idtentry(ISR3, (uint64_t)vector_isr3 , sel, 0x8e, ist); + up_idtentry(ISR4, (uint64_t)vector_isr4 , sel, 0x8e, ist); + up_idtentry(ISR5, (uint64_t)vector_isr5 , sel, 0x8e, ist); + up_idtentry(ISR6, (uint64_t)vector_isr6 , sel, 0x8e, ist); + up_idtentry(ISR7, (uint64_t)vector_isr7 , sel, 0x8e, ist); + up_idtentry(ISR8, (uint64_t)vector_isr8 , sel, 0x8e, ist); + up_idtentry(ISR9, (uint64_t)vector_isr9 , sel, 0x8e, ist); + up_idtentry(ISR10, (uint64_t)vector_isr10, sel, 0x8e, ist); + up_idtentry(ISR11, (uint64_t)vector_isr11, sel, 0x8e, ist); + up_idtentry(ISR12, (uint64_t)vector_isr12, sel, 0x8e, ist); + up_idtentry(ISR13, (uint64_t)vector_isr13, sel, 0x8e, ist); + up_idtentry(ISR14, (uint64_t)vector_isr14, sel, 0x8e, ist); + up_idtentry(ISR15, (uint64_t)vector_isr15, sel, 0x8e, ist); + up_idtentry(ISR16, (uint64_t)vector_isr16, sel, 0x8e, ist); + up_idtentry(ISR17, (uint64_t)vector_isr17, sel, 0x8e, ist); + up_idtentry(ISR18, (uint64_t)vector_isr18, sel, 0x8e, ist); + up_idtentry(ISR19, (uint64_t)vector_isr19, sel, 0x8e, ist); + up_idtentry(ISR20, (uint64_t)vector_isr20, sel, 0x8e, ist); + up_idtentry(ISR21, (uint64_t)vector_isr21, sel, 0x8e, ist); + up_idtentry(ISR22, (uint64_t)vector_isr22, sel, 0x8e, ist); + up_idtentry(ISR23, (uint64_t)vector_isr23, sel, 0x8e, ist); + up_idtentry(ISR24, (uint64_t)vector_isr24, sel, 0x8e, ist); + up_idtentry(ISR25, (uint64_t)vector_isr25, sel, 0x8e, ist); + up_idtentry(ISR26, (uint64_t)vector_isr26, sel, 0x8e, ist); + up_idtentry(ISR27, (uint64_t)vector_isr27, sel, 0x8e, ist); + up_idtentry(ISR28, (uint64_t)vector_isr28, sel, 0x8e, ist); + up_idtentry(ISR29, (uint64_t)vector_isr29, sel, 0x8e, ist); + up_idtentry(ISR30, (uint64_t)vector_isr30, sel, 0x8e, ist); + up_idtentry(ISR31, (uint64_t)vector_isr31, sel, 0x8e, ist); + + /* Set all IRQ vectors and use separate stack from ISR */ + + ist = X86_GDT_IST_IRQ; offset = (uint64_t)vector_irq1 - (uint64_t)vector_irq0; for (irq = IRQ0, vector = (uint64_t)vector_irq0; irq <= IRQ255; irq += 1, vector += offset) { - up_idtentry(irq, (uint64_t)vector, 0x08, 0x8e, 0x1); + up_idtentry(irq, (uint64_t)vector, sel, 0x8e, ist); } /* Then program the IDT */ diff --git a/arch/x86_64/src/intel64/intel64_saveusercontext.S b/arch/x86_64/src/intel64/intel64_saveusercontext.S index dd3c87ce6e0fc..e0bd64eea445c 100644 --- a/arch/x86_64/src/intel64/intel64_saveusercontext.S +++ b/arch/x86_64/src/intel64/intel64_saveusercontext.S @@ -103,6 +103,15 @@ up_saveusercontext: movq %rbp, (8*REG_RBP)(%rdi) +#ifdef CONFIG_LIB_SYSCALL + /* Save CS and SS if we support syscalls */ + xor %rax, %rax + mov %cs, %ax + movq %rax, (8*REG_CS)(%rdi) + mov %ss, %ax + movq %rax, (8*REG_SS)(%rdi) +#endif + /* Save EAX=1. This will be the "apparent" return value from this * function when context is switch back to this thread. The non-zero * return value is the indication that we have been resumed. diff --git a/arch/x86_64/src/intel64/intel64_schedulesigaction.c b/arch/x86_64/src/intel64/intel64_schedulesigaction.c index c581165fc2c4a..0a9bd0f279c7c 100644 --- a/arch/x86_64/src/intel64/intel64_schedulesigaction.c +++ b/arch/x86_64/src/intel64/intel64_schedulesigaction.c @@ -126,6 +126,18 @@ void up_schedule_sigaction(struct tcb_s *tcb) up_current_regs()[REG_RIP] = (uint64_t)x86_64_sigdeliver; up_current_regs()[REG_RSP] = up_current_regs()[REG_RSP] - 8; up_current_regs()[REG_RFLAGS] = 0; + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Update segments to kernel segments */ + + up_current_regs()[REG_SS] = tcb->xcp.regs[REG_SS]; + up_current_regs()[REG_CS] = tcb->xcp.regs[REG_CS]; + up_current_regs()[REG_DS] = tcb->xcp.regs[REG_DS]; + + /* Update RSP to kernel stack */ + + up_current_regs()[REG_RSP] = (uint64_t)x86_64_get_ktopstk(); +#endif } } @@ -216,6 +228,18 @@ void up_schedule_sigaction(struct tcb_s *tcb) up_current_regs()[REG_RSP] = up_current_regs()[REG_RSP] - 8; up_current_regs()[REG_RFLAGS] = 0; +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Update segments to kernel segments */ + + up_current_regs()[REG_SS] = tcb->xcp.regs[REG_SS]; + up_current_regs()[REG_CS] = tcb->xcp.regs[REG_CS]; + up_current_regs()[REG_DS] = tcb->xcp.regs[REG_DS]; + + /* Update RSP to kernel stack */ + + up_current_regs()[REG_RSP] = + (uint64_t)x86_64_get_ktopstk(); +#endif /* Mark that full context switch is necessary when we * return from interrupt handler. * In that case RIP, RSP and RFLAGS are changed, but diff --git a/arch/x86_64/src/intel64/intel64_start.c b/arch/x86_64/src/intel64/intel64_start.c index a7e9eea9a636e..47fae8f135707 100644 --- a/arch/x86_64/src/intel64/intel64_start.c +++ b/arch/x86_64/src/intel64/intel64_start.c @@ -190,10 +190,6 @@ void __nxstart(void) x86_64_timer_calibrate_freq(); -#ifdef CONFIG_LIB_SYSCALL - enable_syscall(); -#endif - /* Store CPU IDs */ x86_64_cpu_priv_set(0); diff --git a/arch/x86_64/src/intel64/intel64_vectors.S b/arch/x86_64/src/intel64/intel64_vectors.S index 5317374572689..dbd95432b20e3 100644 --- a/arch/x86_64/src/intel64/intel64_vectors.S +++ b/arch/x86_64/src/intel64/intel64_vectors.S @@ -923,7 +923,7 @@ irq_common: add $8, %rsp - iretq /* Pops 5 things at once: CS, RIP, RFLAGS and SS and RSP */ + iretq /* Pops 5 things at once: RIP, CS, RFLAGS RSP and SS */ .size irq_common, . - irq_common .end diff --git a/boards/x86_64/intel64/qemu-intel64/configs/knsh_romfs/defconfig b/boards/x86_64/intel64/qemu-intel64/configs/knsh_romfs/defconfig new file mode 100644 index 0000000000000..9da96b7c65c10 --- /dev/null +++ b/boards/x86_64/intel64/qemu-intel64/configs/knsh_romfs/defconfig @@ -0,0 +1,91 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_X86_64_ACPI_DUMP is not set +# CONFIG_DEV_RANDOM is not set +# CONFIG_SIG_SIGKILL_ACTION is not set +# CONFIG_SIG_SIGSTOP_ACTION is not set +# CONFIG_TLS_ALIGNED is not set +CONFIG_16550_ADDRWIDTH=16 +CONFIG_16550_UART0=y +CONFIG_16550_UART0_BASE=0x3f8 +CONFIG_16550_UART0_CLOCK=1843200 +CONFIG_16550_UART0_IRQ=36 +CONFIG_16550_UART0_RXBUFSIZE=16 +CONFIG_16550_UART0_SERIAL_CONSOLE=y +CONFIG_16550_UART0_TXBUFSIZE=16 +CONFIG_16550_UART=y +CONFIG_ARCH="x86_64" +CONFIG_ARCH_ADDRENV=y +CONFIG_ARCH_BOARD="qemu-intel64" +CONFIG_ARCH_BOARD_INTEL64_QEMU=y +CONFIG_ARCH_CHIP="intel64" +CONFIG_ARCH_CHIP_INTEL64_QEMU=y +CONFIG_ARCH_DATA_VBASE=0x800080000 +CONFIG_ARCH_HEAP_VBASE=0x8000f0000 +CONFIG_ARCH_INTEL64_CORE_FREQ_KHZ=2600000 +CONFIG_ARCH_KERNEL_STACKSIZE=8192 +CONFIG_ARCH_PGPOOL_MAPPING=y +CONFIG_ARCH_PGPOOL_PBASE=0x00c000000 +CONFIG_ARCH_PGPOOL_SIZE=67108864 +CONFIG_ARCH_PGPOOL_VBASE=0x10c000000 +CONFIG_ARCH_SIZET_LONG=y +CONFIG_ARCH_TEXT_VBASE=0x800000000 +CONFIG_ARCH_X86_64=y +CONFIG_BOARDCTL_APP_SYMTAB=y +CONFIG_BOARDCTL_ROMDISK=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=4687108 +CONFIG_BOOT_RUNFROMEXTSRAM=y +CONFIG_BUILD_KERNEL=y +CONFIG_CONSOLE_SYSLOG=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_ASSERTIONS_EXPRESSION=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEFAULT_TASK_STACKSIZE=16384 +CONFIG_ELF=y +CONFIG_ELF_STACKSIZE=163840 +CONFIG_EXAMPLES_HELLO=m +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_IDLETHREAD_STACKSIZE=16384 +CONFIG_INIT_FILEPATH="/system/bin/init" +CONFIG_INIT_MOUNT=y +CONFIG_INIT_MOUNT_FLAGS=0x1 +CONFIG_INIT_MOUNT_TARGET="/system/bin" +CONFIG_LIBC_EXECFUNCS=y +CONFIG_LIBM=y +CONFIG_MM_KERNEL_HEAPSIZE=16384 +CONFIG_MM_PGALLOC=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_DISABLE_IFCONFIG=y +CONFIG_NSH_DISABLE_IFUPDOWN=y +CONFIG_NSH_FILE_APPS=y +CONFIG_PREALLOC_CHILDSTATUS=16 +CONFIG_PTHREAD_MUTEX_TYPES=y +CONFIG_PTHREAD_STACK_MIN=16384 +CONFIG_RAM_SIZE=268435456 +CONFIG_RAM_VSTART=0x100000000 +CONFIG_SCHED_CHILD_STATUS=y +CONFIG_SCHED_HAVE_PARENT=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_TICKLESS=y +CONFIG_SCHED_TICKLESS_ALARM=y +CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP=y +CONFIG_SCHED_WAITPID=y +CONFIG_SIG_DEFAULT=y +CONFIG_START_DAY=3 +CONFIG_START_MONTH=3 +CONFIG_START_YEAR=2011 +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_NSH_PROGNAME="init" +CONFIG_SYSTEM_TIME64=y +CONFIG_TESTING_OSTEST=y +CONFIG_TESTING_OSTEST_FPUTESTDISABLE=y +CONFIG_TESTING_OSTEST_STACKSIZE=16384 +CONFIG_USEC_PER_TICK=1 diff --git a/boards/x86_64/intel64/qemu-intel64/configs/knsh_romfs_pci/defconfig b/boards/x86_64/intel64/qemu-intel64/configs/knsh_romfs_pci/defconfig new file mode 100644 index 0000000000000..83599c33fc667 --- /dev/null +++ b/boards/x86_64/intel64/qemu-intel64/configs/knsh_romfs_pci/defconfig @@ -0,0 +1,95 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_PVHBOOT is not set +# CONFIG_ARCH_X86_64_ACPI_DUMP is not set +# CONFIG_DEV_RANDOM is not set +# CONFIG_SIG_SIGKILL_ACTION is not set +# CONFIG_SIG_SIGSTOP_ACTION is not set +# CONFIG_TLS_ALIGNED is not set +CONFIG_16550_ADDRWIDTH=16 +CONFIG_16550_PCI_UART0=y +CONFIG_16550_PCI_UART0_CLOCK=1843200 +CONFIG_16550_PCI_UART0_DEVICE=0x9100 +CONFIG_16550_PCI_UART0_SERIAL_CONSOLE=y +CONFIG_16550_PCI_UART0_VENDOR=0x125b +CONFIG_16550_PCI_UART=y +CONFIG_ARCH="x86_64" +CONFIG_ARCH_ADDRENV=y +CONFIG_ARCH_BOARD="qemu-intel64" +CONFIG_ARCH_BOARD_INTEL64_QEMU=y +CONFIG_ARCH_CHIP="intel64" +CONFIG_ARCH_CHIP_INTEL64_QEMU=y +CONFIG_ARCH_DATA_VBASE=0x800080000 +CONFIG_ARCH_HEAP_VBASE=0x8000f0000 +CONFIG_ARCH_INTEL64_CORE_FREQ_KHZ=0 +CONFIG_ARCH_KERNEL_STACKSIZE=8192 +CONFIG_ARCH_PGPOOL_MAPPING=y +CONFIG_ARCH_PGPOOL_PBASE=0x00c000000 +CONFIG_ARCH_PGPOOL_SIZE=67108864 +CONFIG_ARCH_PGPOOL_VBASE=0x10c000000 +CONFIG_ARCH_SIZET_LONG=y +CONFIG_ARCH_TEXT_VBASE=0x800000000 +CONFIG_ARCH_X86_64=y +CONFIG_BOARDCTL_APP_SYMTAB=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARDCTL_ROMDISK=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=999 +CONFIG_BOOT_RUNFROMEXTSRAM=y +CONFIG_BUILD_KERNEL=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_ASSERTIONS_EXPRESSION=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEFAULT_TASK_STACKSIZE=16384 +CONFIG_DEV_SIMPLE_ADDRENV=y +CONFIG_ELF=y +CONFIG_ELF_STACKSIZE=163840 +CONFIG_EXAMPLES_HELLO=m +CONFIG_EXPERIMENTAL=y +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_IDLETHREAD_STACKSIZE=16384 +CONFIG_INIT_FILEPATH="/system/bin/init" +CONFIG_INIT_MOUNT=y +CONFIG_INIT_MOUNT_FLAGS=0x1 +CONFIG_INIT_MOUNT_TARGET="/system/bin" +CONFIG_LIBC_EXECFUNCS=y +CONFIG_LIBM=y +CONFIG_MM_KERNEL_HEAPSIZE=16384 +CONFIG_MM_PGALLOC=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_DISABLE_IFCONFIG=y +CONFIG_NSH_DISABLE_IFUPDOWN=y +CONFIG_NSH_FILE_APPS=y +CONFIG_PCI=y +CONFIG_PCI_MSIX=y +CONFIG_PREALLOC_CHILDSTATUS=16 +CONFIG_PTHREAD_MUTEX_TYPES=y +CONFIG_PTHREAD_STACK_MIN=16384 +CONFIG_RAM_SIZE=268435456 +CONFIG_RAM_VSTART=0x100000000 +CONFIG_SCHED_CHILD_STATUS=y +CONFIG_SCHED_HAVE_PARENT=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_TICKLESS=y +CONFIG_SCHED_TICKLESS_ALARM=y +CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP=y +CONFIG_SCHED_WAITPID=y +CONFIG_SIG_DEFAULT=y +CONFIG_START_DAY=3 +CONFIG_START_MONTH=3 +CONFIG_START_YEAR=2011 +CONFIG_SYSLOG_DEVPATH="/dev/S1" +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_NSH_PROGNAME="init" +CONFIG_SYSTEM_TIME64=y +CONFIG_TESTING_OSTEST=y +CONFIG_TESTING_OSTEST_FPUTESTDISABLE=y +CONFIG_TESTING_OSTEST_STACKSIZE=16384 diff --git a/boards/x86_64/intel64/qemu-intel64/scripts/Make.defs b/boards/x86_64/intel64/qemu-intel64/scripts/Make.defs index 2b2d675e37a98..ed40ccf54688d 100644 --- a/boards/x86_64/intel64/qemu-intel64/scripts/Make.defs +++ b/boards/x86_64/intel64/qemu-intel64/scripts/Make.defs @@ -24,4 +24,8 @@ include $(TOPDIR)/.config include $(TOPDIR)/tools/Config.mk include $(TOPDIR)/arch/x86_64/src/intel64/Toolchain.defs -ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)qemu.ld \ No newline at end of file +ifeq ($(CONFIG_BUILD_KERNEL),y) +ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)qemu-kernel.ld +else +ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)qemu.ld +endif diff --git a/boards/x86_64/intel64/qemu-intel64/scripts/qemu-kernel.ld b/boards/x86_64/intel64/qemu-intel64/scripts/qemu-kernel.ld new file mode 100644 index 0000000000000..341bc0c44e559 --- /dev/null +++ b/boards/x86_64/intel64/qemu-intel64/scripts/qemu-kernel.ld @@ -0,0 +1,130 @@ +/**************************************************************************** + * boards/x86_64/intel64/qemu-intel64/scripts/qemu-kernel.ld + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +OUTPUT_ARCH(i386:x86-64) +ENTRY(__pmode_entry) +SECTIONS +{ + + . = 0x0; + + .realmode : { + . = ALIGN(8); + KEEP(*(.multiboot)) + *(.realmode) + } + + . = 0x1M; + _kernel_physical_start = .; + + .loader.text : { + . = ALIGN(8); + *(.loader.text) + } + + .loader.rodata : { + *(.loader.rodata) + } + + .loader.data : { + *(.loader.data) + } + + .loader.bss : { + *(.loader.bss) + } + + . = ALIGN(0x1000); + _boot_end = .; + + . += 0x100000000; + _kernel_virtual_start = .; + + .text : AT(_boot_end) + { + _stext = ABSOLUTE(.); + . = ALIGN(8); + KEEP(*(.multiboot)) + *(.text .text.*) + *(.gnu.linkonce.t.*) + _etext = ABSOLUTE(.); + } + + .rodata ALIGN(0x1000) : + { + _srodata = ABSOLUTE(.); + *(.rodata .rodata.*) + *(.fixup) + *(.gnu.warning) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + *(.eh_frame) + *(.note.gnu.*) + _erodata = ABSOLUTE(.); + } + + .data ALIGN(0x1000) : + { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } + + .pgheap ALIGN(0x1000) : + { + __pgheap_start = ABSOLUTE(.); + . = ALIGN(0x1000); + __pgheap_size = ABSOLUTE(.); + } + + .bss ALIGN(0x1000) : + { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(16); + _ebss = ABSOLUTE(.); + } + + _kernel_virtual_end = .; + + _kernel_physical_end = (LOADADDR (.bss) + SIZEOF (.bss) + 0xFFF) & 0xFFFFFFFFFFFFF000; + + /* Stabs debugging sections */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/x86_64/intel64/qemu-intel64/src/Makefile b/boards/x86_64/intel64/qemu-intel64/src/Makefile index ca8ec7e0a9a16..4ff5d9fa9984b 100644 --- a/boards/x86_64/intel64/qemu-intel64/src/Makefile +++ b/boards/x86_64/intel64/qemu-intel64/src/Makefile @@ -23,6 +23,7 @@ include $(TOPDIR)/Make.defs CSRCS = qemu_boot.c qemu_bringup.c qemu_net.c +CSRCS += $(if $(wildcard romfs_boot.c), romfs_boot.c, romfs_stub.c) ifeq ($(CONFIG_BOARDCTL),y) CSRCS += qemu_appinit.c diff --git a/boards/x86_64/intel64/qemu-intel64/src/qemu_appinit.c b/boards/x86_64/intel64/qemu-intel64/src/qemu_appinit.c index 571ab8ee404f2..79bd770617026 100644 --- a/boards/x86_64/intel64/qemu-intel64/src/qemu_appinit.c +++ b/boards/x86_64/intel64/qemu-intel64/src/qemu_appinit.c @@ -27,8 +27,28 @@ #include #include +#include + +#include + #include "x86_64_internal.h" #include "qemu_intel64.h" +#include "romfs.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Additional checks for kernel build */ + +#ifdef CONFIG_BUILD_KERNEL +# ifndef CONFIG_BOARD_LATE_INITIALIZE +# error KERNEL build require CONFIG_BOARD_LATE_INITIALIZE +# endif +#endif + +#define SECTORSIZE 512 +#define NSECTORS(b) (((b) + SECTORSIZE - 1) / SECTORSIZE) /**************************************************************************** * Public Functions @@ -71,3 +91,49 @@ int board_app_initialize(uintptr_t arg) return qemu_bringup(); #endif } + +/**************************************************************************** + * Name: board_late_initialize + * + * Description: + * If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional + * initialization call will be performed in the boot-up sequence to a + * function called board_late_initialize(). board_late_initialize() will + * be called after up_initialize() and board_early_initialize() and just + * before the initial application is started. This additional + * initialization phase may be used, for example, to initialize board- + * specific device drivers for which board_early_initialize() is not + * suitable. + * + * Waiting for events, use of I2C, SPI, etc are permissible in the context + * of board_late_initialize(). That is because board_late_initialize() + * will run on a temporary, internal kernel thread. + * + ****************************************************************************/ + +void board_late_initialize(void) +{ + int ret = OK; + + UNUSED(ret); + + /* Perform board-specific initialization */ + + ret = qemu_bringup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: qemu_bringup() failed: %d\n", ret); + } + + /* Create ROM disk for mount in nx_start_application */ + + if (NSECTORS(romfs_img_len) > 1) + { + ret = romdisk_register(0, romfs_img, NSECTORS(romfs_img_len), + SECTORSIZE); + if (ret < 0) + { + ferr("ERROR: Failed to register romfs: %d\n", -ret); + } + } +} diff --git a/boards/x86_64/intel64/qemu-intel64/src/romfs.h b/boards/x86_64/intel64/qemu-intel64/src/romfs.h new file mode 100644 index 0000000000000..c28c24d66ecd9 --- /dev/null +++ b/boards/x86_64/intel64/qemu-intel64/src/romfs.h @@ -0,0 +1,39 @@ +/**************************************************************************** + * boards/x86_64/intel64/qemu-intel64/src/romfs.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_X86_64_INTEL64_QEMU_INTEL64_SRC_ROMFS_H +#define __BOARDS_X86_64_INTEL64_QEMU_INTEL64_SRC_ROMFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +extern const unsigned char romfs_img[]; +extern const unsigned int romfs_img_len; + +#endif /* __BOARDS_X86_64_INTEL64_QEMU_INTEL64_SRC_ROMFS_H */ diff --git a/boards/x86_64/intel64/qemu-intel64/src/romfs_stub.c b/boards/x86_64/intel64/qemu-intel64/src/romfs_stub.c new file mode 100644 index 0000000000000..0cbe428a40ea6 --- /dev/null +++ b/boards/x86_64/intel64/qemu-intel64/src/romfs_stub.c @@ -0,0 +1,39 @@ +/**************************************************************************** + * boards/x86_64/intel64/qemu-intel64/src/romfs_stub.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +weak_data const unsigned char aligned_data(4) romfs_img[] = +{ + 0x00 +}; +weak_data const unsigned int romfs_img_len = 1; + +/**************************************************************************** + * Public Functions + ****************************************************************************/