feat: orangepi3 higher-half poc

Reset is broken
This commit is contained in:
Mark Poliakov 2021-10-11 15:09:26 +03:00
parent a8b7e88cfe
commit 189229ca7a
14 changed files with 191 additions and 93 deletions

View File

@ -57,7 +57,7 @@ ifeq ($(ARCH),aarch64)
$(OBJCOPY) -O binary $(O)/kernel $(O)/kernel.bin
endif
ifeq ($(MACH),orangepi3)
$(LLVM_BASE)/llvm-strip $(O)/kernel
# $(LLVM_BASE)/llvm-strip $(O)/kernel
$(LLVM_BASE)/llvm-size $(O)/kernel
endif

View File

@ -1,35 +1,44 @@
ENTRY(_entry);
MEMORY {
ram : ORIGIN = 0x48000000, LENGTH = 992M
}
KERNEL_OFFSET = 0xFFFFFF8000000000;
BASE_OFFSET = 0x42000000;
SECTIONS {
. = BASE_OFFSET;
.text.lower : {
*(.text._entry)
}
. = ALIGN(16);
. = . + KERNEL_OFFSET;
PROVIDE(__kernel_start = .);
.text : {
*(.text._entry)
.text : AT(. - KERNEL_OFFSET) {
*(.text._entry_upper)
*(.text*)
} >ram
}
. = ALIGN(4K);
.rodata : {
.rodata : AT(. - KERNEL_OFFSET) {
*(.rodata*)
} >ram
}
. = ALIGN(4K);
.data : {
.data : AT(. - KERNEL_OFFSET) {
*(.data*)
} >ram
}
. = ALIGN(4K);
.bss : {
PROVIDE(__bss_start = .);
PROVIDE(__bss_start_phys = . - KERNEL_OFFSET);
PROVIDE(__bss_start = .);
.bss : AT(. - KERNEL_OFFSET) {
*(COMMON)
*(.bss*)
. = ALIGN(4K);
PROVIDE(__bss_end = .);
} >ram
}
PROVIDE(__bss_end_phys = . - KERNEL_OFFSET);
PROVIDE(__kernel_end = .);
}

View File

@ -1,17 +1,4 @@
// vi:ft=a64asm.asm:
.macro ADR_REL reg, sym
adrp \reg, \sym
add \reg, \reg, #:lo12:\sym
.endm
.macro ADR_ABS reg, sym
movz \reg, #:abs_g3:\sym
movk \reg, #:abs_g2_nc:\sym
movk \reg, #:abs_g1_nc:\sym
movk \reg, #:abs_g0_nc:\sym
.endm
.section .text._entry
.global _entry
_entry:

View File

@ -0,0 +1,16 @@
.macro MOV_L reg, value
mov \reg, #((\value) & 0xFFFF)
movk \reg, #((\value) >> 16), lsl #16
.endm
.macro ADR_REL reg, sym
adrp \reg, \sym
add \reg, \reg, #:lo12:\sym
.endm
.macro ADR_ABS reg, sym
movz \reg, #:abs_g3:\sym
movk \reg, #:abs_g2_nc:\sym
movk \reg, #:abs_g1_nc:\sym
movk \reg, #:abs_g0_nc:\sym
.endm

View File

