1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
//! The static library that forms the core of the kernel.
#![no_std]
use crate::arch::{sleep_forever, PAGE_SIZE, PAGE_SIZE_BITS};
use core::ptr::NonNull;
use log::{debug, info, warn};
use vernos_alloc_buddy::BuddyAllocator;
use vernos_alloc_physmem_free_list::FreeListAllocator;
use vernos_device_tree::FlattenedDeviceTree;
use vernos_utils::dbg;
#[cfg(target_os = "none")]
mod panic;
pub mod arch;
pub mod logger;
/// The first stage of booting the kernel. This should be executed by hart0 alone. It runs with
/// paging disabled, and:
///
/// - sets up a physical memory allocator
/// - sets up paging
/// - allocates some global structures in the higher half of memory:
/// - a logger's buffer
/// - a stack for this kernel thread
/// - the DeviceTree in tree form
///
/// It returns the top address of the stack for this kernel thread.
///
/// # Safety
///
/// - The `device_tree` pointer must be a valid pointer into physical memory. See
/// `device_tree::FlattenedDeviceTree::from_ptr` for the precise requirements.
/// - This must be called in supervisor mode with paging disabled.
/// - Any other harts must not be running concurrently with us.
#[no_mangle]
pub unsafe extern "C" fn hart0_early_boot(device_tree: *const u8) -> ! {
// Set up the logger.
logger::init();
// Parse the DeviceTree.
let flattened_device_tree =
unsafe { FlattenedDeviceTree::from_ptr(device_tree) }.expect("invalid DeviceTree");
// Find the available physical memory areas and initialize the physical memory
// free-list.
let mut physical_memory_free_list = FreeListAllocator::<PAGE_SIZE>::new();
let mut physical_memory_region_count = 0;
flattened_device_tree
.for_each_memory_range::<_, PAGE_SIZE>(|addrs| {
dbg!(&addrs);
let len_bytes = addrs.end - addrs.start;
assert!(addrs.start.trailing_zeros() as usize >= PAGE_SIZE_BITS);
assert!(len_bytes.trailing_zeros() as usize >= PAGE_SIZE_BITS);
// UNWRAP: for_each_memory_range avoids returning the zero address.
let addr = NonNull::new(addrs.start as *mut [u8; PAGE_SIZE]).unwrap();
let len_pages = len_bytes >> PAGE_SIZE_BITS;
physical_memory_free_list.add(addr, len_pages);
physical_memory_region_count += 1;
Ok(())
})
.unwrap_or_else(|err| void::unreachable(err));
// Log the physical memory we found.
debug!(
"found {} usable regions of physical memory{}",
physical_memory_region_count,
if physical_memory_region_count == 0 {
""
} else {
":"
}
);
for (addr, len_pages) in physical_memory_free_list.iter() {
debug!(
"{:p}..{:p} ({} bytes)",
addr.as_ptr(),
addr.as_ptr().wrapping_add(len_pages),
len_pages << PAGE_SIZE_BITS,
)
}
// Initialize the buddy allocator.
let alloc_buddy =
BuddyAllocator::<PAGE_SIZE, PAGE_SIZE_BITS, 19>::new(physical_memory_free_list)
.expect("failed to configure the buddy allocator");
dbg!(alloc_buddy.debug_free_lists());
todo!()
}
/// The entrypoint to the kernel, to be run after paging is set up. This should be executed by
/// hart0 alone. It performs some early boot tasks, then wakes up any other harts.
///
/// It receives the stack canary from the initial stack, and validates it.
///
/// # Safety
///
/// - `hart0_early_boot` must have been called.
/// - This must be called in supervisor mode with traps disabled, but with all traps delegated to
/// supervisor mode.
/// - Any other harts must not be running concurrently with us. TODO: Define their state.
#[no_mangle]
pub unsafe extern "C" fn hart0_boot(stack_canary: u64) -> ! {
assert_eq!(stack_canary, 0xdead0bad0defaced);
/*
// After this point, everything else is for debugging.
#[cfg(target_arch = "riscv64")]
{
flattened_device_tree
.for_each_node(|node| {
if node.is_unit(&["", "cpus"]) {
if let Some(timebase_frequency) = node.get_prop_u32("timebase-frequency") {
// SAFETY: Other harts are not concurrently running, so they can't be
// concurrently accessing or modifying this.
unsafe {
vernos_driver_riscv_timer::TIMEBASE_FREQUENCY = timebase_frequency;
}
}
}
Ok(())
})
.unwrap_or_else(|err| void::unreachable(err));
arch::interrupts::example_timer();
}
*/
if true {
todo!();
}
info!("sleeping forever...");
sleep_forever();
}
|