diff --git a/kernel/Makefile b/kernel/Makefile index 9f54a192..62dde62c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -87,6 +87,7 @@ objdump := $(prefix)-objdump objcopy := $(prefix)-objcopy cc := $(prefix)-gcc as := $(prefix)-as +gdb := $(prefix)-gdb .PHONY: all clean run build asm doc justrun kernel @@ -103,8 +104,10 @@ run: build justrun justrun: @qemu-system-$(arch) $(qemu_opts) || [ $$? -eq 11 ] # run qemu and assert it exit 11 -debug: $(bin) +debug: $(kernel) $(bin) @qemu-system-$(arch) $(qemu_opts) -s -S & + @sleep 1 + @$(gdb) $(kernel) -x ../tools/gdbinit ifeq ($(arch), x86_64) build: kernel @@ -136,7 +139,7 @@ else cp bbl ../../kernel/$@ endif else ifeq ($(arch), aarch64) - $(objcopy) $(kernel) -O binary $@ + $(objcopy) $(kernel) --strip-all -O binary $@ endif kernel: diff --git a/kernel/aarch64-blog_os.json b/kernel/aarch64-blog_os.json index 048db110..8c9ab023 100644 --- a/kernel/aarch64-blog_os.json +++ b/kernel/aarch64-blog_os.json @@ -13,6 +13,11 @@ "linker": "aarch64-none-elf-ld", "linker-flavor": "ld", "linker-is-gnu": true, + "pre-link-args": { + "ld": [ + "-Tsrc/arch/aarch64/boot/linker.ld" + ] + }, "llvm-target": "aarch64-unknown-none", "no-compiler-rt": true, "features": "+a53,+strict-align", @@ -20,6 +25,7 @@ "os": "none", "panic": "abort", "panic-strategy": "abort", + "relocation-model": "static", "position-independent-executables": true, "target-c-int-width": "32", "target-endian": "little", diff --git a/kernel/src/arch/aarch64/boot/boot.S b/kernel/src/arch/aarch64/boot/boot.S new file mode 100644 index 00000000..ab0601cc --- /dev/null +++ b/kernel/src/arch/aarch64/boot/boot.S @@ -0,0 +1,99 @@ +# TODO rewrite in Rust, use crate cortex-a + +.section .text.boot + +.global _start +_start: + # read cpu affinity, start core 0, halt rest + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, setup + +halt: + # core affinity != 0, halt it + wfe + b halt + +setup: + # store the desired EL1 stack pointer in x1 + adr x1, _start + + # read the current exception level into x0 (ref: C5.2.1) + mrs x0, CurrentEL + and x0, x0, #0b1100 + lsr x0, x0, #2 + +switch_to_el2: + # switch to EL2 if we're in EL3. otherwise switch to EL1 + cmp x0, #2 + beq switch_to_el1 + + # set-up SCR_EL3 (bits 0, 4, 5, 7, 8, 10) (A53: 4.3.42) + mov x0, #0x5b1 + msr scr_el3, x0 + + # set-up SPSR_EL3 (bits 0, 3, 6, 7, 8, 9) (ref: C5.2.20) + mov x0, #0x3c9 + msr spsr_el3, x0 + + # switch + adr x0, switch_to_el1 + msr elr_el3, x0 + + eret + +switch_to_el1: + # switch to EL1 if we're not already in EL1. otherwise continue with start + cmp x0, #1 + beq set_stack + + # set the stack-pointer for EL1 + msr sp_el1, x1 + + # set-up HCR_EL2, enable AArch64 in EL1 (bits 1, 31) (ref: D10.2.45) + mov x0, #0x0002 + movk x0, #0x8000, lsl #16 + msr hcr_el2, x0 + + # Set SCTLR to known state (RES1: 11, 20, 22, 23, 28, 29) (ref: D10.2.100) + mov x0, #0x0800 + movk x0, #0x30d0, lsl #16 + msr sctlr_el1, x0 + + # set-up SPSR_EL2 (bits 0, 2, 6, 7, 8, 9) (ref: C5.2.19) + mov x0, #0x3c5 + msr spsr_el2, x0 + + # enable CNTP for EL1/EL0 (ref: D7.5.2, D7.5.13) + # NOTE: This doesn't actually enable the counter stream. + mrs x0, cnthctl_el2 + orr x0, x0, #3 + msr cnthctl_el2, x0 + msr cntvoff_el2, xzr + + # switch + adr x0, set_stack + msr elr_el2, x0 + + eret + +set_stack: + # set the current stack pointer + mov sp, x1 + +zero_bss: + # load the start address and number of bytes in BSS section + ldr x1, =__bss_start + ldr x2, =__bss_length + +zero_bss_loop: + # zero out the BSS section, 64-bits at a time + cbz x2, go_kmain + str xzr, [x1], #8 + sub x2, x2, #8 + cbnz x2, zero_bss_loop + +go_kmain: + # jump to rust_main, which shouldn't return. halt if it does + bl rust_main + b halt diff --git a/kernel/src/arch/aarch64/boot/linker.ld b/kernel/src/arch/aarch64/boot/linker.ld new file mode 100644 index 00000000..ce4c0c2a --- /dev/null +++ b/kernel/src/arch/aarch64/boot/linker.ld @@ -0,0 +1,39 @@ +ENTRY(_start) + +SECTIONS { + . = 0x80000; /* Raspbery Pi 3 Aarch64 (kernel8.img) load address */ + + /* start of the binary */ + _start = .; + + .text : { + KEEP(*(.text.boot)) /* from boot.S */ + *(.text .text.* .gnu.linkonce.t*) + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r*) + } + + .data : { + *(.data .data.* .gnu.linkonce.d*) + } + + .bss (NOLOAD) : { + . = ALIGN(32); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + . = ALIGN(8); + __bss_end = .; + } + + /* end of the binary */ + _end = ALIGN(8); + + /* number of bytes in BSS section and complete binary */ + __bss_length = (__bss_end - __bss_start); + __binary_length = (_end - _start); + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index c19cd975..137941c8 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -29,6 +29,4 @@ pub extern fn rust_main() -> ! { ::kmain(); } -// global_asm!(include_str!("boot/boot.asm")); -// global_asm!(include_str!("boot/entry.asm")); -// global_asm!(include_str!("boot/trap.asm")); +global_asm!(include_str!("boot/boot.S")); diff --git a/tools/gdbinit b/tools/gdbinit new file mode 100644 index 00000000..5041b6e7 --- /dev/null +++ b/tools/gdbinit @@ -0,0 +1,3 @@ +target remote :1234 +break rust_main +continue