@ -34,8 +34,10 @@ fn __aa64_bsp_main(fdt_base: usize) {
machine::init_board().unwrap();
let fdt = DeviceTree::from_phys(fdt_base + 0xFFFFFF8000000000).expect("Failed to obtain a device tree");
fdt.dump();
// let fdt = DeviceTree::from_phys(fdt_base + 0xFFFFFF8000000000).expect("Failed to obtain a device tree");
// fdt.dump();
debugln!("Machine init finished");
unsafe {
machine::local_timer().enable().unwrap();
@ -47,6 +49,8 @@ fn __aa64_bsp_main(fdt_base: usize) {
}
}
global_asm!(include_str!("macros.S"));
cfg_if! {
if #[cfg(feature = "mach_orangepi3")] {
global_asm!(include_str!("uboot.S"));

View File

@ -10,19 +10,11 @@
.set CNTHCTL_EL2_EL1PCEN, 1 << 1
.set CNTHCTL_EL2_EL1PCTEN, 1 << 0
.macro ADR_REL reg, sym
adrp \reg, \sym
add \reg, \reg, #:lo12:\sym
.endm
.macro MOV_L reg, value
mov \reg, #((\value) & 0xFFFF)
movk \reg, #((\value) >> 16), lsl #16
.endm
.section .text._entry
.global _entry
_entry:
mov x8, x0
// Test for EL2
mrs x0, CurrentEL
lsr x0, x0, #2
@ -45,7 +37,7 @@ _entry:
orr x0, x0, #SPSR_EL2_MASK_DAIF
msr spsr_el2, x0
ADR_REL x0, 1f
adr x0, 1f
msr elr_el2, x0
isb
@ -54,8 +46,27 @@ _entry:
dsb sy
isb
ADR_REL x0, bsp_stack_top
mov sp, x0
// Zero .bss
ADR_ABS x0, __bss_start_phys
ADR_ABS x1, __bss_end_phys
1:
cmp x0, x1
beq 2f
str xzr, [x0], #8
b 1b
2:
ADR_ABS x9, __aa64_entry_upper
b __aa64_enter_upper
.section .text._entry_upper
__aa64_entry_upper:
// x0 -- fdt address
ADR_REL x1, bsp_stack_top
mov sp, x1
mov lr, xzr
bl __aa64_bsp_main

View File

@ -6,8 +6,8 @@
.set MAIR_EL1_Attr0_Normal_Inner_NC, (4 << 0)
.set MAIR_EL1_Attr0_Normal_Outer_NC, (4 << 4)
.set MAIR_EL1_Attr1_Device, (0 << 4)
.set MAIR_EL1_Attr1_Device_nGnRnE, (0 << 4)
.set MAIR_EL1_Attr1_Device, (0 << 12)
.set MAIR_EL1_Attr1_Device_nGnRE, (1 << 8)
.set ID_AA64MMFR0_EL1_TGran4, (0xF << 28)
@ -27,13 +27,10 @@
.set TCR_EL1_ATTRS, (TCR_EL1_TG1_4K | TCR_EL1_SH1_Outer | TCR_EL1_TG0_4K | TCR_EL1_SH0_Outer | (25 << TCR_EL1_T1SZ_SHIFT) | (25 << TCR_EL1_T0SZ_SHIFT))
.set SCTLR_EL1_I, (1 << 12)
.set SCTLR_EL1_C, (1 << 2)
.set SCTLR_EL1_M, (1 << 0)
.macro MOV_L reg, value
mov \reg, #((\value) & 0xFFFF)
movk \reg, #((\value) >> 16), lsl #16
.endm
.section .text._entry
.global __aa64_enter_upper
.type __aa64_enter_upper, %function
@ -65,7 +62,9 @@ __aa64_enter_upper:
cbnz x2, 1b
.init_mmu_regs:
mov x0, #(MAIR_EL1_Attr0_Normal_Outer_NC | MAIR_EL1_Attr0_Normal_Inner_NC | MAIR_EL1_Attr1_Device | MAIR_EL1_Attr1_Device_nGnRnE)
mov x0, #(MAIR_EL1_Attr0_Normal_Outer_NC | MAIR_EL1_Attr0_Normal_Inner_NC | MAIR_EL1_Attr1_Device | MAIR_EL1_Attr1_Device_nGnRE)
msr mair_el1, x0
// Test for 4KiB page support
mrs x0, ID_AA64MMFR0_EL1
mov x1, ID_AA64MMFR0_EL1_TGran4
@ -79,11 +78,12 @@ __aa64_enter_upper:
orr x0, x0, x1
msr tcr_el1, x0
msr mair_el1, x0
msr ttbr0_el1, x5
msr ttbr1_el1, x5
dsb ish
isb
mrs x0, sctlr_el1
orr x0, x0, #SCTLR_EL1_M
msr sctlr_el1, x0

View File

@ -5,12 +5,13 @@
//! 1. CPUS-PORT (TODO PL, PM)
//! 2. CPUX-PORT (PC, PD, PF, PG, PH)
//!
use crate::arch::MemoryIo;
use crate::dev::{
gpio::{GpioDevice, PinConfig, PinMode, PullMode},
Device,
};
use crate::mem::virt::DeviceMemoryIo;
use crate::sync::IrqSafeNullLock;
use crate::util::InitOnce;
use error::Errno;
use tock_registers::interfaces::{Readable, Writeable};
use tock_registers::register_structs;
@ -28,11 +29,12 @@ register_structs! {
}
struct CpuxGpio {
regs: MemoryIo<[CpuxPortRegs; 8]>,
regs: DeviceMemoryIo<[CpuxPortRegs; 8]>,
}
pub struct Gpio {
cpux: IrqSafeNullLock<CpuxGpio>,
cpux: InitOnce<IrqSafeNullLock<CpuxGpio>>,
cpux_base: usize,
}
/// Structure combining bank and pin numbers
@ -142,6 +144,9 @@ impl Device for Gpio {
}
unsafe fn enable(&self) -> Result<(), Errno> {
self.cpux.init(IrqSafeNullLock::new(CpuxGpio {
regs: DeviceMemoryIo::map(self.name(), self.cpux_base, 1)?,
}));
Ok(())
}
}
@ -155,7 +160,7 @@ impl GpioDevice for Gpio {
match bank {
0 | 1 | 4 => unimplemented!(),
_ => self.cpux.lock().set_pin_config(bank, pin, cfg),
_ => self.cpux.get().lock().set_pin_config(bank, pin, cfg),
}
}
@ -169,7 +174,7 @@ impl GpioDevice for Gpio {
match bank {
0 | 1 | 4 => unimplemented!(),
_ => self.cpux.lock().write_pin(bank, pin, state),
_ => self.cpux.get().lock().write_pin(bank, pin, state),
}
}
@ -179,7 +184,7 @@ impl GpioDevice for Gpio {
match bank {
0 | 1 | 4 => unimplemented!(),
_ => self.cpux.lock().toggle_pin(bank, pin),
_ => self.cpux.get().lock().toggle_pin(bank, pin),
}
}
@ -189,7 +194,7 @@ impl GpioDevice for Gpio {
match bank {
0 | 1 | 4 => unimplemented!(),
_ => Ok(self.cpux.lock().read_pin(bank, pin)),
_ => Ok(self.cpux.get().lock().read_pin(bank, pin)),
}
}
}
@ -200,11 +205,10 @@ impl Gpio {
self.set_pin_config(PinAddress::new(7, 1), &PinConfig::alt(2))
}
pub const unsafe fn new(base: usize) -> Self {
pub const unsafe fn new(cpux_base: usize) -> Self {
Self {
cpux: IrqSafeNullLock::new(CpuxGpio {
regs: MemoryIo::new(base),
}),
cpux: InitOnce::new(),
cpux_base,
}
}
}

