arch/x86: initial Intel64 bootstrap framework

This patch adds basic build infrastructure, definitions, a linker
script, etc. to use the Zephyr and 0.10.1 SDK to build a 64-bit
ELF binary suitable for use with GRUB to minimally bootstrap an
Apollo Lake (e.g., UpSquared) board. The resulting binary can hardly
be called a Zephyr kernel as it is lacking most of the glue logic,
but it is a starting point to flesh those out in the x86 tree.

The "kernel" builds with a few harmless warnings, both with GCC from
the Zephyr SDK and with ICC (which is currently being worked on in
a separate branch). These warnings are either related to pointer size
differences (since this is an LP64 build) and/or dummy functions
that will be replaced with working versions shortly.

Signed-off-by: Charles E. Youse <charles.youse@intel.com>
This commit is contained in:
Charles E. Youse 2019-07-04 13:49:06 -07:00 committed by Andrew Boie
commit 34307a54f0
10 changed files with 291 additions and 1 deletions

View file

@ -1,3 +1,14 @@
# Copyright (c) 2019 Intel Corp. # Copyright (c) 2019 Intel Corp.
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
#
# XXX: When using the Intel toolchain, cmake doesn't recognize .S files
# automatically, and I can't be bothered to figure out how to fix this.
#
set_property(SOURCE intel64/locore.S PROPERTY LANGUAGE ASM)
zephyr_library_sources(
intel64/locore.S
intel64/thread.c
)

View file

@ -0,0 +1,156 @@
/*
* Copyright (c) 2019 Intel Corporation
* SPDX-License-Identifier: Apache-2.0
*/
#include <arch/x86/multiboot.h>
#include <sys/util.h>
#include <arch/x86/msr.h>
#include <kernel_arch_data.h>
#define NR_IDT_VECTOR 256 /* full IDT, we're not short of RAM */
#define IRQ_STACK_SIZE 4096 /* must be a multiple of 16 */
.section .locore,"ax"
.code32
.globl __start
__start:
/*
* multiboot starts us here in 32-bit flat mode with interrupts
* and paging disabled. first, switch to our own GDT and stack.
*/
lgdt gdt48
lidt idt48
jmpl $X86_KERNEL_CS_32, $1f
1: movw $X86_KERNEL_DS_32, %ax
movw %ax, %ds
movw %ax, %ss
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movl $(irq_stack + IRQ_STACK_SIZE), %esp
/*
* transition to long mode, by the book.
*/
movl %cr4, %eax /* enable PAE */
orl $CR4_PAE, %eax
movl %eax, %cr4
movl $pml4, %eax /* load page base */
movl %eax, %cr3
movl $X86_EFER_MSR, %ecx /* enable long mode */
rdmsr
orl $X86_EFER_MSR_LME, %eax
wrmsr
movl %cr0, %eax /* enable paging */
orl $CR0_PG, %eax
movl %eax, %cr0
/*
* jump into long mode, reload the segment registers (again).
*/
jmpl $X86_KERNEL_CS_64, $1f
.code64
1: movl $X86_KERNEL_DS_64, %eax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw %ax, %fs
movw %ax, %gs
/*
* func() is just a placeholder C function. don't replace CALL
* with JMP; we must honor the ABI stack alignment requirements.
*/
call func
stop: jmp stop
/*
* The multiboot header is identical (for obvious reasons) to the 32-bit
* version in ia32/crt0.S. They should be refactored into a common file.
*/
#ifdef CONFIG_X86_MULTIBOOT
.align 4
.long X86_MULTIBOOT_HEADER_MAGIC
.long X86_MULTIBOOT_HEADER_FLAGS
.long -(X86_MULTIBOOT_HEADER_MAGIC + X86_MULTIBOOT_HEADER_FLAGS)
#ifdef CONFIG_X86_MULTIBOOT_FRAMEBUF
.fill 5,4,0 /* (unused exec layout) */
.long 0 /* linear graphics mode */
.long CONFIG_X86_MULTIBOOT_FRAMEBUF_X /* width */
.long CONFIG_X86_MULTIBOOT_FRAMEBUF_Y /* height */
.long 32 /* depth */
#endif /* CONFIG_X86_MULTIBOOT_FRAMEBUF */
#endif
/*
* GDT - a single GDT is shared by all threads (and, eventually, all CPUs).
* This layout must agree with the selectors in intel64/kernel_arch_data.h.
*/
.align 8
gdt:
.word 0, 0, 0, 0 /* 0x00: null descriptor */
.word 0xFFFF, 0, 0x9A00, 0x00CF /* 0x08: 32-bit kernel code */
.word 0xFFFF, 0, 0x9200, 0x00CF /* 0x10: 32-bit kernel data */
.word 0, 0, 0x9800, 0x0020 /* 0x18: 64-bit kernel code */
gdt48:
.word (gdt48 - gdt - 1)
.long gdt
/*
* IDT. Empty for now.
*/
.align 8
idt: .fill (NR_IDT_VECTOR*16), 1, 0
idt48:
.word (idt48 - idt - 1)
.long idt
/*
* Page tables. Long mode requires them, but we don't implement any memory
* protection yet, so these simply identity-map the first 4GB w/ 1GB pages.
*/
.align 4096
pml4:
.long pdp + 0x03 /* 0x03 = R/W, P */
.long 0
.fill 4088, 1, 0
pdp: .long 0x00000183 /* 0x183 = G, 1GB, R/W, P */
.long 0
.long 0x40000183
.long 0
.long 0x80000183
.long 0
.long 0xC0000183
.long 0
.fill 4064, 1, 0
/*
* For now, the "IRQ stack" is just used as a scratch stack during
* early kernel initialization.
*/
.align 16
irq_stack:
.fill IRQ_STACK_SIZE, 1, 0xFF

