aarch64: initial support for Orange Pi 3
This commit is contained in:
parent
44a888c39a
commit
afc3af54fa
14
Cargo.toml
14
Cargo.toml
@ -18,10 +18,13 @@ spinning_top = "0.2.5"
|
|||||||
# static_assertions = "1.1.0"
|
# static_assertions = "1.1.0"
|
||||||
tock-registers = "0.8.1"
|
tock-registers = "0.8.1"
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
bitmap-font = { version = "0.3.0" }
|
|
||||||
embedded-graphics = "0.8.0"
|
|
||||||
git-version = "0.3.5"
|
git-version = "0.3.5"
|
||||||
|
|
||||||
|
aarch64-cpu = "9.3.1"
|
||||||
|
|
||||||
|
bitmap-font = { version = "0.3.0", optional = true }
|
||||||
|
embedded-graphics = { version = "0.8.0", optional = true }
|
||||||
|
|
||||||
[dependencies.elf]
|
[dependencies.elf]
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
git = "https://git.alnyan.me/yggdrasil/yggdrasil-elf.git"
|
git = "https://git.alnyan.me/yggdrasil/yggdrasil-elf.git"
|
||||||
@ -30,9 +33,14 @@ features = ["no_std_stream"]
|
|||||||
|
|
||||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||||
fdt-rs = { version = "0.4.3", default-features = false }
|
fdt-rs = { version = "0.4.3", default-features = false }
|
||||||
aarch64-cpu = "9.3.1"
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||||
yboot-proto = { git = "https://git.alnyan.me/yggdrasil/yboot-proto.git" }
|
yboot-proto = { git = "https://git.alnyan.me/yggdrasil/yboot-proto.git" }
|
||||||
aml = "0.16.4"
|
aml = "0.16.4"
|
||||||
acpi = "4.1.1"
|
acpi = "4.1.1"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
fb_console = ["bitmap-font", "embedded-graphics"]
|
||||||
|
aarch64_qemu = []
|
||||||
|
aarch64_orange_pi3 = []
|
||||||
|
77
src/arch/aarch64/boot/entry.S
Normal file
77
src/arch/aarch64/boot/entry.S
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
.set CNTHCTL_EL2_EL1PCTEN, 1 << 0
|
||||||
|
.set CNTHCTL_EL2_EL1PCEN, 1 << 1
|
||||||
|
|
||||||
|
.set HCR_EL2_RW_EL1IsAArch64, 1 << 31
|
||||||
|
|
||||||
|
.set SCTLR_EL2_RES1, 0x30C50830
|
||||||
|
|
||||||
|
.set SPSR_EL2_EL1h, 0x5
|
||||||
|
.set SPSR_EL2_MASK_DAIF, 0xF << 6
|
||||||
|
|
||||||
|
.macro MOV_L reg, value
|
||||||
|
mov \reg, #((\value) & 0xFFFF)
|
||||||
|
movk \reg, #((\value) >> 16), lsl #16
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.global __aarch64_entry
|
||||||
|
.section .text.entry
|
||||||
|
__aarch64_entry:
|
||||||
|
// x0 -- dtb_phys
|
||||||
|
|
||||||
|
// Multiple processor cores may or may not be running at this point
|
||||||
|
mrs x1, mpidr_el1
|
||||||
|
ands x1, x1, #0xF
|
||||||
|
bne 1f
|
||||||
|
|
||||||
|
mrs x8, CurrentEL
|
||||||
|
lsr x8, x8, #2
|
||||||
|
cmp x8, #2
|
||||||
|
bne .el1
|
||||||
|
|
||||||
|
// Leave EL2
|
||||||
|
.el2:
|
||||||
|
mrs x8, CNTHCTL_EL2
|
||||||
|
orr x8, x8, #(CNTHCTL_EL2_EL1PCTEN | CNTHCTL_EL2_EL1PCEN)
|
||||||
|
msr CNTHCTL_EL2, x8
|
||||||
|
msr CNTVOFF_EL2, xzr
|
||||||
|
|
||||||
|
MOV_L x8, SCTLR_EL2_RES1
|
||||||
|
msr SCTLR_EL2, x8
|
||||||
|
|
||||||
|
mov x8, #HCR_EL2_RW_EL1IsAArch64
|
||||||
|
msr HCR_EL2, x8
|
||||||
|
|
||||||
|
mov x8, #SPSR_EL2_EL1h
|
||||||
|
orr x8, x8, #SPSR_EL2_MASK_DAIF
|
||||||
|
msr SPSR_EL2, x8
|
||||||
|
|
||||||
|
adr x8, .el1
|
||||||
|
msr ELR_EL2, x8
|
||||||
|
|
||||||
|
isb
|
||||||
|
eret
|
||||||
|
.el1:
|
||||||
|
dsb sy
|
||||||
|
isb
|
||||||
|
|
||||||
|
// Zero .bss
|
||||||
|
adr x8, __bss_start_phys
|
||||||
|
adr x9, __bss_end_phys
|
||||||
|
1:
|
||||||
|
cmp x8, x9
|
||||||
|
beq 2f
|
||||||
|
strb wzr, [x8]
|
||||||
|
add x8, x8, #1
|
||||||
|
b 1b
|
||||||
|
2:
|
||||||
|
|
||||||
|
// BSP in SMP or uniprocessor
|
||||||
|
ldr x1, ={stack_bottom} + {stack_size} - {kernel_virt_offset}
|
||||||
|
mov sp, x1
|
||||||
|
|
||||||
|
bl {kernel_lower_entry} - {kernel_virt_offset}
|
||||||
|
|
||||||
|
// AP in a SMP system
|
||||||
|
// TODO spin loop for this method of init
|
||||||
|
1:
|
||||||
|
b .
|
@ -1,8 +1,17 @@
|
|||||||
//! Main entry point for the AArch64 platforms
|
//! Main entry point for the AArch64 platforms
|
||||||
use core::{arch::asm, sync::atomic::Ordering};
|
use core::{
|
||||||
|
arch::{asm, global_asm},
|
||||||
|
sync::atomic::Ordering,
|
||||||
|
};
|
||||||
|
|
||||||
use aarch64_cpu::registers::{CurrentEL, CPACR_EL1};
|
use aarch64_cpu::{
|
||||||
use tock_registers::interfaces::{ReadWriteable, Readable};
|
asm::barrier,
|
||||||
|
registers::{
|
||||||
|
CurrentEL, CNTHCTL_EL2, CNTVOFF_EL2, CPACR_EL1, ELR_EL2, HCR_EL2, SCTLR_EL2, SPSR_EL2,
|
||||||
|
SP_EL1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
cpu::Cpu, exception, kernel_main, smp::CPU_COUNT, AArch64, KernelStack, ARCHITECTURE,
|
cpu::Cpu, exception, kernel_main, smp::CPU_COUNT, AArch64, KernelStack, ARCHITECTURE,
|
||||||
@ -19,13 +28,20 @@ use crate::{
|
|||||||
|
|
||||||
pub(super) static CPU_INIT_FENCE: SpinFence = SpinFence::new();
|
pub(super) static CPU_INIT_FENCE: SpinFence = SpinFence::new();
|
||||||
|
|
||||||
fn __aarch64_common_lower_entry() {
|
extern "C" fn el1_bsp_lower_entry(dtb_phys: usize) -> ! {
|
||||||
// Unmask FP operations
|
// Unmask FP operations
|
||||||
CPACR_EL1.modify(CPACR_EL1::FPEN::TrapNothing);
|
CPACR_EL1.modify(CPACR_EL1::FPEN::TrapNothing);
|
||||||
|
|
||||||
if CurrentEL.read(CurrentEL::EL) != 1 {
|
unsafe {
|
||||||
panic!("Only EL1 is supported for now");
|
ARCHITECTURE.init_mmu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sp = unsafe { BSP_STACK.data.as_ptr().add(BOOT_STACK_SIZE).virtualize() };
|
||||||
|
let elr = absolute_address!(__aarch64_bsp_upper_entry);
|
||||||
|
|
||||||
|
barrier::dsb(barrier::SY);
|
||||||
|
barrier::isb(barrier::SY);
|
||||||
|
enter_higher_half(sp as usize, elr, dtb_phys);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter_higher_half(sp: usize, elr: usize, arg: usize) -> ! {
|
fn enter_higher_half(sp: usize, elr: usize, arg: usize) -> ! {
|
||||||
@ -39,27 +55,16 @@ fn enter_higher_half(sp: usize, elr: usize, arg: usize) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) extern "C" fn __aarch64_ap_lower_entry(sp: usize) -> ! {
|
pub(super) extern "C" fn __aarch64_ap_lower_entry(sp: usize) -> ! {
|
||||||
__aarch64_common_lower_entry();
|
loop {}
|
||||||
|
// __aarch64_common_lower_entry();
|
||||||
|
|
||||||
unsafe {
|
// unsafe {
|
||||||
ARCHITECTURE.init_mmu(false);
|
// ARCHITECTURE.init_mmu(false);
|
||||||
}
|
// }
|
||||||
|
|
||||||
let sp = unsafe { sp.virtualize() };
|
// let sp = unsafe { sp.virtualize() };
|
||||||
let elr = absolute_address!(__aarch64_ap_upper_entry);
|
// let elr = absolute_address!(__aarch64_ap_upper_entry);
|
||||||
enter_higher_half(sp, elr, 0);
|
// enter_higher_half(sp, elr, 0);
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn __aarch64_bsp_lower_entry(dtb_phys: usize) -> ! {
|
|
||||||
__aarch64_common_lower_entry();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
ARCHITECTURE.init_mmu(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let sp = unsafe { BSP_STACK.data.as_ptr().add(BOOT_STACK_SIZE).virtualize() };
|
|
||||||
let elr = absolute_address!(__aarch64_bsp_upper_entry);
|
|
||||||
enter_higher_half(sp as usize, elr, dtb_phys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn __aarch64_bsp_upper_entry(dtb_phys: usize) -> ! {
|
extern "C" fn __aarch64_bsp_upper_entry(dtb_phys: usize) -> ! {
|
||||||
@ -91,38 +96,14 @@ extern "C" fn __aarch64_ap_upper_entry(_x0: usize) -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[link_section = ".text.entry"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
unsafe extern "C" fn __aarch64_entry() -> ! {
|
|
||||||
// Setup the stack and pass on to a proper function
|
|
||||||
asm!(
|
|
||||||
r#"
|
|
||||||
// Multiple processor cores may or may not be running at this point
|
|
||||||
mrs x1, mpidr_el1
|
|
||||||
ands x1, x1, #0xF
|
|
||||||
bne 1f
|
|
||||||
|
|
||||||
// BSP in SMP or uniprocessor
|
|
||||||
ldr x1, ={stack_bottom} + {stack_size} - {kernel_virt_offset}
|
|
||||||
mov sp, x1
|
|
||||||
|
|
||||||
bl {kernel_lower_entry} - {kernel_virt_offset}
|
|
||||||
|
|
||||||
// AP in a SMP system
|
|
||||||
// TODO spin loop for this method of init
|
|
||||||
1:
|
|
||||||
b .
|
|
||||||
"#,
|
|
||||||
kernel_lower_entry = sym __aarch64_bsp_lower_entry,
|
|
||||||
stack_bottom = sym BSP_STACK,
|
|
||||||
stack_size = const BOOT_STACK_SIZE,
|
|
||||||
kernel_virt_offset = const KERNEL_VIRT_OFFSET,
|
|
||||||
options(noreturn)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".bss"]
|
|
||||||
static BSP_STACK: KernelStack = KernelStack {
|
static BSP_STACK: KernelStack = KernelStack {
|
||||||
data: [0; BOOT_STACK_SIZE],
|
data: [0; BOOT_STACK_SIZE],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
global_asm!(
|
||||||
|
include_str!("entry.S"),
|
||||||
|
kernel_lower_entry = sym el1_bsp_lower_entry,
|
||||||
|
stack_bottom = sym BSP_STACK,
|
||||||
|
stack_size = const BOOT_STACK_SIZE,
|
||||||
|
kernel_virt_offset = const KERNEL_VIRT_OFFSET
|
||||||
|
);
|
||||||
|
@ -7,14 +7,16 @@ use fdt_rs::{
|
|||||||
|
|
||||||
use crate::{debug::LogLevel, mem::phys::PhysicalMemoryRegion};
|
use crate::{debug::LogLevel, mem::phys::PhysicalMemoryRegion};
|
||||||
|
|
||||||
|
const INDEX_BUFFER_SIZE: usize = 65536;
|
||||||
|
|
||||||
#[repr(C, align(0x10))]
|
#[repr(C, align(0x10))]
|
||||||
struct FdtIndexBuffer([u8; 32768]);
|
struct FdtIndexBuffer([u8; INDEX_BUFFER_SIZE]);
|
||||||
|
|
||||||
static mut FDT_INDEX_BUFFER: FdtIndexBuffer = FdtIndexBuffer::zeroed();
|
static mut FDT_INDEX_BUFFER: FdtIndexBuffer = FdtIndexBuffer::zeroed();
|
||||||
|
|
||||||
impl FdtIndexBuffer {
|
impl FdtIndexBuffer {
|
||||||
const fn zeroed() -> Self {
|
const fn zeroed() -> Self {
|
||||||
Self([0; 32768])
|
Self([0; INDEX_BUFFER_SIZE])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,16 +82,24 @@ impl Iterator for FdtMemoryRegionIter<'_> {
|
|||||||
break None;
|
break None;
|
||||||
};
|
};
|
||||||
|
|
||||||
if item.name().unwrap_or("").starts_with("memory@") {
|
let name = item.name().unwrap_or("");
|
||||||
|
|
||||||
|
if name.starts_with("memory@") || name == "memory" {
|
||||||
let reg = item
|
let reg = item
|
||||||
.props()
|
.props()
|
||||||
.find(|p| p.name().unwrap_or("") == "reg")
|
.find(|p| p.name().unwrap_or("") == "reg")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "aarch64_orange_pi3"))]
|
||||||
break Some(PhysicalMemoryRegion {
|
break Some(PhysicalMemoryRegion {
|
||||||
base: reg.u64(0).unwrap() as usize,
|
base: reg.u64(0).unwrap() as usize,
|
||||||
size: reg.u64(1).unwrap() as usize,
|
size: reg.u64(1).unwrap() as usize,
|
||||||
});
|
});
|
||||||
|
#[cfg(feature = "aarch64_orange_pi3")]
|
||||||
|
break Some(PhysicalMemoryRegion {
|
||||||
|
base: reg.u32(0).unwrap() as usize,
|
||||||
|
size: reg.u32(1).unwrap() as usize,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,11 +151,13 @@ fn dump_node(node: &TNode, depth: usize, level: LogLevel) {
|
|||||||
log_print_raw!(level, "{:?} {{\n", node_name);
|
log_print_raw!(level, "{:?} {{\n", node_name);
|
||||||
for prop in node.props() {
|
for prop in node.props() {
|
||||||
indent(level, depth + 1);
|
indent(level, depth + 1);
|
||||||
let name = prop.name().unwrap();
|
let name = prop.name().unwrap_or("<???>");
|
||||||
log_print_raw!(level, "{name:?} = ");
|
log_print_raw!(level, "{name:?} = ");
|
||||||
|
|
||||||
match name {
|
match name {
|
||||||
"compatible" | "stdout-path" => log_print_raw!(level, "{:?}", prop.str().unwrap()),
|
"compatible" | "stdout-path" => {
|
||||||
|
log_print_raw!(level, "{:?}", prop.str().unwrap_or("<???>"))
|
||||||
|
}
|
||||||
_ => log_print_raw!(level, "{:x?}", prop.raw()),
|
_ => log_print_raw!(level, "{:x?}", prop.raw()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ use core::sync::atomic::Ordering;
|
|||||||
|
|
||||||
use aarch64_cpu::registers::{DAIF, ID_AA64MMFR0_EL1, SCTLR_EL1, TCR_EL1, TTBR0_EL1, TTBR1_EL1};
|
use aarch64_cpu::registers::{DAIF, ID_AA64MMFR0_EL1, SCTLR_EL1, TCR_EL1, TTBR0_EL1, TTBR1_EL1};
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
|
use cfg_if::cfg_if;
|
||||||
use fdt_rs::prelude::PropReader;
|
use fdt_rs::prelude::PropReader;
|
||||||
use plat_qemu::PLATFORM;
|
|
||||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -30,7 +30,19 @@ use self::{
|
|||||||
table::{init_fixed_tables, KERNEL_TABLES},
|
table::{init_fixed_tables, KERNEL_TABLES},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod plat_qemu;
|
pub mod plat_orange_pi3;
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "aarch64_qemu")] {
|
||||||
|
pub mod plat_qemu;
|
||||||
|
|
||||||
|
pub use plat_qemu::{PlatformImpl, PLATFORM};
|
||||||
|
} else if #[cfg(feature = "aarch64_orange_pi3")] {
|
||||||
|
|
||||||
|
pub use plat_orange_pi3::{PlatformImpl, PLATFORM};
|
||||||
|
} else {
|
||||||
|
compile_error!("No platform selected for AArch64");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod boot;
|
pub mod boot;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
@ -156,6 +168,7 @@ impl AArch64 {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let regions = FdtMemoryRegionIter::new(dt);
|
let regions = FdtMemoryRegionIter::new(dt);
|
||||||
|
|
||||||
phys::init_from_iter(regions)
|
phys::init_from_iter(regions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,7 +186,14 @@ fn setup_initrd() {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "aarch64_orange_pi3")]
|
||||||
|
let initrd_start = initrd_start.u32(0).unwrap() as usize;
|
||||||
|
#[cfg(feature = "aarch64_orange_pi3")]
|
||||||
|
let initrd_end = initrd_end.u32(0).unwrap() as usize;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "aarch64_orange_pi3"))]
|
||||||
let initrd_start = initrd_start.u64(0).unwrap() as usize;
|
let initrd_start = initrd_start.u64(0).unwrap() as usize;
|
||||||
|
#[cfg(not(feature = "aarch64_orange_pi3"))]
|
||||||
let initrd_end = initrd_end.u64(0).unwrap() as usize;
|
let initrd_end = initrd_end.u64(0).unwrap() as usize;
|
||||||
|
|
||||||
let start_aligned = initrd_start & !0xFFF;
|
let start_aligned = initrd_start & !0xFFF;
|
||||||
@ -206,8 +226,8 @@ pub fn kernel_main(dtb_phys: usize) -> ! {
|
|||||||
unsafe {
|
unsafe {
|
||||||
AArch64::set_interrupt_mask(true);
|
AArch64::set_interrupt_mask(true);
|
||||||
|
|
||||||
ARCHITECTURE.init_device_tree(dtb_phys);
|
|
||||||
PLATFORM.init_debug();
|
PLATFORM.init_debug();
|
||||||
|
ARCHITECTURE.init_device_tree(dtb_phys);
|
||||||
}
|
}
|
||||||
debug::reset();
|
debug::reset();
|
||||||
|
|
||||||
@ -217,6 +237,7 @@ pub fn kernel_main(dtb_phys: usize) -> ! {
|
|||||||
setup_initrd();
|
setup_initrd();
|
||||||
|
|
||||||
debugln!("Initializing {} platform", PLATFORM.name());
|
debugln!("Initializing {} platform", PLATFORM.name());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
ARCHITECTURE
|
ARCHITECTURE
|
||||||
.init_physical_memory(dtb_phys)
|
.init_physical_memory(dtb_phys)
|
||||||
@ -240,10 +261,10 @@ pub fn kernel_main(dtb_phys: usize) -> ! {
|
|||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
Cpu::init_ipi_queues();
|
// Cpu::init_ipi_queues();
|
||||||
|
|
||||||
CPU_INIT_FENCE.signal();
|
// CPU_INIT_FENCE.signal();
|
||||||
CPU_INIT_FENCE.wait_all(CPU_COUNT.load(Ordering::Acquire));
|
// CPU_INIT_FENCE.wait_all(CPU_COUNT.load(Ordering::Acquire));
|
||||||
|
|
||||||
task::init().expect("Failed to initialize the scheduler");
|
task::init().expect("Failed to initialize the scheduler");
|
||||||
|
|
||||||
|
99
src/arch/aarch64/plat_orange_pi3/mod.rs
Normal file
99
src/arch/aarch64/plat_orange_pi3/mod.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
///
|
||||||
|
/// # Booting using u-boot
|
||||||
|
///
|
||||||
|
/// > fatload mmc 0:1 0x40000000 uRamdisk
|
||||||
|
/// > fatload mmc 0:1 0x4d000000 sun50i-h6-orangepi-3.dtb
|
||||||
|
/// > loady 0x44000000
|
||||||
|
/// ...
|
||||||
|
/// > bootm 0x44000000 0x40000000 0x4d000000
|
||||||
|
///
|
||||||
|
use abi::error::Error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
arch::CpuMessage,
|
||||||
|
debug::{self, LogLevel},
|
||||||
|
device::{
|
||||||
|
interrupt::{ExternalInterruptController, InterruptSource, IpiDeliveryTarget},
|
||||||
|
platform::Platform,
|
||||||
|
timer::TimestampSource,
|
||||||
|
InitializableDevice,
|
||||||
|
},
|
||||||
|
fs::devfs::{self, CharDeviceType},
|
||||||
|
};
|
||||||
|
|
||||||
|
use self::{r_wdog::RWatchdog, serial::Serial};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
gic::{Gic, IrqNumber},
|
||||||
|
timer::ArmTimer,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod r_wdog;
|
||||||
|
pub mod serial;
|
||||||
|
|
||||||
|
pub struct PlatformImpl {
|
||||||
|
uart0: Serial,
|
||||||
|
r_wdog: RWatchdog,
|
||||||
|
pub gic: Gic,
|
||||||
|
timer: ArmTimer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Platform for PlatformImpl {
|
||||||
|
type IrqNumber = IrqNumber;
|
||||||
|
|
||||||
|
const KERNEL_PHYS_BASE: usize = 0x50000000;
|
||||||
|
|
||||||
|
unsafe fn init(&'static self, is_bsp: bool) -> Result<(), Error> {
|
||||||
|
if is_bsp {
|
||||||
|
self.gic.init(())?;
|
||||||
|
|
||||||
|
self.timer.init(())?;
|
||||||
|
self.r_wdog.init(())?;
|
||||||
|
|
||||||
|
self.timer.init_irq()?;
|
||||||
|
self.uart0.init_irq()?;
|
||||||
|
|
||||||
|
devfs::add_char_device(&self.uart0, CharDeviceType::TtySerial)?;
|
||||||
|
} else {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn init_debug(&'static self) {
|
||||||
|
self.uart0.init(()).unwrap();
|
||||||
|
debug::add_sink(&self.uart0, LogLevel::Debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interrupt_controller(
|
||||||
|
&self,
|
||||||
|
) -> &dyn ExternalInterruptController<IrqNumber = Self::IrqNumber> {
|
||||||
|
&self.gic
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timestamp_source(&self) -> &dyn TimestampSource {
|
||||||
|
&self.timer
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn send_ipi(&self, target: IpiDeliveryTarget, _msg: CpuMessage) -> Result<(), Error> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"Orange Pi 3"
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn reset(&self) -> ! {
|
||||||
|
self.r_wdog.reset_board();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static PLATFORM: PlatformImpl = unsafe {
|
||||||
|
PlatformImpl {
|
||||||
|
uart0: Serial::new(0x05000000, IrqNumber::new(32)),
|
||||||
|
r_wdog: RWatchdog::new(0x07020400),
|
||||||
|
gic: Gic::new(0x03021000, 0x03022000),
|
||||||
|
timer: ArmTimer::new(IrqNumber::new(30)),
|
||||||
|
}
|
||||||
|
};
|
78
src/arch/aarch64/plat_orange_pi3/r_wdog.rs
Normal file
78
src/arch/aarch64/plat_orange_pi3/r_wdog.rs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
use abi::error::Error;
|
||||||
|
use tock_registers::{
|
||||||
|
interfaces::Writeable, register_bitfields, register_structs, registers::ReadWrite,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
device::InitializableDevice, mem::device::DeviceMemoryIo, sync::IrqSafeSpinlock,
|
||||||
|
util::OneTimeInit,
|
||||||
|
};
|
||||||
|
|
||||||
|
register_bitfields! {
|
||||||
|
u32,
|
||||||
|
CTRL [
|
||||||
|
KEY OFFSET(1) NUMBITS(12) [
|
||||||
|
Value = 0xA57
|
||||||
|
],
|
||||||
|
RESTART OFFSET(0) NUMBITS(1) []
|
||||||
|
],
|
||||||
|
CFG [
|
||||||
|
CONFIG OFFSET(0) NUMBITS(2) [
|
||||||
|
System = 1,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
MODE [
|
||||||
|
EN OFFSET(0) NUMBITS(1) [],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
Regs {
|
||||||
|
(0x00 => IRQ_EN: ReadWrite<u32>),
|
||||||
|
(0x04 => IRQ_STA: ReadWrite<u32>),
|
||||||
|
(0x08 => _0),
|
||||||
|
(0x10 => CTRL: ReadWrite<u32, CTRL::Register>),
|
||||||
|
(0x14 => CFG: ReadWrite<u32, CFG::Register>),
|
||||||
|
(0x18 => MODE: ReadWrite<u32, MODE::Register>),
|
||||||
|
(0x1C => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RWatchdog {
|
||||||
|
inner: OneTimeInit<IrqSafeSpinlock<DeviceMemoryIo<Regs>>>,
|
||||||
|
base: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InitializableDevice for RWatchdog {
|
||||||
|
type Options = ();
|
||||||
|
|
||||||
|
unsafe fn init(&self, opts: Self::Options) -> Result<(), Error> {
|
||||||
|
let regs = DeviceMemoryIo::map("r_wdog", self.base)?;
|
||||||
|
|
||||||
|
self.inner.init(IrqSafeSpinlock::new(regs));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RWatchdog {
|
||||||
|
pub unsafe fn reset_board(&self) -> ! {
|
||||||
|
let regs = self.inner.get().lock();
|
||||||
|
|
||||||
|
regs.CFG.write(CFG::CONFIG::System);
|
||||||
|
regs.MODE.write(MODE::EN::SET);
|
||||||
|
regs.CTRL.write(CTRL::KEY::Value + CTRL::RESTART::SET);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
core::arch::asm!("wfe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const unsafe fn new(base: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: OneTimeInit::new(),
|
||||||
|
base,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
153
src/arch/aarch64/plat_orange_pi3/serial.rs
Normal file
153
src/arch/aarch64/plat_orange_pi3/serial.rs
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
use abi::{error::Error, io::DeviceRequest};
|
||||||
|
use tock_registers::{
|
||||||
|
interfaces::{Readable, Writeable},
|
||||||
|
register_bitfields, register_structs,
|
||||||
|
registers::{ReadOnly, ReadWrite},
|
||||||
|
};
|
||||||
|
use vfs::CharDevice;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
arch::aarch64::gic::IrqNumber,
|
||||||
|
arch::PLATFORM,
|
||||||
|
debug::DebugSink,
|
||||||
|
device::{
|
||||||
|
interrupt::InterruptSource,
|
||||||
|
platform::Platform,
|
||||||
|
serial::SerialDevice,
|
||||||
|
tty::{CharRing, TtyDevice},
|
||||||
|
Device, InitializableDevice,
|
||||||
|
},
|
||||||
|
mem::device::DeviceMemoryIo,
|
||||||
|
sync::IrqSafeSpinlock,
|
||||||
|
util::OneTimeInit,
|
||||||
|
};
|
||||||
|
|
||||||
|
register_bitfields! {
|
||||||
|
u32,
|
||||||
|
USR [
|
||||||
|
TFE OFFSET(2) NUMBITS(1) [],
|
||||||
|
TFNF OFFSET(1) NUMBITS(1) []
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
Regs {
|
||||||
|
(0x00 => DLL: ReadWrite<u32>),
|
||||||
|
(0x04 => _0),
|
||||||
|
(0x7C => USR: ReadOnly<u32, USR::Register>),
|
||||||
|
(0x80 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Inner {
|
||||||
|
regs: DeviceMemoryIo<Regs>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Serial {
|
||||||
|
inner: OneTimeInit<IrqSafeSpinlock<Inner>>,
|
||||||
|
ring: CharRing<16>,
|
||||||
|
base: usize,
|
||||||
|
irq: IrqNumber,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharDevice for Serial {
|
||||||
|
fn read(&'static self, _blocking: bool, data: &mut [u8]) -> Result<usize, Error> {
|
||||||
|
self.line_read(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, _blocking: bool, data: &[u8]) -> Result<usize, Error> {
|
||||||
|
self.line_write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||||
|
match req {
|
||||||
|
&mut DeviceRequest::SetTerminalGroup(id) => {
|
||||||
|
self.set_signal_group(id as _);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(Error::InvalidArgument),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TtyDevice<16> for Serial {
|
||||||
|
fn ring(&self) -> &CharRing<16> {
|
||||||
|
&self.ring
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterruptSource for Serial {
|
||||||
|
unsafe fn init_irq(&'static self) -> Result<(), Error> {
|
||||||
|
let intc = PLATFORM.interrupt_controller();
|
||||||
|
|
||||||
|
intc.register_handler(self.irq, self)?;
|
||||||
|
intc.enable_irq(self.irq)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_irq(&self) -> Result<bool, Error> {
|
||||||
|
let byte = self.inner.get().lock().regs.DLL.get();
|
||||||
|
|
||||||
|
self.recv_byte(byte as u8);
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugSink for Serial {
|
||||||
|
fn putc(&self, c: u8) -> Result<(), Error> {
|
||||||
|
self.send(c).ok();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerialDevice for Serial {
|
||||||
|
fn send(&self, byte: u8) -> Result<(), Error> {
|
||||||
|
let inner = self.inner.get().lock();
|
||||||
|
if byte == b'\n' {
|
||||||
|
while inner.regs.USR.matches_all(USR::TFE::CLEAR) {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
|
inner.regs.DLL.set(b'\r' as u32);
|
||||||
|
}
|
||||||
|
while inner.regs.USR.matches_all(USR::TFE::CLEAR) {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
|
inner.regs.DLL.set(byte as u32);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive(&self, blocking: bool) -> Result<u8, Error> {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InitializableDevice for Serial {
|
||||||
|
type Options = ();
|
||||||
|
|
||||||
|
unsafe fn init(&self, opts: Self::Options) -> Result<(), Error> {
|
||||||
|
let regs = DeviceMemoryIo::<Regs>::map("h6-uart", self.base)?;
|
||||||
|
self.inner.init(IrqSafeSpinlock::new(Inner { regs }));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for Serial {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"Allwinner H6 UART"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serial {
|
||||||
|
pub const unsafe fn new(base: usize, irq: IrqNumber) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: OneTimeInit::new(),
|
||||||
|
ring: CharRing::new(),
|
||||||
|
|
||||||
|
base,
|
||||||
|
irq,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,14 +22,14 @@ use super::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// AArch64 "virt" platform implementation
|
/// AArch64 "virt" platform implementation
|
||||||
pub struct QemuPlatform {
|
pub struct PlatformImpl {
|
||||||
/// ...
|
/// ...
|
||||||
pub gic: Gic,
|
pub gic: Gic,
|
||||||
pl011: Pl011,
|
pl011: Pl011,
|
||||||
local_timer: ArmTimer,
|
local_timer: ArmTimer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Platform for QemuPlatform {
|
impl Platform for PlatformImpl {
|
||||||
type IrqNumber = IrqNumber;
|
type IrqNumber = IrqNumber;
|
||||||
|
|
||||||
const KERNEL_PHYS_BASE: usize = 0x40080000;
|
const KERNEL_PHYS_BASE: usize = 0x40080000;
|
||||||
@ -78,11 +78,15 @@ impl Platform for QemuPlatform {
|
|||||||
infoln!("TODO send ipi");
|
infoln!("TODO send ipi");
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn reset(&self) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AArch64 "virt" platform
|
/// AArch64 "virt" platform
|
||||||
pub static PLATFORM: QemuPlatform = unsafe {
|
pub static PLATFORM: PlatformImpl = unsafe {
|
||||||
QemuPlatform {
|
PlatformImpl {
|
||||||
pl011: Pl011::new(0x09000000, IrqNumber::new(33)),
|
pl011: Pl011::new(0x09000000, IrqNumber::new(33)),
|
||||||
gic: Gic::new(0x08000000, 0x08010000),
|
gic: Gic::new(0x08000000, 0x08010000),
|
||||||
local_timer: ArmTimer::new(IrqNumber::new(30)),
|
local_timer: ArmTimer::new(IrqNumber::new(30)),
|
||||||
|
@ -7,7 +7,7 @@ use abi::error::Error;
|
|||||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::PLATFORM,
|
arch::{aarch64::gic::IrqNumber, PLATFORM},
|
||||||
device::{
|
device::{
|
||||||
interrupt::InterruptSource, platform::Platform, timer::TimestampSource, Device,
|
interrupt::InterruptSource, platform::Platform, timer::TimestampSource, Device,
|
||||||
InitializableDevice,
|
InitializableDevice,
|
||||||
@ -16,7 +16,7 @@ use crate::{
|
|||||||
task::tasklet,
|
task::tasklet,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{cpu::Cpu, gic::IrqNumber};
|
use super::cpu::Cpu;
|
||||||
|
|
||||||
/// ARM Generic Timer driver
|
/// ARM Generic Timer driver
|
||||||
pub struct ArmTimer {
|
pub struct ArmTimer {
|
||||||
|
@ -20,14 +20,11 @@ macro_rules! absolute_address {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod aarch64;
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(target_arch = "aarch64")] {
|
if #[cfg(target_arch = "aarch64")] {
|
||||||
pub mod aarch64;
|
|
||||||
|
|
||||||
pub use aarch64::plat_qemu::{QemuPlatform as PlatformImpl, PLATFORM};
|
|
||||||
pub use aarch64::{AArch64 as ArchitectureImpl, ARCHITECTURE};
|
|
||||||
|
|
||||||
|
|
||||||
|
pub use aarch64::{AArch64 as ArchitectureImpl, ARCHITECTURE, PlatformImpl, PLATFORM};
|
||||||
} else if #[cfg(target_arch = "x86_64")] {
|
} else if #[cfg(target_arch = "x86_64")] {
|
||||||
pub mod x86_64;
|
pub mod x86_64;
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
|
|
||||||
|
#[cfg(feature = "fb_console")]
|
||||||
pub mod display;
|
pub mod display;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod interrupt;
|
pub mod interrupt;
|
||||||
|
@ -60,4 +60,6 @@ pub trait Platform {
|
|||||||
///
|
///
|
||||||
/// As the call may alter the flow of execution on CPUs, this function is unsafe.
|
/// As the call may alter the flow of execution on CPUs, this function is unsafe.
|
||||||
unsafe fn send_ipi(&self, target: IpiDeliveryTarget, msg: CpuMessage) -> Result<(), Error>;
|
unsafe fn send_ipi(&self, target: IpiDeliveryTarget, msg: CpuMessage) -> Result<(), Error>;
|
||||||
|
|
||||||
|
unsafe fn reset(&self) -> !;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use abi::error::Error;
|
|||||||
|
|
||||||
use super::Device;
|
use super::Device;
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(all(target_arch = "aarch64", not(feature = "aarch64_orange_pi3")))]
|
||||||
pub mod pl011;
|
pub mod pl011;
|
||||||
|
|
||||||
/// Generic serial device interface
|
/// Generic serial device interface
|
||||||
|
@ -9,7 +9,7 @@ use vfs::CharDevice;
|
|||||||
|
|
||||||
use super::SerialDevice;
|
use super::SerialDevice;
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{aarch64::gic::IrqNumber, PLATFORM},
|
arch::{aarch64::gic::IrqNumber, PlatformImpl, PLATFORM},
|
||||||
debug::DebugSink,
|
debug::DebugSink,
|
||||||
device::{
|
device::{
|
||||||
interrupt::InterruptSource,
|
interrupt::InterruptSource,
|
||||||
|
@ -1,91 +1,105 @@
|
|||||||
//! Terminal driver implementation
|
//! Terminal driver implementation
|
||||||
use abi::{
|
use abi::{
|
||||||
error::Error,
|
error::Error,
|
||||||
io::{
|
io::{TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions},
|
||||||
DeviceRequest, TerminalInputOptions, TerminalLineOptions, TerminalOptions,
|
|
||||||
TerminalOutputOptions,
|
|
||||||
},
|
|
||||||
process::Signal,
|
process::Signal,
|
||||||
};
|
};
|
||||||
use vfs::CharDevice;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
device::display::fb_console::FramebufferConsole,
|
|
||||||
proc::wait::Wait,
|
proc::wait::Wait,
|
||||||
sync::IrqSafeSpinlock,
|
sync::IrqSafeSpinlock,
|
||||||
task::{process::Process, ProcessId},
|
task::{process::Process, ProcessId},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::serial::SerialDevice;
|
||||||
display::console::DisplayConsole, input::KeyboardDevice, serial::SerialDevice, Device,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO rewrite this
|
#[cfg(feature = "fb_console")]
|
||||||
/// Helper device to combine a display and a keyboard input into a single terminal
|
pub mod combined {
|
||||||
pub struct CombinedTerminal {
|
use abi::{error::Error, io::DeviceRequest};
|
||||||
#[allow(dead_code)]
|
use vfs::CharDevice;
|
||||||
input: &'static dyn KeyboardDevice,
|
|
||||||
output: &'static dyn DisplayConsole,
|
|
||||||
|
|
||||||
input_ring: CharRing<16>,
|
use crate::device::{
|
||||||
}
|
display::{console::DisplayConsole, fb_console::FramebufferConsole},
|
||||||
|
input::KeyboardDevice,
|
||||||
|
serial::SerialDevice,
|
||||||
|
Device,
|
||||||
|
};
|
||||||
|
|
||||||
impl CombinedTerminal {
|
use super::{CharRing, TtyDevice};
|
||||||
/// Create a combined terminal device from a keyboard and console output devices
|
|
||||||
pub fn new(input: &'static dyn KeyboardDevice, output: &'static FramebufferConsole) -> Self {
|
|
||||||
Self {
|
|
||||||
input,
|
|
||||||
output,
|
|
||||||
input_ring: CharRing::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TtyDevice<16> for CombinedTerminal {
|
// TODO rewrite this
|
||||||
fn ring(&self) -> &CharRing<16> {
|
/// Helper device to combine a display and a keyboard input into a single terminal
|
||||||
&self.input_ring
|
pub struct CombinedTerminal {
|
||||||
}
|
#[allow(dead_code)]
|
||||||
}
|
input: &'static dyn KeyboardDevice,
|
||||||
|
output: &'static dyn DisplayConsole,
|
||||||
|
|
||||||
impl SerialDevice for CombinedTerminal {
|
input_ring: CharRing<16>,
|
||||||
fn receive(&self, _blocking: bool) -> Result<u8, Error> {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send(&self, byte: u8) -> Result<(), Error> {
|
impl CombinedTerminal {
|
||||||
self.output.write_char(byte);
|
/// Create a combined terminal device from a keyboard and console output devices
|
||||||
Ok(())
|
pub fn new(
|
||||||
}
|
input: &'static dyn KeyboardDevice,
|
||||||
}
|
output: &'static FramebufferConsole,
|
||||||
|
) -> Self {
|
||||||
impl Device for CombinedTerminal {
|
Self {
|
||||||
fn name(&self) -> &'static str {
|
input,
|
||||||
"Combined terminal device"
|
output,
|
||||||
}
|
input_ring: CharRing::new(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
impl CharDevice for CombinedTerminal {
|
}
|
||||||
fn read(&'static self, blocking: bool, data: &mut [u8]) -> Result<usize, Error> {
|
|
||||||
assert!(blocking);
|
impl TtyDevice<16> for CombinedTerminal {
|
||||||
self.line_read(data)
|
fn ring(&self) -> &CharRing<16> {
|
||||||
}
|
&self.input_ring
|
||||||
|
}
|
||||||
fn write(&self, blocking: bool, data: &[u8]) -> Result<usize, Error> {
|
}
|
||||||
assert!(blocking);
|
|
||||||
self.line_write(data)
|
impl SerialDevice for CombinedTerminal {
|
||||||
}
|
fn receive(&self, _blocking: bool) -> Result<u8, Error> {
|
||||||
|
todo!()
|
||||||
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
}
|
||||||
match req {
|
|
||||||
&mut DeviceRequest::SetTerminalGroup(id) => {
|
fn send(&self, byte: u8) -> Result<(), Error> {
|
||||||
self.set_signal_group(id as _);
|
self.output.write_char(byte);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for CombinedTerminal {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"Combined terminal device"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharDevice for CombinedTerminal {
|
||||||
|
fn read(&'static self, blocking: bool, data: &mut [u8]) -> Result<usize, Error> {
|
||||||
|
assert!(blocking);
|
||||||
|
self.line_read(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, blocking: bool, data: &[u8]) -> Result<usize, Error> {
|
||||||
|
assert!(blocking);
|
||||||
|
self.line_write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||||
|
match req {
|
||||||
|
&mut DeviceRequest::SetTerminalGroup(id) => {
|
||||||
|
self.set_signal_group(id as _);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(Error::InvalidArgument),
|
||||||
}
|
}
|
||||||
_ => Err(Error::InvalidArgument),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "fb_console")]
|
||||||
|
pub use combined::CombinedTerminal;
|
||||||
|
|
||||||
struct CharRingInner<const N: usize> {
|
struct CharRingInner<const N: usize> {
|
||||||
rd: usize,
|
rd: usize,
|
||||||
wr: usize,
|
wr: usize,
|
||||||
@ -209,7 +223,7 @@ pub trait TtyDevice<const N: usize>: SerialDevice {
|
|||||||
} else if byte == config.chars.erase {
|
} else if byte == config.chars.erase {
|
||||||
// Erase
|
// Erase
|
||||||
if off != 0 {
|
if off != 0 {
|
||||||
self.raw_write(b"\x1b[D \x1b[D");
|
self.raw_write(b"\x1b[D \x1b[D")?;
|
||||||
off -= 1;
|
off -= 1;
|
||||||
rem += 1;
|
rem += 1;
|
||||||
}
|
}
|
||||||
|
15
src/main.rs
15
src/main.rs
@ -22,7 +22,6 @@ use abi::{
|
|||||||
error::Error,
|
error::Error,
|
||||||
io::{FileMode, OpenOptions, RawFd},
|
io::{FileMode, OpenOptions, RawFd},
|
||||||
};
|
};
|
||||||
use device::display::console::task_update_consoles;
|
|
||||||
use fs::{devfs, FileBlockAllocator, INITRD_DATA};
|
use fs::{devfs, FileBlockAllocator, INITRD_DATA};
|
||||||
use memfs::MemoryFilesystem;
|
use memfs::MemoryFilesystem;
|
||||||
use task::tasklet;
|
use task::tasklet;
|
||||||
@ -60,11 +59,15 @@ fn setup_root() -> Result<VnodeRef, Error> {
|
|||||||
/// This function is meant to be used as a kernel-space process after all the platform-specific
|
/// This function is meant to be used as a kernel-space process after all the platform-specific
|
||||||
/// initialization has finished.
|
/// initialization has finished.
|
||||||
pub fn kernel_main() {
|
pub fn kernel_main() {
|
||||||
tasklet::add_periodic(
|
#[cfg(feature = "fb_console")]
|
||||||
"update-console",
|
{
|
||||||
Duration::from_millis(15),
|
use device::display::console::task_update_consoles;
|
||||||
task_update_consoles,
|
tasklet::add_periodic(
|
||||||
);
|
"update-console",
|
||||||
|
Duration::from_millis(15),
|
||||||
|
task_update_consoles,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let root = match setup_root() {
|
let root = match setup_root() {
|
||||||
Ok(root) => root,
|
Ok(root) => root,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Memory management utilities and types
|
//! Memory management utilities and types
|
||||||
// use core::{alloc::Layout, mem::size_of};
|
// use core::{alloc::Layout, mem::size_of};
|
||||||
|
|
||||||
use core::{alloc::Layout, mem::size_of};
|
use core::{alloc::Layout, ffi::c_void, mem::size_of};
|
||||||
|
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
|
|
||||||
@ -286,3 +286,72 @@ pub fn validate_user_region(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C" fn memcpy(p0: *mut c_void, p1: *const c_void, len: usize) -> *mut c_void {
|
||||||
|
let mut offset = 0;
|
||||||
|
while offset < len {
|
||||||
|
let c = (p1 as *const u8).add(offset).read_volatile();
|
||||||
|
(p0 as *mut u8).add(offset).write_volatile(c);
|
||||||
|
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
p0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C" fn memcmp(p0: *const c_void, p1: *const c_void, len: usize) -> i32 {
|
||||||
|
let mut offset = 0;
|
||||||
|
|
||||||
|
if len == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while offset < len {
|
||||||
|
let c0 = (p0 as *const u8).add(offset).read_volatile();
|
||||||
|
let c1 = (p1 as *const u8).add(offset).read_volatile();
|
||||||
|
|
||||||
|
if c0 > c1 {
|
||||||
|
return (c0 - c1) as i32;
|
||||||
|
} else if c0 < c1 {
|
||||||
|
return -((c1 - c0) as i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C" fn memmove(dst: *mut c_void, src: *const c_void, len: usize) -> *mut c_void {
|
||||||
|
if dst as usize == src as usize {
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src.add(len) as usize) <= (dst as usize) || (dst.add(len) as usize) <= (src as usize) {
|
||||||
|
return memcpy(dst, src, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst as usize) < (src as usize) {
|
||||||
|
let a = src as usize - dst as usize;
|
||||||
|
memcpy(dst, src, a);
|
||||||
|
memcpy(src as *mut _, src.add(a), len - a);
|
||||||
|
} else {
|
||||||
|
let a = dst as usize - src as usize;
|
||||||
|
memcpy(dst.add(a), dst, len - a);
|
||||||
|
memcpy(dst, src, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
dst
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C" fn memset(dst: *mut c_void, val: i32, len: usize) -> *mut c_void {
|
||||||
|
let mut offset = 0;
|
||||||
|
while offset < len {
|
||||||
|
(dst as *mut u8).add(offset).write_volatile(val as u8);
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
dst
|
||||||
|
}
|
||||||
|
22
src/panic.rs
22
src/panic.rs
@ -42,19 +42,19 @@ fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
|
|||||||
.compare_exchange(false, true, Ordering::Release, Ordering::Acquire)
|
.compare_exchange(false, true, Ordering::Release, Ordering::Acquire)
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
// Let other CPUs know we're screwed
|
// // Let other CPUs know we're screwed
|
||||||
unsafe {
|
// unsafe {
|
||||||
PLATFORM
|
// PLATFORM
|
||||||
.send_ipi(IpiDeliveryTarget::AllExceptLocal, CpuMessage::Panic)
|
// .send_ipi(IpiDeliveryTarget::AllExceptLocal, CpuMessage::Panic)
|
||||||
.ok();
|
// .ok();
|
||||||
}
|
// }
|
||||||
|
|
||||||
let ap_count = ArchitectureImpl::cpu_count() - 1;
|
// let ap_count = ArchitectureImpl::cpu_count() - 1;
|
||||||
PANIC_HANDLED_FENCE.wait_all(ap_count);
|
// PANIC_HANDLED_FENCE.wait_all(ap_count);
|
||||||
|
|
||||||
unsafe {
|
// unsafe {
|
||||||
hack_locks();
|
// hack_locks();
|
||||||
}
|
// }
|
||||||
|
|
||||||
log_print_raw!(LogLevel::Fatal, "--- BEGIN PANIC ---\n");
|
log_print_raw!(LogLevel::Fatal, "--- BEGIN PANIC ---\n");
|
||||||
log_print_raw!(LogLevel::Fatal, "In CPU {}\n", Cpu::local_id());
|
log_print_raw!(LogLevel::Fatal, "In CPU {}\n", Cpu::local_id());
|
||||||
|
@ -99,7 +99,7 @@ impl<T, const N: usize> StaticVector<T, N> {
|
|||||||
///
|
///
|
||||||
/// Will panic if the vector is full.
|
/// Will panic if the vector is full.
|
||||||
pub fn push(&mut self, value: T) {
|
pub fn push(&mut self, value: T) {
|
||||||
if self.len == N {
|
if self.len >= N {
|
||||||
panic!("Static vector overflow: reached limit of {}", N);
|
panic!("Static vector overflow: reached limit of {}", N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user