mirror of
https://github.com/iceHtwoO/novaOS.git
synced 2026-04-16 20:22:26 +00:00
feat: UART terminal (#7)
* feat: basic terminal * feat: execute application via terminal
This commit is contained in:
committed by
GitHub
parent
34a66ff87a
commit
f33100d36b
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ sd.img
|
|||||||
settings.json
|
settings.json
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.venv
|
.venv
|
||||||
|
.nvimlog
|
||||||
|
|||||||
9
.vscode/launch.json
vendored
9
.vscode/launch.json
vendored
@@ -58,15 +58,12 @@
|
|||||||
],
|
],
|
||||||
"preLaunchTask": "Run QEMU wo window"
|
"preLaunchTask": "Run QEMU wo window"
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "Attach LLDB",
|
"name": "LLDB",
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
"request": "attach",
|
"request": "launch",
|
||||||
"debugServer": 1234,
|
|
||||||
"program": "${workspaceFolder}/target/aarch64-unknown-none/debug/nova",
|
"program": "${workspaceFolder}/target/aarch64-unknown-none/debug/nova",
|
||||||
"stopOnEntry": true,
|
"preLaunchTask": "Run QEMU wo window"
|
||||||
"processCreateCommands": ["gdb-remote localhost:1234"]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -40,12 +40,19 @@ version = "0.2.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nova"
|
name = "nova"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heap",
|
"heap",
|
||||||
"libm",
|
"libm",
|
||||||
|
"log",
|
||||||
"nova_error",
|
"nova_error",
|
||||||
"paste",
|
"paste",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ libm = "0.2.15"
|
|||||||
heap = {path = "workspace/heap"}
|
heap = {path = "workspace/heap"}
|
||||||
nova_error = {path = "workspace/nova_error"}
|
nova_error = {path = "workspace/nova_error"}
|
||||||
paste = "1.0.15"
|
paste = "1.0.15"
|
||||||
|
log = "0.4.29"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,18 @@ pub enum PhysSource {
|
|||||||
#[repr(align(4096))]
|
#[repr(align(4096))]
|
||||||
pub struct PageTable([TableEntry; TABLE_ENTRY_COUNT]);
|
pub struct PageTable([TableEntry; TABLE_ENTRY_COUNT]);
|
||||||
|
|
||||||
|
impl Iterator for PageTable {
|
||||||
|
type Item = VirtAddr;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
for (offset, entity) in self.0.iter().enumerate() {
|
||||||
|
if entity.is_invalid() {
|
||||||
|
return Some(offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static mut TRANSLATIONTABLE_TTBR0: PageTable = PageTable([TableEntry { value: 0 }; 512]);
|
pub static mut TRANSLATIONTABLE_TTBR0: PageTable = PageTable([TableEntry { value: 0 }; 512]);
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -197,7 +209,7 @@ fn map_range_dynamic(
|
|||||||
|
|
||||||
/// Allocate a singe page.
|
/// Allocate a singe page.
|
||||||
pub fn alloc_page(
|
pub fn alloc_page(
|
||||||
virtual_address: usize,
|
virtual_address: VirtAddr,
|
||||||
base_table: *mut PageTable,
|
base_table: *mut PageTable,
|
||||||
additional_flags: u64,
|
additional_flags: u64,
|
||||||
) -> Result<(), NovaError> {
|
) -> Result<(), NovaError> {
|
||||||
@@ -209,6 +221,28 @@ pub fn alloc_page(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocate a singe page in one block.
|
||||||
|
pub fn find_free_kerne_page_in_block(start: VirtAddr) -> Result<VirtAddr, NovaError> {
|
||||||
|
if !start.is_multiple_of(GRANULARITY) {
|
||||||
|
return Err(NovaError::Misalignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (off1, off2, _) = virtual_address_to_table_offset(start);
|
||||||
|
let offsets = [off1, off2];
|
||||||
|
let table = unsafe {
|
||||||
|
&mut *navigate_table(
|
||||||
|
core::ptr::addr_of_mut!(TRANSLATIONTABLE_TTBR1),
|
||||||
|
&offsets,
|
||||||
|
true,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(virt_addr) = table.next() {
|
||||||
|
return Ok(virt_addr);
|
||||||
|
}
|
||||||
|
Err(NovaError::OutOfMeomory)
|
||||||
|
}
|
||||||
|
|
||||||
/// Allocate a single page at an explicit `physical_address`.
|
/// Allocate a single page at an explicit `physical_address`.
|
||||||
pub fn alloc_page_explicit(
|
pub fn alloc_page_explicit(
|
||||||
virtual_address: usize,
|
virtual_address: usize,
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ configure_mmu_el1:
|
|||||||
.align 4
|
.align 4
|
||||||
.global el1_to_el0
|
.global el1_to_el0
|
||||||
el1_to_el0:
|
el1_to_el0:
|
||||||
|
mov x8, x0
|
||||||
// Set SPSR_EL1: return to EL0t
|
// Set SPSR_EL1: return to EL0t
|
||||||
mov x0, #(0b0000)
|
mov x0, #(0b0000)
|
||||||
msr SPSR_EL1, x0
|
msr SPSR_EL1, x0
|
||||||
@@ -93,5 +93,6 @@ el1_to_el0:
|
|||||||
|
|
||||||
isb
|
isb
|
||||||
|
|
||||||
|
mov x0, x8
|
||||||
// Return to EL0
|
// Return to EL0
|
||||||
eret
|
eret
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ pub const EL0_STACK_SIZE: usize = LEVEL2_BLOCK_SIZE * 2;
|
|||||||
pub const MAILBOX_VIRTUAL_ADDRESS: VirtAddr = 0xFFFF_FF81_FFFF_E000;
|
pub const MAILBOX_VIRTUAL_ADDRESS: VirtAddr = 0xFFFF_FF81_FFFF_E000;
|
||||||
pub static mut MAILBOX_PHYSICAL_ADDRESS: Option<PhysAddr> = None;
|
pub static mut MAILBOX_PHYSICAL_ADDRESS: Option<PhysAddr> = None;
|
||||||
|
|
||||||
|
pub const APPLICATION_TRANSLATION_TABLE_VA: VirtAddr = 0xFFFF_FF81_FE00_0000;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static __text_end: u64;
|
static __text_end: u64;
|
||||||
static __share_end: u64;
|
static __share_end: u64;
|
||||||
@@ -99,6 +101,7 @@ pub fn initialize_mmu_translation_tables() {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
// Allocate Mailbox buffer
|
||||||
{
|
{
|
||||||
let addr = reserve_page();
|
let addr = reserve_page();
|
||||||
unsafe { MAILBOX_PHYSICAL_ADDRESS = Some(addr) };
|
unsafe { MAILBOX_PHYSICAL_ADDRESS = Some(addr) };
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ mod bitmaps;
|
|||||||
|
|
||||||
use bitmaps::BASIC_LEGACY;
|
use bitmaps::BASIC_LEGACY;
|
||||||
|
|
||||||
use crate::{
|
use crate::pi3::mailbox::{read_mailbox, write_mailbox};
|
||||||
pi3::mailbox::{read_mailbox, write_mailbox},
|
use log::error;
|
||||||
println,
|
|
||||||
};
|
|
||||||
#[repr(align(16))]
|
#[repr(align(16))]
|
||||||
struct Mailbox([u32; 36]);
|
struct Mailbox([u32; 36]);
|
||||||
|
|
||||||
@@ -237,7 +235,7 @@ impl Default for FrameBuffer {
|
|||||||
|
|
||||||
let _ = read_mailbox(8);
|
let _ = read_mailbox(8);
|
||||||
if mailbox.0[1] == 0 {
|
if mailbox.0[1] == 0 {
|
||||||
println!("Failed");
|
error!("Mailbox request was not processed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
mailbox.0[28] &= 0x3FFFFFFF;
|
mailbox.0[28] &= 0x3FFFFFFF;
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ use core::arch::asm;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
aarch64::registers::{daif::mask_all, read_esr_el1, read_exception_source_el},
|
aarch64::registers::{daif::mask_all, read_esr_el1, read_exception_source_el},
|
||||||
get_current_el, println,
|
get_current_el,
|
||||||
};
|
};
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
const INTERRUPT_BASE: u32 = 0x3F00_B000;
|
const INTERRUPT_BASE: u32 = 0x3F00_B000;
|
||||||
const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204;
|
const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204;
|
||||||
@@ -66,17 +67,17 @@ unsafe extern "C" fn rust_synchronous_interrupt_no_el_change() {
|
|||||||
mask_all();
|
mask_all();
|
||||||
|
|
||||||
let source_el = read_exception_source_el() >> 2;
|
let source_el = read_exception_source_el() >> 2;
|
||||||
println!("--------Sync Exception in EL{}--------", source_el);
|
debug!("--------Sync Exception in EL{}--------", source_el);
|
||||||
println!("No EL change");
|
debug!("No EL change");
|
||||||
println!("Current EL: {}", get_current_el());
|
debug!("Current EL: {}", get_current_el());
|
||||||
println!("{:?}", EsrElX::from(read_esr_el1()));
|
debug!("{:?}", EsrElX::from(read_esr_el1()));
|
||||||
println!("Return register address: {:#x}", read_esr_el1());
|
debug!("Return register address: {:#x}", read_esr_el1());
|
||||||
println!("-------------------------------------");
|
debug!("-------------------------------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_return_to_kernel_main() {
|
fn set_return_to_kernel_loop() {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("ldr x0, =kernel_main", "msr ELR_EL1, x0");
|
asm!("ldr x0, =kernel_loop", "msr ELR_EL1, x0");
|
||||||
asm!("mov x0, #(0b0101)", "msr SPSR_EL1, x0");
|
asm!("mov x0, #(0b0101)", "msr SPSR_EL1, x0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ use crate::{
|
|||||||
gpio::{read_gpio_event_detect_status, reset_gpio_event_detect_status},
|
gpio::{read_gpio_event_detect_status, reset_gpio_event_detect_status},
|
||||||
uart::clear_uart_interrupt_state,
|
uart::clear_uart_interrupt_state,
|
||||||
},
|
},
|
||||||
println, read_address, write_address,
|
read_address, write_address,
|
||||||
};
|
};
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use log::{debug, info};
|
||||||
|
|
||||||
struct InterruptHandlers {
|
struct InterruptHandlers {
|
||||||
source: IRQSource,
|
source: IRQSource,
|
||||||
function: fn(),
|
function: fn(),
|
||||||
@@ -60,9 +62,9 @@ unsafe extern "C" fn rust_irq_handler() {
|
|||||||
if pending_irqs & GPIO_PENDING_BIT_OFFSET != 0 {
|
if pending_irqs & GPIO_PENDING_BIT_OFFSET != 0 {
|
||||||
handle_gpio_interrupt();
|
handle_gpio_interrupt();
|
||||||
let source_el = read_exception_source_el() >> 2;
|
let source_el = read_exception_source_el() >> 2;
|
||||||
println!("Source EL: {}", source_el);
|
debug!("Source EL: {}", source_el);
|
||||||
println!("Current EL: {}", get_current_el());
|
debug!("Current EL: {}", get_current_el());
|
||||||
println!("Return register address: {:#x}", read_esr_el1());
|
debug!("Return register address: {:#x}", read_esr_el1());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(handler_vec) = unsafe { &*core::ptr::addr_of_mut!(INTERRUPT_HANDLERS) } {
|
if let Some(handler_vec) = unsafe { &*core::ptr::addr_of_mut!(INTERRUPT_HANDLERS) } {
|
||||||
@@ -76,7 +78,7 @@ unsafe extern "C" fn rust_irq_handler() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_gpio_interrupt() {
|
fn handle_gpio_interrupt() {
|
||||||
println!("Interrupt");
|
debug!("GPIO interrupt triggered");
|
||||||
for i in 0..=53u32 {
|
for i in 0..=53u32 {
|
||||||
let val = read_gpio_event_detect_status(i);
|
let val = read_gpio_event_detect_status(i);
|
||||||
|
|
||||||
@@ -84,7 +86,7 @@ fn handle_gpio_interrupt() {
|
|||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
match i {
|
match i {
|
||||||
26 => {
|
26 => {
|
||||||
println!("Button Pressed");
|
info!("Button Pressed");
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
aarch64::registers::{daif::mask_all, read_elr_el1, read_esr_el1, read_exception_source_el},
|
aarch64::registers::{daif::mask_all, read_elr_el1, read_esr_el1, read_exception_source_el},
|
||||||
get_current_el,
|
get_current_el,
|
||||||
interrupt_handlers::{set_return_to_kernel_main, EsrElX, TrapFrame},
|
interrupt_handlers::{set_return_to_kernel_loop, EsrElX, TrapFrame},
|
||||||
pi3::mailbox,
|
pi3::mailbox,
|
||||||
println,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use log::{debug, error, warn};
|
||||||
|
|
||||||
/// Synchronous Exception Handler
|
/// Synchronous Exception Handler
|
||||||
///
|
///
|
||||||
/// Source is a lower Exception level, where the implemented level
|
/// Source is a lower Exception level, where the implemented level
|
||||||
@@ -15,22 +16,23 @@ use crate::{
|
|||||||
unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64(frame: &mut TrapFrame) -> usize {
|
unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64(frame: &mut TrapFrame) -> usize {
|
||||||
mask_all();
|
mask_all();
|
||||||
let esr: EsrElX = EsrElX::from(read_esr_el1());
|
let esr: EsrElX = EsrElX::from(read_esr_el1());
|
||||||
|
debug!("Synchronous interrupt from lower EL triggered");
|
||||||
|
log_sync_exception();
|
||||||
match esr.ec {
|
match esr.ec {
|
||||||
0b100100 => {
|
0b100100 => {
|
||||||
log_sync_exception();
|
warn!("Cause: Data Abort from a lower Exception level");
|
||||||
println!("Cause: Data Abort from a lower Exception level");
|
|
||||||
}
|
}
|
||||||
0b010101 => {
|
0b010101 => {
|
||||||
println!("Cause: SVC instruction execution in AArch64");
|
debug!("Cause: SVC instruction execution in AArch64");
|
||||||
return handle_svc(frame);
|
return handle_svc(frame);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unknown Error Code: {:b}", esr.ec);
|
error!("Synchronous interrupt: Unknown Error Code: {:b}", esr.ec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("Returning to kernel main...");
|
|
||||||
|
|
||||||
set_return_to_kernel_main();
|
warn!("UnhandledException -> Returning to kernel...");
|
||||||
|
set_return_to_kernel_loop();
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,11 +48,11 @@ fn handle_svc(frame: &mut TrapFrame) -> usize {
|
|||||||
|
|
||||||
fn log_sync_exception() {
|
fn log_sync_exception() {
|
||||||
let source_el = read_exception_source_el() >> 2;
|
let source_el = read_exception_source_el() >> 2;
|
||||||
println!("--------Sync Exception in EL{}--------", source_el);
|
debug!("--------Sync Exception in EL{}--------", source_el);
|
||||||
println!("Exception escalated to EL {}", get_current_el());
|
debug!("Exception escalated to EL {}", get_current_el());
|
||||||
println!("Current EL: {}", get_current_el());
|
debug!("Current EL: {}", get_current_el());
|
||||||
let esr: EsrElX = EsrElX::from(read_esr_el1());
|
let esr: EsrElX = EsrElX::from(read_esr_el1());
|
||||||
println!("{:?}", esr);
|
debug!("{:?}", esr);
|
||||||
println!("Return address: {:#x}", read_elr_el1());
|
debug!("Return address: {:#x}", read_elr_el1());
|
||||||
println!("-------------------------------------");
|
debug!("-------------------------------------");
|
||||||
}
|
}
|
||||||
|
|||||||
45
src/lib.rs
45
src/lib.rs
@@ -3,12 +3,13 @@
|
|||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
use core::{
|
use core::{
|
||||||
arch::asm,
|
arch::asm,
|
||||||
panic::PanicInfo,
|
panic::PanicInfo,
|
||||||
ptr::{read_volatile, write_volatile},
|
ptr::{read_volatile, write_volatile},
|
||||||
};
|
};
|
||||||
|
use log::LevelFilter;
|
||||||
|
use log::{Level, Metadata, Record};
|
||||||
|
|
||||||
use heap::Heap;
|
use heap::Heap;
|
||||||
|
|
||||||
@@ -18,10 +19,11 @@ use crate::{
|
|||||||
WRITABLE,
|
WRITABLE,
|
||||||
},
|
},
|
||||||
interrupt_handlers::irq::initialize_interrupt_handler,
|
interrupt_handlers::irq::initialize_interrupt_handler,
|
||||||
logger::DefaultLogger,
|
|
||||||
pi3::timer::sleep_s,
|
pi3::timer::sleep_s,
|
||||||
|
terminal::{flush_terminal, init_terminal},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static LOGGER: UartLogger = UartLogger;
|
||||||
static PERIPHERAL_BASE: usize = 0x3F00_0000;
|
static PERIPHERAL_BASE: usize = 0x3F00_0000;
|
||||||
|
|
||||||
unsafe extern "C" {
|
unsafe extern "C" {
|
||||||
@@ -31,7 +33,7 @@ unsafe extern "C" {
|
|||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
pub static mut GLOBAL_ALLOCATOR: Heap = Heap::empty();
|
pub static mut GLOBAL_ALLOCATOR: Heap = Heap::empty();
|
||||||
|
|
||||||
pub unsafe fn init_kernel_heap() {
|
pub unsafe fn initialize_kernel_heap() {
|
||||||
let start = core::ptr::addr_of_mut!(__kernel_end) as usize | KERNEL_VIRTUAL_MEM_SPACE;
|
let start = core::ptr::addr_of_mut!(__kernel_end) as usize | KERNEL_VIRTUAL_MEM_SPACE;
|
||||||
let size = LEVEL2_BLOCK_SIZE * 2;
|
let size = LEVEL2_BLOCK_SIZE * 2;
|
||||||
|
|
||||||
@@ -54,9 +56,9 @@ pub mod aarch64;
|
|||||||
pub mod configuration;
|
pub mod configuration;
|
||||||
pub mod framebuffer;
|
pub mod framebuffer;
|
||||||
pub mod interrupt_handlers;
|
pub mod interrupt_handlers;
|
||||||
pub mod logger;
|
|
||||||
|
|
||||||
pub mod pi3;
|
pub mod pi3;
|
||||||
|
pub mod terminal;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn read_address(address: u32) -> u32 {
|
pub unsafe fn read_address(address: u32) -> u32 {
|
||||||
@@ -80,14 +82,33 @@ pub fn get_current_el() -> u64 {
|
|||||||
el >> 2
|
el >> 2
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut KERNEL_INITIALIZED: bool = false;
|
|
||||||
|
|
||||||
pub fn initialize_kernel() {
|
pub fn initialize_kernel() {
|
||||||
if unsafe { KERNEL_INITIALIZED } {
|
unsafe { initialize_kernel_heap() };
|
||||||
return;
|
|
||||||
}
|
|
||||||
unsafe { init_kernel_heap() };
|
|
||||||
logger::set_logger(Box::new(DefaultLogger));
|
|
||||||
initialize_interrupt_handler();
|
initialize_interrupt_handler();
|
||||||
unsafe { KERNEL_INITIALIZED = true };
|
init_terminal();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UartLogger;
|
||||||
|
|
||||||
|
impl log::Log for UartLogger {
|
||||||
|
fn enabled(&self, metadata: &Metadata) -> bool {
|
||||||
|
metadata.level() <= Level::Debug
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(&self, record: &Record) {
|
||||||
|
if self.enabled(record.metadata()) {
|
||||||
|
println!("{} - {}", record.level(), record.args());
|
||||||
|
if record.level() <= Level::Info {
|
||||||
|
flush_terminal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_logger() {
|
||||||
|
log::set_logger(&LOGGER)
|
||||||
|
.map(|()| log::set_max_level(LevelFilter::Debug))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
use core::fmt::Write;
|
|
||||||
|
|
||||||
use alloc::{boxed::Box, fmt};
|
|
||||||
|
|
||||||
use crate::peripherals::uart;
|
|
||||||
|
|
||||||
static mut LOGGER: Option<Box<dyn Logger>> = None;
|
|
||||||
|
|
||||||
pub trait Logger: Write + Sync {
|
|
||||||
fn flush(&mut self);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DefaultLogger;
|
|
||||||
|
|
||||||
impl Logger for DefaultLogger {
|
|
||||||
fn flush(&mut self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Write for DefaultLogger {
|
|
||||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
|
||||||
uart::Uart.write_str(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! log {
|
|
||||||
() => {};
|
|
||||||
($($arg:tt)*) => {
|
|
||||||
$crate::logger::log(format_args!($($arg)*))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn log(args: fmt::Arguments) {
|
|
||||||
if let Some(logger) = unsafe { &mut *core::ptr::addr_of_mut!(LOGGER) } {
|
|
||||||
logger.write_str("\n").unwrap();
|
|
||||||
logger.write_fmt(args).unwrap();
|
|
||||||
logger.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_logger(logger: Box<dyn Logger>) {
|
|
||||||
unsafe {
|
|
||||||
LOGGER = Some(logger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
65
src/main.rs
65
src/main.rs
@@ -6,6 +6,7 @@ use core::{
|
|||||||
arch::{asm, global_asm},
|
arch::{asm, global_asm},
|
||||||
ptr::write_volatile,
|
ptr::write_volatile,
|
||||||
};
|
};
|
||||||
|
use log::{debug, info};
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ use nova::{
|
|||||||
aarch64::registers::{daif, read_id_aa64mmfr0_el1},
|
aarch64::registers::{daif, read_id_aa64mmfr0_el1},
|
||||||
configuration::memory_mapping::initialize_mmu_translation_tables,
|
configuration::memory_mapping::initialize_mmu_translation_tables,
|
||||||
framebuffer::{FrameBuffer, BLUE, GREEN, RED},
|
framebuffer::{FrameBuffer, BLUE, GREEN, RED},
|
||||||
get_current_el,
|
get_current_el, init_logger,
|
||||||
interrupt_handlers::irq::{enable_irq_source, IRQSource},
|
interrupt_handlers::irq::{enable_irq_source, IRQSource},
|
||||||
peripherals::{
|
peripherals::{
|
||||||
gpio::{
|
gpio::{
|
||||||
@@ -23,7 +24,7 @@ use nova::{
|
|||||||
},
|
},
|
||||||
uart::uart_init,
|
uart::uart_init,
|
||||||
},
|
},
|
||||||
println,
|
print, println,
|
||||||
};
|
};
|
||||||
|
|
||||||
global_asm!(include_str!("vector.S"));
|
global_asm!(include_str!("vector.S"));
|
||||||
@@ -33,7 +34,6 @@ static mut FRAMEBUFFER: Option<FrameBuffer> = None;
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn el2_to_el1();
|
fn el2_to_el1();
|
||||||
fn el1_to_el0();
|
|
||||||
fn configure_mmu_el1();
|
fn configure_mmu_el1();
|
||||||
static mut __bss_start: u32;
|
static mut __bss_start: u32;
|
||||||
static mut __bss_end: u32;
|
static mut __bss_end: u32;
|
||||||
@@ -60,16 +60,18 @@ pub extern "C" fn main() -> ! {
|
|||||||
|
|
||||||
// Set ACT Led to Outout
|
// Set ACT Led to Outout
|
||||||
let _ = set_gpio_function(21, GPIOFunction::Output);
|
let _ = set_gpio_function(21, GPIOFunction::Output);
|
||||||
|
init_logger();
|
||||||
|
|
||||||
println!("Hello World!");
|
info!("Hello World!");
|
||||||
println!("Exception level: {}", get_current_el());
|
info!("Current exception level: {}", get_current_el());
|
||||||
|
|
||||||
|
info!("initializing MMU...");
|
||||||
initialize_mmu_translation_tables();
|
initialize_mmu_translation_tables();
|
||||||
unsafe { configure_mmu_el1() };
|
unsafe { configure_mmu_el1() };
|
||||||
println!("MMU initialized...");
|
info!("MMU configured!");
|
||||||
|
|
||||||
println!("Register: AA64MMFR0_EL1: {:064b}", read_id_aa64mmfr0_el1());
|
debug!("Register: AA64MMFR0_EL1: {:064b}", read_id_aa64mmfr0_el1());
|
||||||
println!("Moving El2->EL1");
|
info!("Moving El2->EL1");
|
||||||
unsafe { FRAMEBUFFER = Some(FrameBuffer::default()) };
|
unsafe { FRAMEBUFFER = Some(FrameBuffer::default()) };
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -89,28 +91,32 @@ unsafe fn zero_bss() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn kernel_main() -> ! {
|
pub extern "C" fn kernel_main() {
|
||||||
println!("Kernel Start...");
|
|
||||||
nova::initialize_kernel();
|
nova::initialize_kernel();
|
||||||
|
info!("Kernel Initialized...");
|
||||||
|
info!("Current exception Level: {}", get_current_el());
|
||||||
|
|
||||||
let mut test_vector = Vec::new();
|
let mut test_vector = Vec::new();
|
||||||
for i in 0..20 {
|
for i in 0..20 {
|
||||||
test_vector.push(i);
|
test_vector.push(i);
|
||||||
}
|
}
|
||||||
println!("heap allocation test: {:?}", test_vector);
|
debug!("heap allocation test: {:?}", test_vector);
|
||||||
|
|
||||||
println!("Exception Level: {}", get_current_el());
|
enable_irq_source(IRQSource::UartInt);
|
||||||
|
|
||||||
|
kernel_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn kernel_loop() {
|
||||||
daif::unmask_all();
|
daif::unmask_all();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
el1_to_el0();
|
|
||||||
};
|
|
||||||
|
|
||||||
#[allow(clippy::empty_loop)]
|
#[allow(clippy::empty_loop)]
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn el0() -> ! {
|
pub extern "C" fn el0(input: usize) {
|
||||||
println!("Jumped into EL0");
|
println!("Jumped into EL0");
|
||||||
|
|
||||||
// Set GPIO 26 to Input
|
// Set GPIO 26 to Input
|
||||||
@@ -119,8 +125,6 @@ pub extern "C" fn el0() -> ! {
|
|||||||
gpio_pull_up(26);
|
gpio_pull_up(26);
|
||||||
set_falling_edge_detect(26, true);
|
set_falling_edge_detect(26, true);
|
||||||
|
|
||||||
enable_irq_source(IRQSource::UartInt);
|
|
||||||
|
|
||||||
if let Some(fb) = unsafe { FRAMEBUFFER.as_mut() } {
|
if let Some(fb) = unsafe { FRAMEBUFFER.as_mut() } {
|
||||||
for i in 0..1080 {
|
for i in 0..1080 {
|
||||||
fb.draw_pixel(50, i, BLUE);
|
fb.draw_pixel(50, i, BLUE);
|
||||||
@@ -134,12 +138,27 @@ pub extern "C" fn el0() -> ! {
|
|||||||
fb.draw_function(cos, 0, 101, RED);
|
fb.draw_function(cos, 0, 101, RED);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
let _temp = syscall(67);
|
||||||
let temp = syscall(67);
|
|
||||||
println!("{} °C", temp / 1000);
|
println!("Calculting prime to: {}", input);
|
||||||
|
|
||||||
|
for i in 3..input {
|
||||||
|
let mut is_prime = true;
|
||||||
|
for j in 3..i {
|
||||||
|
if i == j {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if i % j == 0 {
|
||||||
|
is_prime = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if is_prime {
|
||||||
|
print!("{} ", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
|
||||||
blink_gpio(SpecificGpio::OnboardLed as u8, 500);
|
blink_gpio(SpecificGpio::OnboardLed as u8, 500);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cos(x: u32) -> f64 {
|
fn cos(x: u32) -> f64 {
|
||||||
|
|||||||
@@ -1,53 +1,92 @@
|
|||||||
use core::fmt::Write;
|
use core::arch::asm;
|
||||||
|
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use nova::{
|
|
||||||
interrupt_handlers::register_interrupt_handler, logger::Logger,
|
use crate::{
|
||||||
peripherals::uart::read_uart_data, print, println,
|
interrupt_handlers::irq::{register_interrupt_handler, IRQSource},
|
||||||
|
peripherals::uart::read_uart_data,
|
||||||
|
pi3::mailbox::read_soc_temp,
|
||||||
|
print, println,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub static mut TERMINAL: Option<Terminal> = None;
|
||||||
|
|
||||||
pub struct Terminal {
|
pub struct Terminal {
|
||||||
buffer: String,
|
|
||||||
input: String,
|
input: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn el1_to_el0();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Terminal {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Terminal {
|
impl Terminal {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
buffer: String::new(),
|
|
||||||
input: String::new(),
|
input: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&mut self) {
|
fn flush(&mut self) {
|
||||||
println!("{}", self.buffer);
|
print!("\n> {}", self.input);
|
||||||
print!("> {}", self.input);
|
}
|
||||||
self.buffer.clear();
|
|
||||||
|
fn exec(&mut self) {
|
||||||
|
print!("\n");
|
||||||
|
let val = self.input.clone();
|
||||||
|
self.input.clear();
|
||||||
|
|
||||||
|
match val.as_str() {
|
||||||
|
"temp" => {
|
||||||
|
println!("{}", read_soc_temp([0]).unwrap()[1]);
|
||||||
|
}
|
||||||
|
"el0" => unsafe {
|
||||||
|
let i = 69;
|
||||||
|
asm!("", in("x0") i);
|
||||||
|
el1_to_el0();
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
println!("Unknown command: \"{}\"", self.input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.input.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Write for Terminal {
|
pub fn init_terminal() {
|
||||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
unsafe { TERMINAL = Some(Terminal::new()) };
|
||||||
self.buffer.push_str(s);
|
register_terminal_interrupt_handler();
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Logger for Terminal {
|
|
||||||
fn flush(&mut self) {
|
|
||||||
println!("{}", self.buffer);
|
|
||||||
print!("> {}", self.input);
|
|
||||||
self.buffer.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminal_uart_rx_interrupt_handler() {
|
fn terminal_uart_rx_interrupt_handler() {
|
||||||
print!("{}", read_uart_data());
|
let input = read_uart_data();
|
||||||
|
#[allow(static_mut_refs)]
|
||||||
|
if let Some(term) = unsafe { TERMINAL.as_mut() } {
|
||||||
|
match input {
|
||||||
|
'\r' => {
|
||||||
|
term.exec();
|
||||||
|
term.flush();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
term.input.push(input);
|
||||||
|
print!("{}", input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_terminal_interrupt_handler() {
|
pub fn flush_terminal() {
|
||||||
register_interrupt_handler(
|
#[allow(static_mut_refs)]
|
||||||
nova::interrupt_handlers::IRQSource::UartInt,
|
if let Some(term) = unsafe { TERMINAL.as_mut() } {
|
||||||
terminal_uart_rx_interrupt_handler,
|
term.flush();
|
||||||
);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_terminal_interrupt_handler() {
|
||||||
|
register_interrupt_handler(IRQSource::UartInt, terminal_uart_rx_interrupt_handler);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,4 +11,5 @@ pub enum NovaError {
|
|||||||
Misalignment,
|
Misalignment,
|
||||||
InvalidGranularity,
|
InvalidGranularity,
|
||||||
Paging,
|
Paging,
|
||||||
|
OutOfMeomory,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user