View file

@ -0,0 +1,10 @@
/*
* Copyright (c) 2019 Intel Corporation
* SPDX-License-Identifier: Apache-2.0
*/
void func(void)
{
for (;;) {
}
}

View file

@ -6,4 +6,13 @@
#ifndef ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_DATA_H_ #ifndef ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_DATA_H_
#define ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_DATA_H_ #define ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_DATA_H_
/*
* GDT selectors - these must agree with the GDT layout in locore.S.
*/
#define X86_KERNEL_CS_32 0x08 /* 32-bit kernel code */
#define X86_KERNEL_DS_32 0x10 /* 32-bit kernel data */
#define X86_KERNEL_CS_64 0x18 /* 64-bit kernel code */
#define X86_KERNEL_DS_64 0x00 /* 64-bit kernel data (null!) */
#endif /* ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_DATA_H_ */ #endif /* ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_DATA_H_ */

View file

@ -6,4 +6,21 @@
#ifndef ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_FUNC_H_ #ifndef ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_FUNC_H_
#define ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_FUNC_H_ #define ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_FUNC_H_
#ifndef _ASMLANGUAGE
#define z_is_in_isr() (0)
static ALWAYS_INLINE void
z_set_thread_return_value(struct k_thread *thread, unsigned int value)
{
/* nothing */ ;
}
static inline void kernel_arch_init(void)
{
/* nothing */ ;
}
#endif /* _ASMLANGUAGE */
#endif /* ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_FUNC_H_ */ #endif /* ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_FUNC_H_ */

View file

@ -6,4 +6,11 @@
#ifndef ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_THREAD_H_ #ifndef ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_THREAD_H_
#define ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_THREAD_H_ #define ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_THREAD_H_
#ifndef _ASMLANGUAGE
struct _callee_saved { };
struct _thread_arch { };
#endif /* _ASMLANGUAGE */
#endif /* ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_THREAD_H_ */ #endif /* ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_THREAD_H_ */

View file

@ -1,4 +1,6 @@
# Copyright (c) 2019 Intel Corp. # Copyright (c) 2019 Intel Corp.
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
message(FATAL_ERROR "nice try, no Intel64 support yet") zephyr_cc_option(-m64)
add_subdirectory(core)

View file

@ -3,7 +3,32 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
/*
* dummies for now
*/
#ifndef ZEPHYR_INCLUDE_ARCH_X86_INTEL64_ARCH_H_ #ifndef ZEPHYR_INCLUDE_ARCH_X86_INTEL64_ARCH_H_
#define ZEPHYR_INCLUDE_ARCH_X86_INTEL64_ARCH_H_ #define ZEPHYR_INCLUDE_ARCH_X86_INTEL64_ARCH_H_
#define Z_ARCH_THREAD_STACK_DEFINE(sym, size) \
struct _k_thread_stack_element sym[size]
#define Z_ARCH_THREAD_STACK_SIZEOF(sym) sizeof(sym)
#define Z_ARCH_THREAD_STACK_BUFFER(sym) ((char *) sym)
#define Z_IRQ_TO_INTERRUPT_VECTOR(irq) (0)
#define Z_ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p)
#define z_arch_irq_lock() (0)
#define z_arch_irq_unlock(k)
#define z_x86_msr_read(a) (0)
#define sys_read8(x) (0)
#define sys_read32(x) (0)
#define sys_in32(x) (0)
#define sys_write8(x,y)
#define sys_write32(x,y)
#define sys_out32(x, y)
#endif /* ZEPHYR_INCLUDE_ARCH_X86_INTEL64_ARCH_H_ */ #endif /* ZEPHYR_INCLUDE_ARCH_X86_INTEL64_ARCH_H_ */

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2019 Intel Corp.
* SPDX-License-Identifier: Apache-2.0
*/
ENTRY(CONFIG_KERNEL_ENTRY)
SECTIONS
{
/*
* The "locore" must be in the 64K of RAM, so that 16-bit code (with
* segment registers == 0x0000) and 32/64-bit code agree on addresses.
* ... there is no 16-bit code yet, but there will be when we add SMP.
*/
.locore 0x8000 : ALIGN(16)
{
*(.locore)
*(.locore.*)
}
/*
* The parts of the system that don't benefit from being in the locore
* start at the 1MB mark, otherwise the system size would be artificially
* clamped by the ISA memory hole/ROM space at 0x90000-0xFFFFF.
*/
.text 0x100000 : ALIGN(16)
{
*(.text)
*(.text.*)
*(.rodata.*)
}
/DISCARD/ :
{
*(.comment*)
*(.debug*)
*(.got*)
*(.igot.*)
*(.iplt)
*(.note.GNU-stack)
*(.rela.*)
}
}

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2011-2014, Wind River Systems, Inc. * Copyright (c) 2011-2014, Wind River Systems, Inc.
* Copyright (c) 2019 Intel Corp.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -7,6 +8,12 @@
#include <autoconf.h> #include <autoconf.h>
#include <generated_dts_board.h> #include <generated_dts_board.h>
#ifdef CONFIG_X86_LONGMODE
#include <arch/x86/intel64/linker.ld>
#else /* IA32 */
#define PHYS_LOAD_ADDR DT_PHYS_RAM_ADDR #define PHYS_LOAD_ADDR DT_PHYS_RAM_ADDR
#define PHYS_RAM_ADDR DT_PHYS_RAM_ADDR #define PHYS_RAM_ADDR DT_PHYS_RAM_ADDR
@ -25,3 +32,4 @@ MEMORY
#include <arch/x86/ia32/linker.ld> #include <arch/x86/ia32/linker.ld>
#endif /* CONFIG_X86_LONGMODE */