mirror of
https://github.com/sgmarz/osblog.git
synced 2024-11-24 02:16:19 +04:00
Ran rustfmt
This commit is contained in:
parent
0b2506e8e5
commit
6f333bd8f0
@ -10,35 +10,36 @@ use core::ptr::null_mut;
|
||||
pub enum SatpMode {
|
||||
Off = 0,
|
||||
Sv39 = 8,
|
||||
Sv48 = 9
|
||||
Sv48 = 9,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone,Copy)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct KernelTrapFrame {
|
||||
pub regs: [usize; 32], // 0 - 255
|
||||
pub fregs: [usize; 32], // 256 - 511
|
||||
pub satp: usize, // 512 - 519
|
||||
pub trap_stack: *mut u8, // 520
|
||||
pub hartid: usize, // 528
|
||||
pub regs: [usize; 32], // 0 - 255
|
||||
pub fregs: [usize; 32], // 256 - 511
|
||||
pub satp: usize, // 512 - 519
|
||||
pub trap_stack: *mut u8, // 520
|
||||
pub hartid: usize, // 528
|
||||
}
|
||||
|
||||
impl KernelTrapFrame {
|
||||
pub const fn zero() -> Self {
|
||||
KernelTrapFrame {
|
||||
regs: [0; 32],
|
||||
fregs: [0; 32],
|
||||
satp: 0,
|
||||
trap_stack: null_mut(),
|
||||
hartid: 0
|
||||
}
|
||||
KernelTrapFrame { regs: [0; 32],
|
||||
fregs: [0; 32],
|
||||
satp: 0,
|
||||
trap_stack: null_mut(),
|
||||
hartid: 0, }
|
||||
}
|
||||
}
|
||||
|
||||
pub static mut KERNEL_TRAP_FRAME: [KernelTrapFrame; 8] = [KernelTrapFrame::zero(); 8];
|
||||
pub static mut KERNEL_TRAP_FRAME: [KernelTrapFrame; 8] =
|
||||
[KernelTrapFrame::zero(); 8];
|
||||
|
||||
pub const fn build_satp(mode: SatpMode, asid: usize, addr: usize) -> usize {
|
||||
(mode as usize) << 60 | (asid & 0xffff) << 44 | (addr >> 12) & 0xff_ffff_ffff
|
||||
(mode as usize) << 60
|
||||
| (asid & 0xffff) << 44
|
||||
| (addr >> 12) & 0xff_ffff_ffff
|
||||
}
|
||||
|
||||
pub fn mhartid_read() -> usize {
|
||||
@ -135,7 +136,6 @@ pub fn sepc_read() -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn satp_write(val: usize) {
|
||||
unsafe {
|
||||
asm!("csrw satp, $0" :: "r"(val));
|
||||
|
@ -58,7 +58,6 @@ static mut KMEM_HEAD: *mut AllocList = null_mut();
|
||||
static mut KMEM_ALLOC: usize = 0;
|
||||
static mut KMEM_PAGE_TABLE: *mut Table = null_mut();
|
||||
|
||||
|
||||
// These functions are safe helpers around an unsafe
|
||||
// operation.
|
||||
pub fn get_head() -> *mut u8 {
|
||||
|
@ -254,29 +254,33 @@ extern "C" fn kinit() {
|
||||
// back and forth between the kernel's table and user
|
||||
// applicatons' tables.
|
||||
cpu::mscratch_write(
|
||||
(&mut cpu::KERNEL_TRAP_FRAME[0]
|
||||
as *mut cpu::KernelTrapFrame)
|
||||
as usize,
|
||||
(&mut cpu::KERNEL_TRAP_FRAME[0]
|
||||
as *mut cpu::KernelTrapFrame)
|
||||
as usize,
|
||||
);
|
||||
cpu::sscratch_write(cpu::mscratch_read());
|
||||
cpu::KERNEL_TRAP_FRAME[0].satp = satp_value;
|
||||
// Move the stack pointer to the very bottom. The stack is actually in a
|
||||
// non-mapped page. The stack is decrement-before push and increment after
|
||||
// pop. Therefore, the stack will be allocated (decremented)
|
||||
// before it is stored.
|
||||
cpu::KERNEL_TRAP_FRAME[0].trap_stack = page::zalloc(1).add(page::PAGE_SIZE);
|
||||
// Move the stack pointer to the very bottom. The stack is
|
||||
// actually in a non-mapped page. The stack is decrement-before
|
||||
// push and increment after pop. Therefore, the stack will be
|
||||
// allocated (decremented) before it is stored.
|
||||
cpu::KERNEL_TRAP_FRAME[0].trap_stack =
|
||||
page::zalloc(1).add(page::PAGE_SIZE);
|
||||
id_map_range(
|
||||
&mut root,
|
||||
cpu::KERNEL_TRAP_FRAME[0].trap_stack.sub(page::PAGE_SIZE) as usize,
|
||||
cpu::KERNEL_TRAP_FRAME[0].trap_stack as usize,
|
||||
page::EntryBits::ReadWrite.val(),
|
||||
&mut root,
|
||||
cpu::KERNEL_TRAP_FRAME[0].trap_stack
|
||||
.sub(page::PAGE_SIZE,)
|
||||
as usize,
|
||||
cpu::KERNEL_TRAP_FRAME[0].trap_stack as usize,
|
||||
page::EntryBits::ReadWrite.val(),
|
||||
);
|
||||
// The trap frame itself is stored in the mscratch register.
|
||||
id_map_range(
|
||||
&mut root,
|
||||
cpu::mscratch_read(),
|
||||
cpu::mscratch_read() + core::mem::size_of::<cpu::KernelTrapFrame>(),
|
||||
page::EntryBits::ReadWrite.val(),
|
||||
&mut root,
|
||||
cpu::mscratch_read(),
|
||||
cpu::mscratch_read()
|
||||
+ core::mem::size_of::<cpu::KernelTrapFrame,>(),
|
||||
page::EntryBits::ReadWrite.val(),
|
||||
);
|
||||
page::print_page_allocations();
|
||||
let p = cpu::KERNEL_TRAP_FRAME[0].trap_stack as usize - 1;
|
||||
@ -302,16 +306,17 @@ extern "C" fn kinit_hart(hartid: usize) {
|
||||
// back and forth between the kernel's table and user
|
||||
// applicatons' tables.
|
||||
cpu::mscratch_write(
|
||||
(&mut cpu::KERNEL_TRAP_FRAME[hartid]
|
||||
as *mut cpu::KernelTrapFrame)
|
||||
as usize,
|
||||
(&mut cpu::KERNEL_TRAP_FRAME[hartid]
|
||||
as *mut cpu::KernelTrapFrame)
|
||||
as usize,
|
||||
);
|
||||
// Copy the same mscratch over to the supervisor version of the same
|
||||
// register.
|
||||
// Copy the same mscratch over to the supervisor version of the
|
||||
// same register.
|
||||
cpu::sscratch_write(cpu::mscratch_read());
|
||||
cpu::KERNEL_TRAP_FRAME[hartid].hartid = hartid;
|
||||
// We can't do the following until zalloc() is locked, but we don't have locks, yet :(
|
||||
// cpu::KERNEL_TRAP_FRAME[hartid].satp = cpu::KERNEL_TRAP_FRAME[0].satp;
|
||||
// We can't do the following until zalloc() is locked, but we
|
||||
// don't have locks, yet :( cpu::KERNEL_TRAP_FRAME[hartid].satp
|
||||
// = cpu::KERNEL_TRAP_FRAME[0].satp;
|
||||
// cpu::KERNEL_TRAP_FRAME[hartid].trap_stack = page::zalloc(1);
|
||||
}
|
||||
}
|
||||
|
@ -398,7 +398,12 @@ impl Table {
|
||||
/// The bits MUST include one or more of the following:
|
||||
/// Read, Write, Execute
|
||||
/// The valid bit automatically gets added.
|
||||
pub fn map(root: &mut Table, vaddr: usize, paddr: usize, bits: i64, level: usize) {
|
||||
pub fn map(root: &mut Table,
|
||||
vaddr: usize,
|
||||
paddr: usize,
|
||||
bits: i64,
|
||||
level: usize)
|
||||
{
|
||||
// Make sure that Read, Write, or Execute have been provided
|
||||
// otherwise, we'll leak memory and always create a page fault.
|
||||
assert!(bits & 0xe != 0);
|
||||
@ -463,8 +468,8 @@ pub fn map(root: &mut Table, vaddr: usize, paddr: usize, bits: i64, level: usize
|
||||
EntryBits::Dirty.val() | // Some machines require this to =1
|
||||
EntryBits::Access.val() // Just like dirty, some machines require this
|
||||
;
|
||||
// Set the entry. V should be set to the correct pointer by the loop
|
||||
// above.
|
||||
// Set the entry. V should be set to the correct pointer by the loop
|
||||
// above.
|
||||
v.set_entry(entry);
|
||||
}
|
||||
|
||||
@ -482,7 +487,8 @@ pub fn unmap(root: &mut Table) {
|
||||
// This is a valid entry, so drill down and free.
|
||||
let memaddr_lv1 = (entry_lv2.get_entry() & !0x3ff) << 2;
|
||||
let table_lv1 = unsafe {
|
||||
// Make table_lv1 a mutable reference instead of a pointer.
|
||||
// Make table_lv1 a mutable reference instead of
|
||||
// a pointer.
|
||||
(memaddr_lv1 as *mut Table).as_mut().unwrap()
|
||||
};
|
||||
for lv1 in 0..Table::len() {
|
||||
|
@ -3,34 +3,51 @@
|
||||
// Stephen Marz
|
||||
// 10 October 2019
|
||||
|
||||
|
||||
use crate::cpu::KernelTrapFrame;
|
||||
|
||||
#[no_mangle]
|
||||
extern "C"
|
||||
fn s_trap(epc: usize, tval: usize, cause: usize, hart: usize, stat: usize, frame: &mut KernelTrapFrame) -> usize {
|
||||
extern "C" fn s_trap(epc: usize,
|
||||
tval: usize,
|
||||
cause: usize,
|
||||
hart: usize,
|
||||
stat: usize,
|
||||
frame: &mut KernelTrapFrame)
|
||||
-> usize
|
||||
{
|
||||
println!("STRAP (cause: {} @ 0x{:x}) [cpu: {}]", cause, epc, hart);
|
||||
epc + 4
|
||||
epc + 4
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C"
|
||||
fn m_trap(epc: usize, tval: usize, cause: usize, hart: usize, stat: usize, frame: &mut KernelTrapFrame) -> usize {
|
||||
// println!("MTRAP ({}) (cause: 0x{:x} @ 0x{:x}) [0x{:x}]", hart, cause, epc, stat);
|
||||
// println!("Stack = {:p}", &frame.trap_stack);
|
||||
// Only machine timers should come here. Everything else should be brought to supervisor
|
||||
// mode (s_trap).
|
||||
extern "C" fn m_trap(epc: usize,
|
||||
tval: usize,
|
||||
cause: usize,
|
||||
hart: usize,
|
||||
stat: usize,
|
||||
frame: &mut KernelTrapFrame)
|
||||
-> usize
|
||||
{
|
||||
// println!("MTRAP ({}) (cause: 0x{:x} @ 0x{:x}) [0x{:x}]", hart, cause,
|
||||
// epc, stat); println!("Stack = {:p}", &frame.trap_stack);
|
||||
// Only machine timers should come here. Everything else should be
|
||||
// brought to supervisor mode (s_trap).
|
||||
if cause == 0x8000_0000_0000_0007 {
|
||||
unsafe {
|
||||
let addr = 0x0200_4000 + hart * 8;
|
||||
let mtimecmp = addr as *mut u64;
|
||||
let mtime = 0x0200_bff8 as *const u64;
|
||||
mtimecmp.write_volatile(mtime.read_volatile() + 10_000_000);
|
||||
mtimecmp.write_volatile(
|
||||
mtime.read_volatile()
|
||||
+ 10_000_000,
|
||||
);
|
||||
asm!("csrw sip, $0" ::"r"(2));
|
||||
}
|
||||
epc
|
||||
}
|
||||
else {
|
||||
panic!("Non-timer machine interrupt: 0x{:x} on hart {}", cause, hart)
|
||||
panic!(
|
||||
"Non-timer machine interrupt: 0x{:x} on hart {}",
|
||||
cause, hart
|
||||
)
|
||||
}
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
// uart.rs
|
||||
// UART routines and driver
|
||||
|
||||
use core::convert::TryInto;
|
||||
use core::fmt::Write;
|
||||
use core::fmt::Error;
|
||||
use core::{convert::TryInto,
|
||||
fmt::{Error, Write}};
|
||||
|
||||
pub struct Uart {
|
||||
base_address: usize,
|
||||
@ -20,9 +19,7 @@ impl Write for Uart {
|
||||
|
||||
impl Uart {
|
||||
pub fn new(base_address: usize) -> Self {
|
||||
Uart {
|
||||
base_address
|
||||
}
|
||||
Uart { base_address }
|
||||
}
|
||||
|
||||
pub fn init(&mut self) {
|
||||
@ -32,28 +29,32 @@ impl Uart {
|
||||
// are bits 0 and 1 of the line control register (LCR)
|
||||
// which is at base_address + 3
|
||||
// We can easily write the value 3 here or 0b11, but I'm
|
||||
// extending it so that it is clear we're setting two individual
|
||||
// fields
|
||||
// extending it so that it is clear we're setting two
|
||||
// individual fields
|
||||
// Word 0 Word 1
|
||||
// ~~~~~~ ~~~~~~
|
||||
let lcr: u8 = (1 << 0) | (1 << 1);
|
||||
let lcr: u8 = (1 << 0) | (1 << 1);
|
||||
ptr.add(3).write_volatile(lcr);
|
||||
|
||||
// Now, enable the FIFO, which is bit index 0 of the FIFO
|
||||
// control register (FCR at offset 2).
|
||||
// Again, we can just write 1 here, but when we use left shift,
|
||||
// it's easier to see that we're trying to write bit index #0.
|
||||
// Now, enable the FIFO, which is bit index 0 of the
|
||||
// FIFO control register (FCR at offset 2).
|
||||
// Again, we can just write 1 here, but when we use left
|
||||
// shift, it's easier to see that we're trying to write
|
||||
// bit index #0.
|
||||
ptr.add(2).write_volatile(1 << 0);
|
||||
|
||||
// Enable receiver buffer interrupts, which is at bit index
|
||||
// 0 of the interrupt enable register (IER at offset 1).
|
||||
// Enable receiver buffer interrupts, which is at bit
|
||||
// index 0 of the interrupt enable register (IER at
|
||||
// offset 1).
|
||||
ptr.add(1).write_volatile(1 << 0);
|
||||
|
||||
// If we cared about the divisor, the code below would set the divisor
|
||||
// from a global clock rate of 22.729 MHz (22,729,000 cycles per second)
|
||||
// to a signaling rate of 2400 (BAUD). We usually have much faster signalling
|
||||
// rates nowadays, but this demonstrates what the divisor actually does.
|
||||
// The formula given in the NS16500A specification for calculating the divisor
|
||||
// If we cared about the divisor, the code below would
|
||||
// set the divisor from a global clock rate of 22.729
|
||||
// MHz (22,729,000 cycles per second) to a signaling
|
||||
// rate of 2400 (BAUD). We usually have much faster
|
||||
// signalling rates nowadays, but this demonstrates what
|
||||
// the divisor actually does. The formula given in the
|
||||
// NS16500A specification for calculating the divisor
|
||||
// is:
|
||||
// divisor = ceil( (clock_hz) / (baud_sps x 16) )
|
||||
// So, we substitute our values and get:
|
||||
@ -61,30 +62,39 @@ impl Uart {
|
||||
// divisor = ceil( 22_729_000 / 38_400 )
|
||||
// divisor = ceil( 591.901 ) = 592
|
||||
|
||||
// The divisor register is two bytes (16 bits), so we need to split the value
|
||||
// 592 into two bytes. Typically, we would calculate this based on measuring
|
||||
// the clock rate, but again, for our purposes [qemu], this doesn't really do
|
||||
// anything.
|
||||
// The divisor register is two bytes (16 bits), so we
|
||||
// need to split the value 592 into two bytes.
|
||||
// Typically, we would calculate this based on measuring
|
||||
// the clock rate, but again, for our purposes [qemu],
|
||||
// this doesn't really do anything.
|
||||
let divisor: u16 = 592;
|
||||
let divisor_least: u8 = (divisor & 0xff).try_into().unwrap();
|
||||
let divisor_most: u8 = (divisor >> 8).try_into().unwrap();
|
||||
let divisor_least: u8 =
|
||||
(divisor & 0xff).try_into().unwrap();
|
||||
let divisor_most: u8 =
|
||||
(divisor >> 8).try_into().unwrap();
|
||||
|
||||
// Notice that the divisor register DLL (divisor latch least) and DLM (divisor latch most)
|
||||
// have the same base address as the receiver/transmitter and the interrupt enable register.
|
||||
// To change what the base address points to, we open the "divisor latch" by writing 1 into
|
||||
// the Divisor Latch Access Bit (DLAB), which is bit index 7 of the Line Control Register (LCR)
|
||||
// which is at base_address + 3.
|
||||
// Notice that the divisor register DLL (divisor latch
|
||||
// least) and DLM (divisor latch most) have the same
|
||||
// base address as the receiver/transmitter and the
|
||||
// interrupt enable register. To change what the base
|
||||
// address points to, we open the "divisor latch" by
|
||||
// writing 1 into the Divisor Latch Access Bit (DLAB),
|
||||
// which is bit index 7 of the Line Control Register
|
||||
// (LCR) which is at base_address + 3.
|
||||
ptr.add(3).write_volatile(lcr | 1 << 7);
|
||||
|
||||
// Now, base addresses 0 and 1 point to DLL and DLM, respectively.
|
||||
// Put the lower 8 bits of the divisor into DLL
|
||||
// Now, base addresses 0 and 1 point to DLL and DLM,
|
||||
// respectively. Put the lower 8 bits of the divisor
|
||||
// into DLL
|
||||
ptr.add(0).write_volatile(divisor_least);
|
||||
ptr.add(1).write_volatile(divisor_most);
|
||||
|
||||
// Now that we've written the divisor, we never have to touch this again. In hardware, this
|
||||
// will divide the global clock (22.729 MHz) into one suitable for 2,400 signals per second.
|
||||
// So, to once again get access to the RBR/THR/IER registers, we need to close the DLAB bit
|
||||
// by clearing it to 0.
|
||||
// Now that we've written the divisor, we never have to
|
||||
// touch this again. In hardware, this will divide the
|
||||
// global clock (22.729 MHz) into one suitable for 2,400
|
||||
// signals per second. So, to once again get access to
|
||||
// the RBR/THR/IER registers, we need to close the DLAB
|
||||
// bit by clearing it to 0.
|
||||
ptr.add(3).write_volatile(lcr);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user