From e21d7fdd5950dd1a286ebab890d1d163a5bd576b Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 1 Oct 2021 18:37:47 +0300 Subject: [PATCH] feat?: it boots on orange pi 3 --- Makefile | 11 ++++ etc/aarch64-orangepi3.json | 17 +++++ etc/aarch64-orangepi3.ld | 35 +++++++++++ kernel/Cargo.toml | 2 +- kernel/src/arch/aarch64/boot/entry.S | 2 + kernel/src/arch/aarch64/boot/mod.rs | 62 ++++++++++++++----- kernel/src/arch/aarch64/boot/uboot.S | 46 ++++++++++++++ kernel/src/arch/aarch64/mach_orangepi3/mod.rs | 62 +++++++++++++++++++ kernel/src/arch/aarch64/mod.rs | 4 ++ 9 files changed, 226 insertions(+), 15 deletions(-) create mode 100644 etc/aarch64-orangepi3.json create mode 100644 etc/aarch64-orangepi3.ld create mode 100644 kernel/src/arch/aarch64/boot/uboot.S create mode 100644 kernel/src/arch/aarch64/mach_orangepi3/mod.rs diff --git a/Makefile b/Makefile index 04981c4..b551da6 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ GDB?=gdb-multiarch LLVM_BASE=$(shell llvm-config --bindir) OBJCOPY=$(LLVM_BASE)/llvm-objcopy +MKIMAGE?=mkimage PROFILE?=debug O=target/$(ARCH)-$(MACH)/$(PROFILE) @@ -30,6 +31,12 @@ QEMU_OPTS+=-kernel $(O)/kernel.bin \ -m 512 \ -serial chardev:serial0 endif +ifeq ($(MACH),rpi3b) +QEMU_OPTS+=-kernel $(O)/kernel.bin \ + -M raspi3b \ + -serial null \ + -serial chardev:serial0 +endif endif .PHONY: address error etc kernel src @@ -41,6 +48,10 @@ kernel: ifeq ($(ARCH),aarch64) $(OBJCOPY) -O binary $(O)/kernel $(O)/kernel.bin endif +ifeq ($(MACH),orangepi3) + $(LLVM_BASE)/llvm-strip $(O)/kernel + $(LLVM_BASE)/llvm-size $(O)/kernel +endif clean: cargo clean diff --git a/etc/aarch64-orangepi3.json b/etc/aarch64-orangepi3.json new file mode 100644 index 0000000..e5b4900 --- /dev/null +++ b/etc/aarch64-orangepi3.json @@ -0,0 +1,17 @@ +{ + "arch": "aarch64", + "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + "disable-redzone": true, + "executables": true, + "features": "+strict-align,+neon,+fp-armv8", + "linker": "rust-lld", + "linker-flavor": "ld.lld", + "llvm-target": "aarch64-unknown-none", + "max-atomic-width": 128, + "panic-strategy": "abort", + "relocation-model": "static", + "target-pointer-width": "64", + "pre-link-args": { + "ld.lld": [ "-Tetc/aarch64-orangepi3.ld" ] + } +} diff --git a/etc/aarch64-orangepi3.ld b/etc/aarch64-orangepi3.ld new file mode 100644 index 0000000..f9cf1a4 --- /dev/null +++ b/etc/aarch64-orangepi3.ld @@ -0,0 +1,35 @@ +ENTRY(_entry); + +MEMORY { + ram : ORIGIN = 0x48000000, LENGTH = 992M +} + +SECTIONS { + PROVIDE(__kernel_start = .); + + .text : { + *(.text._entry) + *(.text*) + } >ram + + . = ALIGN(4K); + .rodata : { + *(.rodata*) + } >ram + + . = ALIGN(4K); + .data : { + *(.data*) + } >ram + + . = ALIGN(4K); + .bss : { + PROVIDE(__bss_start = .); + *(COMMON) + *(.bss*) + . = ALIGN(4K); + PROVIDE(__bss_end = .); + } >ram + + PROVIDE(__kernel_end = .); +} diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 0e0091e..b5c40a3 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -20,4 +20,4 @@ cortex-a = { version = "6.x.x" } [features] mach_qemu = [] -default = ["mach_qemu"] +mach_orangepi3 = [] diff --git a/kernel/src/arch/aarch64/boot/entry.S b/kernel/src/arch/aarch64/boot/entry.S index c2ba320..2aaf351 100644 --- a/kernel/src/arch/aarch64/boot/entry.S +++ b/kernel/src/arch/aarch64/boot/entry.S @@ -1,3 +1,5 @@ +// vi:ft=a64asm.asm: + .macro ADR_REL reg, sym adrp \reg, \sym add \reg, \reg, #:lo12:\sym diff --git a/kernel/src/arch/aarch64/boot/mod.rs b/kernel/src/arch/aarch64/boot/mod.rs index d071a8d..db46a27 100644 --- a/kernel/src/arch/aarch64/boot/mod.rs +++ b/kernel/src/arch/aarch64/boot/mod.rs @@ -1,37 +1,71 @@ //! aarch64 common boot logic -use crate::arch::aarch64::asm::CPACR_EL1; -use cortex_a::registers::VBAR_EL1; -use tock_registers::interfaces::Writeable; + +use crate::arch::aarch64::asm::{CPACR_EL1}; +use cortex_a::registers::{VBAR_EL1, SCTLR_EL1}; +use tock_registers::interfaces::{Writeable, ReadWriteable}; + +use cortex_a::asm::barrier::{self, dsb, isb}; #[no_mangle] fn __aa64_bsp_main() { // Disable FP instruction trapping - CPACR_EL1.write(CPACR_EL1::FPEN::TrapNone); + CPACR_EL1.modify(CPACR_EL1::FPEN::TrapNone); extern "C" { static aa64_el1_vectors: u8; } unsafe { VBAR_EL1.set(&aa64_el1_vectors as *const _ as u64); + + // Setup caching in SCTLR_EL1 + dsb(barrier::SY); + isb(barrier::SY); + + SCTLR_EL1.modify(SCTLR_EL1::I::SET + + SCTLR_EL1::SA::SET + + SCTLR_EL1::C::SET + + SCTLR_EL1::A::SET); + + dsb(barrier::SY); + isb(barrier::SY); } debugln!("Test"); - use crate::arch::machine; - use crate::dev::{serial::SerialDevice, timer::TimestampSource, Device}; - + let mut el: u64; + let mut sctlr_el1: u64; unsafe { - machine::console().lock().enable().unwrap(); - machine::local_timer().lock().enable().unwrap(); + asm!("mrs {}, currentel", out(reg) el); + asm!("mrs {}, sctlr_el1", out(reg) sctlr_el1); } + el >>= 2; + el &= 0x3; - let base = machine::local_timer().lock().timestamp().unwrap(); + debugln!("Current EL = {}", el); + debugln!("SCTLR_EL1 = {:#x}", sctlr_el1); + + //use crate::arch::machine; + //use crate::dev::{serial::SerialDevice, timer::TimestampSource, Device}; + + //unsafe { + //machine::console().lock().enable().unwrap(); + //machine::local_timer().lock().enable().unwrap(); + //} + + //let base = machine::local_timer().lock().timestamp().unwrap(); loop { - let count = machine::local_timer().lock().timestamp().unwrap(); - let ch = machine::console().lock().recv(true).unwrap(); - debugln!("[{:?}] {:#04x} = '{}'!", count - base, ch, ch as char); + cortex_a::asm::wfe(); + //let count = machine::local_timer().lock().timestamp().unwrap(); + //let ch = machine::console().lock().recv(true).unwrap(); + //debugln!("[{:?}] {:#04x} = '{}'!", count - base, ch, ch as char); } } -global_asm!(include_str!("entry.S")); +cfg_if! { + if #[cfg(feature = "mach_orangepi3")] { + global_asm!(include_str!("uboot.S")); + } else { + global_asm!(include_str!("entry.S")); + } +} diff --git a/kernel/src/arch/aarch64/boot/uboot.S b/kernel/src/arch/aarch64/boot/uboot.S new file mode 100644 index 0000000..8ba2611 --- /dev/null +++ b/kernel/src/arch/aarch64/boot/uboot.S @@ -0,0 +1,46 @@ +// vi:ft=a64asm.asm: + +.set UART0_BASE, 0x05000000 + +.set SPSR_EL2_EL1h, 0x5 +.set HCR_EL2_RW, 1 << 31 +.set HCR_EL2_HCD, 1 << 29 + +.macro ADR_REL reg, sym + adrp \reg, \sym + add \reg, \reg, #:lo12:\sym +.endm + +.section .text._entry +.global _entry +_entry: + // Test for EL2 + mrs x0, CurrentEL + lsr x0, x0, #2 + cmp x0, #2 + bne 1f + // Exit EL2 + // TODO cnthtctl_el2 setup + + ADR_REL x0, 1f + msr elr_el2, x0 + mov x0, #SPSR_EL2_EL1h + msr spsr_el2, x0 + mov x0, #(HCR_EL2_RW | HCR_EL2_HCD) + msr hcr_el2, x0 + + eret +1: + dsb sy + isb + + ADR_REL x0, bsp_stack_top + mov sp, x0 + + b __aa64_bsp_main + +.section .bss +.p2align 12 +bsp_stack_bottom: + .skip 32768 +bsp_stack_top: diff --git a/kernel/src/arch/aarch64/mach_orangepi3/mod.rs b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs new file mode 100644 index 0000000..2ddb954 --- /dev/null +++ b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs @@ -0,0 +1,62 @@ +//! QEMU virt machine + +use crate::arch::aarch64::timer::GenericTimer; +use crate::dev::{Device, serial::SerialDevice}; +use crate::dev::timer::TimestampSource; +use crate::sync::Spin; +use error::Errno; + +fn delay(mut p: usize) { + while p != 0 { + cortex_a::asm::nop(); + p -= 1; + } +} + +struct Uart { + base: usize +} + +impl Device for Uart { + fn name() -> &'static str { + "Allwinner H6 UART" + } + + unsafe fn enable(&mut self) -> Result<(), Errno> { + todo!() + } +} + +impl SerialDevice for Uart { + fn send(&mut self, byte: u8) -> Result<(), Errno> { + unsafe { + if byte == b'\n' { + core::ptr::write_volatile(self.base as *mut u32, 13u32); + delay(10000); + } + core::ptr::write_volatile(self.base as *mut u32, byte as u32); + delay(10000); + } + Ok(()) + } + + fn recv(&mut self, blocking: bool) -> Result { + todo!() + } +} + +const UART0_BASE: usize = 0x05000000; + +/// Returns primary console for this machine +#[inline] +pub fn console() -> &'static Spin { + &UART0 +} + +///// Returns the timer used as CPU-local periodic IRQ source +//#[inline] +//pub fn local_timer() -> &'static Spin { +// &LOCAL_TIMER +//} + +static UART0: Spin = Spin::new(Uart { base: UART0_BASE }); diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index cc26aef..e807376 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -10,5 +10,9 @@ cfg_if! { pub mod mach_qemu; pub use mach_qemu as machine; + } else if #[cfg(feature = "mach_orangepi3")] { + pub mod mach_orangepi3; + + pub use mach_orangepi3 as machine; } }