Compare commits
4 commits
1ff52acc42
...
304152dbeb
Author | SHA1 | Date | |
---|---|---|---|
gil | 304152dbeb | ||
gil | e7060b38bd | ||
gil | 9e180a565a | ||
gil | c7ccdc371d |
2
build.rs
2
build.rs
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Tell ld to use linker script.
|
// Tell ld to use linker script.
|
||||||
println!("cargo::rustc-link-arg=-Tsrc/script.ld");
|
println!("cargo::rustc-link-arg=-Tsrc/script.lds");
|
||||||
// Don't do any magic linker stuff.
|
// Don't do any magic linker stuff.
|
||||||
println!("cargo::rustc-link-arg=--omagic");
|
println!("cargo::rustc-link-arg=--omagic");
|
||||||
}
|
}
|
||||||
|
|
75
src/entry.rs
75
src/entry.rs
|
@ -1,16 +1,75 @@
|
||||||
use crate::abort;
|
// src/entry.rs
|
||||||
|
#[no_mangle]
|
||||||
|
#[link_section = ".text.init"]
|
||||||
|
unsafe extern "C" fn _entry() {
|
||||||
|
use core::arch::asm;
|
||||||
|
// let id = riscv::register::mhartid::read();
|
||||||
|
// write_tp(&id);
|
||||||
|
// TODO set up stack for all harts
|
||||||
|
// TODO set up CSRs for all harts
|
||||||
|
// if id != 0 { abort(); }
|
||||||
|
|
||||||
|
asm!(
|
||||||
|
/* Global pointer register `gp`
|
||||||
|
|
||||||
|
Push current option stack to temporarily disable relaxation, load
|
||||||
|
_global_pointer symbol (provided by linker), then pop option stack.
|
||||||
|
|
||||||
|
Important to keep relaxation off for this instruction, so that
|
||||||
|
the instruction is emitted as:
|
||||||
|
1:
|
||||||
|
auipc gp, %pcrel_hi(_global_pointer)
|
||||||
|
addi gp, gp, %pcrel_lo(1b)"
|
||||||
|
instead of:
|
||||||
|
mv gp, gp
|
||||||
|
which would do nothing. */
|
||||||
|
".option push",
|
||||||
|
".option norelax",
|
||||||
|
"la gp, _global_pointer",
|
||||||
|
".option pop",
|
||||||
|
);
|
||||||
|
|
||||||
|
riscv::register::satp::write(0);
|
||||||
|
|
||||||
unsafe extern "C" fn _enter() {
|
|
||||||
let id = riscv::register::mhartid::read();
|
let id = riscv::register::mhartid::read();
|
||||||
write_tp(&id);
|
if id != 0 { crate::abort(); }
|
||||||
// TODO: set up stack for all harts
|
|
||||||
// TODO: set up CSRs for all harts
|
|
||||||
if id != 0 { abort(); }
|
|
||||||
|
|
||||||
// TODO: clear BSS
|
// Clear BSS section
|
||||||
// TODO: do hardware inits and wake other harts
|
asm!(
|
||||||
|
"la t0, _bss_start",
|
||||||
|
"la t1, _bss_end",
|
||||||
|
"bgeu t0, t1, 2f",
|
||||||
|
"1:",
|
||||||
|
"sb zero, 0(t0)",
|
||||||
|
"addi t0, t0, 1",
|
||||||
|
"bne t0, t1, 1b",
|
||||||
|
|
||||||
|
"2:",
|
||||||
|
"la sp, _stack_end",
|
||||||
|
|
||||||
|
"li t0, (0b11 << 11) | (1 << 13)",
|
||||||
|
"csrw mstatus, t0",
|
||||||
|
"csrw mie, x0",
|
||||||
|
|
||||||
|
"la t1, {kinit}",
|
||||||
|
"csrw mepc, t1",
|
||||||
|
|
||||||
|
"la ra, 2f",
|
||||||
|
"mret",
|
||||||
|
"2:",
|
||||||
|
kinit = sym kinit,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn kinit() {
|
||||||
|
use crate::uart;
|
||||||
|
uart::Device::new(0x1000_0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn kinit_hart() {}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn write_tp(id: &usize) {
|
unsafe fn write_tp(id: &usize) {
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
|
|
12
src/heap.rs
12
src/heap.rs
|
@ -14,23 +14,23 @@ static ALLOCATOR: LockedHeap = LockedHeap::empty();
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// Must be called at most once.
|
/// Must be called at most once.
|
||||||
pub unsafe fn init() {
|
pub unsafe fn init() {
|
||||||
let heap_bottom;
|
let heap_start;
|
||||||
let heap_size;
|
let heap_size;
|
||||||
// UNSAFE: This is fine, just loading some constants.
|
// UNSAFE: This is fine, just loading some constants.
|
||||||
unsafe {
|
unsafe {
|
||||||
// using inline assembly is easier to access linker constants
|
// using inline assembly is easier to access linker constants
|
||||||
asm!(
|
asm!(
|
||||||
"la {heap_bottom}, _kernel_heap_bottom",
|
"la {heap_start}, _heap_start",
|
||||||
"la {heap_size}, _kernel_heap_size",
|
"la {heap_size}, _heap_size",
|
||||||
heap_bottom = out(reg) heap_bottom,
|
heap_start = out(reg) heap_start,
|
||||||
heap_size = out(reg) heap_size,
|
heap_size = out(reg) heap_size,
|
||||||
options(nomem)
|
options(nomem)
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
println!(
|
println!(
|
||||||
"Initialising kernel heap (bottom: {:#x}, size: {:#x})",
|
"Initialising kernel heap (bottom: {:#x}, size: {:#x})",
|
||||||
heap_bottom as usize, heap_size
|
heap_start as usize, heap_size
|
||||||
);
|
);
|
||||||
// UNSAFE: Fine to call at most once.
|
// UNSAFE: Fine to call at most once.
|
||||||
unsafe { ALLOCATOR.lock().init(heap_bottom, heap_size) };
|
unsafe { ALLOCATOR.lock().init(heap_start, heap_size) };
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ unsafe extern "C" fn _enter() -> ! {
|
||||||
"csrw mideleg, t5", // delegate all machine interrupts
|
"csrw mideleg, t5", // delegate all machine interrupts
|
||||||
|
|
||||||
// set the stack pointer
|
// set the stack pointer
|
||||||
"la sp, _init_stack_top",
|
"la sp, _stack_end",
|
||||||
|
|
||||||
// Make sure machine mode is set, and enable coarse interrupts
|
// Make sure machine mode is set, and enable coarse interrupts
|
||||||
"li t0, (0b11 << 11) | (1 << 7) | (1 << 3)",
|
"li t0, (0b11 << 11) | (1 << 7) | (1 << 3)",
|
||||||
|
@ -96,7 +96,7 @@ extern "C" fn start() -> ! {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// println!("This should not print because the console is not initialised.");
|
// println!("This should not print because the console is not initialised.");
|
||||||
unsafe { uart::init_console(0x1000_0000) };
|
uart::init_console(0x1000_0000);
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
|
|
||||||
// print current hartid
|
// print current hartid
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# src/script.ld
|
/* src/script.lds */
|
||||||
|
|
||||||
OUTPUT_ARCH("riscv")
|
OUTPUT_ARCH("riscv")
|
||||||
ENTRY(_enter)
|
ENTRY(_enter)
|
||||||
|
@ -17,18 +17,25 @@ SECTIONS {
|
||||||
. = ORIGIN(ram); # start at 0x8000_0000 (DRAM)
|
. = ORIGIN(ram); # start at 0x8000_0000 (DRAM)
|
||||||
|
|
||||||
.text : { # put code first
|
.text : { # put code first
|
||||||
|
PROVIDE(_text_start = .);
|
||||||
*(.text.init) # start with anything in the .text.init section
|
*(.text.init) # start with anything in the .text.init section
|
||||||
*(.text .text.*) # then put anything else in .text
|
*(.text .text.*) # then put anything else in .text
|
||||||
|
PROVIDE(_text_end = .);
|
||||||
} >ram AT>ram :text # put this section into the text segment
|
} >ram AT>ram :text # put this section into the text segment
|
||||||
|
|
||||||
PROVIDE(_global_pointer = .); # this is magic, google "linker relaxation"
|
PROVIDE(_global_pointer = .); # this is magic, google "linker relaxation"
|
||||||
|
|
||||||
.rodata : { # next, read-only data
|
.rodata : { # next, read-only data
|
||||||
|
PROVIDE(_rodata_start = .);
|
||||||
*(.rodata .rodata.*)
|
*(.rodata .rodata.*)
|
||||||
|
PROVIDE(_rodata_end = .);
|
||||||
} >ram AT>ram :text # goes into the text segment as well (since instructions are generally read-only)
|
} >ram AT>ram :text # goes into the text segment as well (since instructions are generally read-only)
|
||||||
|
|
||||||
.data : { # and the data section
|
.data : { # and the data section
|
||||||
|
. = ALIGN(4096);
|
||||||
|
PROVIDE(_data_start = .);
|
||||||
*(.sdata .sdata.*) *(.data .data.*)
|
*(.sdata .sdata.*) *(.data .data.*)
|
||||||
|
PROVIDE(_data_end = .);
|
||||||
} >ram AT>ram :data # this will go into the data segment
|
} >ram AT>ram :data # this will go into the data segment
|
||||||
|
|
||||||
.bss :{ # finally, the BSS
|
.bss :{ # finally, the BSS
|
||||||
|
@ -37,10 +44,14 @@ SECTIONS {
|
||||||
PROVIDE(_bss_end = .); # ... and one at the end
|
PROVIDE(_bss_end = .); # ... and one at the end
|
||||||
} >ram AT>ram :bss # and this goes into the bss segment
|
} >ram AT>ram :bss # and this goes into the bss segment
|
||||||
|
|
||||||
. = ALIGN(16); # our stack needs to be 16-byte aligned, per the C calling convention
|
PROVIDE(_memory_start = ORIGIN(ram));
|
||||||
PROVIDE(_init_stack_top = . + 0x1000); # reserve 0x1000 bytes (4 kB) for the initialisation stack
|
|
||||||
|
|
||||||
PROVIDE(_kernel_heap_bottom = _init_stack_top); # allocate heap to remaining physical memory
|
. = ALIGN(16); # stack is 16-byte aligned, per the C calling convention
|
||||||
PROVIDE(_kernel_heap_top = ORIGIN(ram) + LENGTH(ram)); # top of heap is end of ram
|
PROVIDE(_stack_start = .);
|
||||||
PROVIDE(_kernel_heap_size = _kernel_heap_top - _kernel_heap_bottom); # capture size of heap
|
PROVIDE(_stack_end = _stack_start + 0x80000); # reserve 0x80000 bytes for the stack
|
||||||
|
|
||||||
|
PROVIDE(_memory_end = ORIGIN(ram) + LENGTH(ram));
|
||||||
|
|
||||||
|
PROVIDE(_heap_start = _stack_end); # allocate heap to remaining physical memory
|
||||||
|
PROVIDE(_heap_size = _memory_end - _heap_start); # capture size of heap
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@ impl Device {
|
||||||
/// Create a new UART device.
|
/// Create a new UART device.
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// `base` must be the base address of a UART device.
|
/// `base` must be the base address of a UART device.
|
||||||
pub unsafe fn new(base: usize) -> Self {
|
pub fn new(base: usize) -> Self {
|
||||||
use core::ptr::write_volatile;
|
use core::ptr::write_volatile;
|
||||||
let addr = base as *mut u8;
|
let addr = base as *mut u8;
|
||||||
// Set data size to 8 bits.
|
// Set data size to 8 bits.
|
||||||
|
@ -64,9 +64,9 @@ impl core::fmt::Write for Device {
|
||||||
/// Initialise the UART debugging console.
|
/// Initialise the UART debugging console.
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// `base` must point to the base address of a UART device.
|
/// `base` must point to the base address of a UART device.
|
||||||
pub unsafe fn init_console(base: usize) {
|
pub fn init_console(base: usize) {
|
||||||
let mut console = CONSOLE.lock();
|
let mut console: spinning_top::lock_api::MutexGuard<spinning_top::RawSpinlock, Option<Device>> = CONSOLE.lock();
|
||||||
*console = Some(unsafe { Device::new(base) });
|
*console = Some(Device::new(base));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a formatted string to the [CONSOLE].
|
/// Prints a formatted string to the [CONSOLE].
|
||||||
|
|
Loading…
Reference in a new issue