View File

@ -28,14 +28,17 @@ use wdog::RWdog;
#[allow(missing_docs)]
pub fn init_board() -> Result<(), Errno> {
unsafe {
UART0.enable()?;
GIC.enable()?;
GPIO.enable()?;
UART0.init_irqs()?;
R_WDOG.enable()?;
GPIO.cfg_uart0_ph0_ph1()?;
GPIO.set_pin_config(PinAddress::new(3, 26), &PinConfig::out_pull_down())?;
UART0.enable()?;
UART0.init_irqs()?;
RTC.enable()?;
RTC.init_irqs()?;
}

View File

@ -1,13 +1,12 @@
use crate::arch::{
machine::{self, IrqNumber},
MemoryIo,
};
use crate::arch::machine::{self, IrqNumber};
use crate::dev::{
irq::{IntController, IntSource},
rtc::RtcDevice,
Device,
};
use crate::mem::virt::DeviceMemoryIo;
use crate::sync::IrqSafeNullLock;
use crate::util::InitOnce;
use error::Errno;
use tock_registers::{
interfaces::{Readable, Writeable},
@ -48,7 +47,8 @@ register_structs! {
}
pub struct Rtc {
regs: IrqSafeNullLock<MemoryIo<Regs>>,
regs: InitOnce<IrqSafeNullLock<DeviceMemoryIo<Regs>>>,
base: usize,
irq: IrqNumber,
}
@ -70,13 +70,14 @@ impl RtcDevice for Rtc {}
impl IntSource for Rtc {
fn handle_irq(&self) -> Result<(), Errno> {
self.regs.lock().arm_alarm0_irq(1);
self.regs.get().lock().arm_alarm0_irq(1);
debugln!("Tick!");
Ok(())
}
fn init_irqs(&'static self) -> Result<(), Errno> {
machine::intc().register_handler(self.irq, self)?;
self.regs.lock().arm_alarm0_irq(1);
self.regs.get().lock().arm_alarm0_irq(1);
machine::intc().enable_irq(self.irq)?;
Ok(())
@ -89,6 +90,7 @@ impl Device for Rtc {
}
unsafe fn enable(&self) -> Result<(), Errno> {
self.regs.init(IrqSafeNullLock::new(DeviceMemoryIo::map(self.name(), self.base, 1)?));
Ok(())
}
}
@ -101,7 +103,8 @@ impl Rtc {
/// Does not perform `base` validation.
pub const unsafe fn new(base: usize, irq: IrqNumber) -> Self {
Self {
regs: IrqSafeNullLock::new(MemoryIo::new(base)),
regs: InitOnce::new(),
base,
irq,
}
}

View File

@ -1,8 +1,9 @@
use crate::arch::{
machine::{self, IrqNumber},
MemoryIo,
};
use crate::sync::IrqSafeNullLock;
use crate::util::InitOnce;
use crate::mem::virt::DeviceMemoryIo;
use crate::dev::{
irq::{IntController, IntSource},
serial::SerialDevice,
@ -73,8 +74,13 @@ register_structs! {
}
}
struct UartInner {
regs: DeviceMemoryIo<Regs>
}
pub(super) struct Uart {
regs: IrqSafeNullLock<MemoryIo<Regs>>,
inner: InitOnce<IrqSafeNullLock<UartInner>>,
base: usize,
irq: IrqNumber
}
@ -84,33 +90,41 @@ impl Device for Uart {
}
unsafe fn enable(&self) -> Result<(), Errno> {
let mut inner = UartInner {
regs: DeviceMemoryIo::map(self.name(), self.base, 1)?
};
// TODO
self.inner.init(IrqSafeNullLock::new(inner));
Ok(())
}
}
impl SerialDevice for Uart {
fn send(&self, byte: u8) -> Result<(), Errno> {
let regs = self.regs.lock();
while !regs.LSR.matches_all(LSR::THRE::SET) {
if !self.inner.is_initialized() {
return Ok(());
}
let inner = self.inner.get().lock();
while !inner.regs.LSR.matches_all(LSR::THRE::SET) {
cortex_a::asm::nop();
}
regs.DR_DLL.set(byte as u32);
inner.regs.DR_DLL.set(byte as u32);
Ok(())
}
fn recv(&self, _blocking: bool) -> Result<u8, Errno> {
let regs = self.regs.lock();
while !regs.LSR.matches_all(LSR::DR::SET) {
let inner = self.inner.get().lock();
while !inner.regs.LSR.matches_all(LSR::DR::SET) {
cortex_a::asm::nop();
}
Ok(regs.DR_DLL.get() as u8)
Ok(inner.regs.DR_DLL.get() as u8)
}
}
impl IntSource for Uart {
fn handle_irq(&self) -> Result<(), Errno> {
let byte = self.regs.lock().DR_DLL.get();
let byte = self.inner.get().lock().regs.DR_DLL.get();
debugln!("irq byte = {:#04x}!", byte);
if byte == 0x1B {
@ -127,7 +141,7 @@ impl IntSource for Uart {
fn init_irqs(&'static self) -> Result<(), Errno> {
machine::intc().register_handler(self.irq, self)?;
self.regs.lock().IER_DLH.modify(IER::ERBFI::SET);
self.inner.get().lock().regs.IER_DLH.modify(IER::ERBFI::SET);
machine::intc().enable_irq(self.irq)?;
Ok(())
@ -137,7 +151,8 @@ impl IntSource for Uart {
impl Uart {
pub const unsafe fn new(base: usize, irq: IrqNumber) -> Self {
Self {
regs: IrqSafeNullLock::new(MemoryIo::new(base)),
inner: InitOnce::new(),
base,
irq
}
}

View File

@ -1,5 +1,8 @@
use crate::arch::MemoryIo;
use crate::dev::Device;
use crate::mem::virt::DeviceMemoryIo;
use crate::sync::IrqSafeNullLock;
use crate::util::InitOnce;
use error::Errno;
use tock_registers::{
interfaces::Writeable, register_bitfields, register_structs, registers::ReadWrite,
};
@ -36,7 +39,23 @@ register_structs! {
}
pub(super) struct RWdog {
regs: IrqSafeNullLock<MemoryIo<RWdogRegs>>,
inner: InitOnce<IrqSafeNullLock<DeviceMemoryIo<RWdogRegs>>>,
base: usize,
}
impl Device for RWdog {
fn name(&self) -> &'static str {
"Allwinner H6 R_WDOG"
}
unsafe fn enable(&self) -> Result<(), Errno> {
self.inner.init(IrqSafeNullLock::new(DeviceMemoryIo::map(
self.name(),
self.base,
1,
)?));
Ok(())
}
}
impl RWdog {
@ -46,7 +65,7 @@ impl RWdog {
///
/// Unsafe: may interrupt critical processes
pub unsafe fn reset_board(&self) -> ! {
let regs = self.regs.lock();
let regs = self.inner.get().lock();
regs.CFG.write(CFG::CONFIG::System);
regs.MODE.write(MODE::EN::SET);
@ -64,7 +83,8 @@ impl RWdog {
/// Does not perform `base` validation.
pub const unsafe fn new(base: usize) -> Self {
Self {
regs: IrqSafeNullLock::new(MemoryIo::new(base)),
inner: InitOnce::new(),
base,
}
}
}

View File

@ -26,8 +26,28 @@ pub mod mem;
pub mod sync;
pub mod util;
use core::fmt::{Write, self};
struct DummyUart;
impl Write for DummyUart {
fn write_str(&mut self, s: &str) -> fmt::Result {
for b in s.bytes() {
unsafe {
core::ptr::write_volatile(0xFFFFFFC000000000 as *mut u32, b as u32);
for _ in 0..100000 {
asm!("nop");
}
}
}
Ok(())
}
}
#[panic_handler]
fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
let mut u = DummyUart;
write!(&mut u, "Panic occurred!\r\n");
write!(&mut u, "{:?}", pi);
// TODO
loop {}
}

View File

@ -10,10 +10,12 @@ use error::Errno;
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
const PTE_BLOCK_AF: u64 = 1 << 10;
const PTE_BLOCK_NSH: u64 = 0 << 8;
const PTE_BLOCK_ISH: u64 = 3 << 8;
const PTE_BLOCK_OSH: u64 = 2 << 8;
const PTE_TABLE: u64 = 1 << 1;
const PTE_PRESENT: u64 = 1 << 0;
const PTE_ATTR1: u64 = 1 << 2;
#[repr(C, align(0x1000))]
struct Table([u64; 512]);
@ -59,7 +61,8 @@ impl DeviceMemory {
HUGE_COUNT += 1;
KERNEL_TTBR1.0[count + 256] =
(phys as u64) | PTE_PRESENT | PTE_BLOCK_OSH | PTE_BLOCK_AF;
(phys as u64) | PTE_PRESENT | PTE_BLOCK_OSH | PTE_BLOCK_AF | PTE_ATTR1;
asm!("dsb ish; isb");
DEVICE_MAP_OFFSET + (count << 30)
}
@ -70,7 +73,8 @@ impl DeviceMemory {
}
BIG_COUNT += 1;
KERNEL_L1.0[count] = (phys as u64) | PTE_PRESENT | PTE_BLOCK_OSH | PTE_BLOCK_AF;
KERNEL_L1.0[count] = (phys as u64) | PTE_PRESENT | PTE_BLOCK_OSH | PTE_BLOCK_AF | PTE_ATTR1;
asm!("dsb ish; isb");
DEVICE_MAP_OFFSET + (count << 21)
}
@ -82,7 +86,9 @@ impl DeviceMemory {
COUNT += 1;
KERNEL_L2.0[count] =
(phys as u64) | PTE_TABLE | PTE_PRESENT | PTE_BLOCK_OSH | PTE_BLOCK_AF;
(phys as u64) | PTE_TABLE | PTE_BLOCK_OSH | PTE_PRESENT | PTE_BLOCK_AF | PTE_ATTR1;
asm!("tlbi vaae1, {}", in(reg) (DEVICE_MAP_OFFSET + (count << 12)), options(nostack, nomem));
asm!("dsb ish; isb");
DEVICE_MAP_OFFSET + (count << 12)
}