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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
| #![no_std]
#![no_main]
extern crate alloc;
use alloc::vec::Vec;
use core::panic::PanicInfo;
use core::sync::atomic::{AtomicU64, Ordering};
use linked_list_allocator::LockedHeap;
use rustbelt::arch::aarch64::{self as arch, board, console, dtb, exceptions, mmio, paging, timer};
use rustbelt::println;
const HEAP_SIZE: usize = 1 << 20;
#[repr(C, align(4096))]
struct HeapSpace([u8; HEAP_SIZE]);
static mut HEAP_SPACE: HeapSpace = HeapSpace([0; HEAP_SIZE]);
#[global_allocator]
static HEAP: LockedHeap = LockedHeap::empty();
const VIRT_DTB: usize = 0x4000_0000;
const TICK_HZ: u64 = 100;
static MARKER: AtomicU64 = AtomicU64::new(0);
#[unsafe(no_mangle)]
pub extern "C" fn kmain(dtb_arg: usize, boot_el: u64) -> ! {
let b = board::current();
console::puts_raw(arch::BANNER);
exceptions::init();
unsafe { paging::init(b) };
println!("[boot] {} board, Cortex-A53; entered at EL{}, running at EL{}", b.name(), boot_el, arch::current_el());
println!("[boot] exception vectors installed (VBAR_EL1)");
MARKER.store(0x5ca1_ab1e, Ordering::SeqCst);
let through_high = unsafe { core::ptr::read_volatile(paging::high(&MARKER as *const _ as usize) as *const u64) };
mmio::use_high_half(paging::HIGH_BASE);
println!(
"[mmu] on ({}): 4 KiB granule, identity map + higher half at {:#x}; a word at {:#x} reads {:#x} through {:#x}",
if paging::enabled() { "SCTLR_EL1.M = 1" } else { "NOT ON?" },
paging::HIGH_BASE,
&MARKER as *const _ as usize,
through_high,
paging::high(&MARKER as *const _ as usize)
);
println!("[mmu] devices are now reached through the higher half (this line went to the UART at {:#x})", mmio::virt(0x0900_0000));
unsafe { HEAP.lock().init(&raw mut HEAP_SPACE as usize, HEAP_SIZE) };
let numbers: Vec<u64> = (1..=1000).collect();
println!("[heap] {} KiB at {:#x}; a Vec of 1..=1000 sums to {}", HEAP_SIZE >> 10, &raw const HEAP_SPACE as usize, numbers.iter().sum::<u64>());
let dtb_addr = if dtb_arg != 0 { dtb_arg } else { VIRT_DTB };
let fdt = unsafe { dtb::Fdt::at(dtb_addr) };
match &fdt {
Some(f) => println!("[dtb] device tree at {:#x}, {} bytes", dtb_addr, f.size()),
None => println!("[dtb] no device tree at {:#x}", dtb_addr),
}
for line in b.configure(fdt.as_ref()) {
println!("[dtb] {}", line);
}
if let Some(f) = &fdt {
list_virtio(f);
}
#[cfg(feature = "aarch64-fault")]
{
println!("[fault] reading 0x10_0000_0000 on purpose (--features aarch64-fault)");
let v = unsafe { core::ptr::read_volatile(0x10_0000_0000 as *const u64) };
println!("[fault] read {:#x}?! the exception handler should have stopped us", v);
}
b.irq().init();
b.irq().enable(b.timer_irq());
timer::start(TICK_HZ);
exceptions::enable();
println!("[timer] generic timer at {} Hz, ticking {} times a second (INTID {})", timer::frequency(), TICK_HZ, b.timer_irq());
let start = timer::counter();
let mut shown = 0;
while timer::ticks() < 100 {
unsafe { core::arch::asm!("wfi") };
let t = timer::ticks();
if t > shown && shown < 5 {
shown = t;
println!("[timer] tick {}", t);
}
}
let ms = (timer::counter() - start) * 1000 / timer::frequency();
println!("[timer] 100 ticks took {} ms (should be about 1000)", ms);
println!("[exit] bring-up done; leaving QEMU through semihosting SYS_EXIT, status 0");
arch::exit(0)
}
fn list_virtio(f: &dtb::Fdt) {
let mut slots = 0;
let mut found = Vec::new();
f.for_each_node(|n| {
if n.is_compatible("virtio,mmio") {
if let Some((base, _)) = n.reg(0) {
slots += 1;
let base = base as usize;
let (magic, version, id) = (mmio::read32(base), mmio::read32(base + 4), mmio::read32(base + 8));
if magic == 0x7472_6976 && id != 0 {
found.push((base, version, id));
}
}
}
});
found.sort();
println!("[virtio] {} virtio-mmio slots, {} in use", slots, found.len());
for (base, version, id) in found {
let name = match id {
1 => "network card",
2 => "block device",
3 => "console",
4 => "entropy source (rng)",
16 => "GPU",
18 => "input",
_ => "other",
};
println!("[virtio] {:#x}: device ID {} ({}), virtio-mmio version {}", base, id, name, version);
}
}
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
unsafe { console::force_unlock() };
println!("[panic] {}", info);
arch::exit(2)
}
|