-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.rs
157 lines (132 loc) · 4.28 KB
/
main.rs
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
153
154
155
156
157
// Copyright 2021 The Firefly Authors.
//
// Use of this source code is governed by a BSD 3-clause
// license that can be found in the LICENSE file.
// This is the entry point for the kernel, which
// runs the kernel's standard initialisation,
// then either runs tests or starts kmain,
// where the kernel does its real work.
#![no_std]
#![no_main]
#![deny(clippy::float_arithmetic)]
#![deny(clippy::inline_asm_x86_att_syntax)]
#![deny(clippy::missing_panics_doc)]
#![allow(clippy::panic)]
#![deny(clippy::return_self_not_must_use)]
#![deny(clippy::single_char_lifetime_names)]
#![deny(clippy::wildcard_imports)]
#![deny(unused_crate_dependencies)]
extern crate alloc;
use alloc::string::ToString;
use alloc::{format, vec};
use bootinfo::{entry_point, BootInfo};
use core::panic::PanicInfo;
use filesystem::{FileType, Permissions};
use memory::PageTable;
use multitasking::process::Process;
use multitasking::thread::Thread;
use multitasking::{scheduler, thread};
use serial::println;
use storage::block;
use x86_64::instructions::{hlt, interrupts};
/// This function is called on panic.
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
println!("{}", info);
loop {
interrupts::disable();
hlt();
}
}
entry_point!(kmain);
fn kmain(boot_info: &'static BootInfo) -> ! {
println!("Kernel booting...");
kernel::init(boot_info);
println!("Kernel ready!");
println!("Kernel booted at {}.", time::boot_time());
cpu::print_branding();
// Check that we have the devices necessary
// to do something useful.
if network::with_interfaces(|i| i.is_empty()) {
println!("No network interfaces identified. Shutting down.");
power::shutdown();
}
if block::with_devices(|d| d.is_empty()) {
println!("No storage devices identified. Shutting down.");
power::shutdown();
}
// Set up our initial workload for when
// we get a DHCP configuration.
let workload =
Thread::create_kernel_thread(initial_workload, "initial workload starter".to_string());
network::register_workload(workload.waker());
// Hand over to the scheduler.
scheduler::start();
}
fn initial_workload() -> ! {
println!("Starting initial workload.");
block::iter_devices(|dev| {
// Read the first block to see whether we
// need to advance the device.
if dev.segment_size() != 512 {
return;
}
let mut block = [0u8; 512];
if let Ok(n) = dev.read(0, &mut block) {
if n != 512 {
return;
}
} else {
return;
}
let offset = if block[511] == 0xaa && block[510] == 0x55 {
let offset = u32::from_le_bytes([block[506], block[507], block[508], block[509]]);
offset as usize / 512
} else {
0
};
// Read the archive.
let mut reader = tar::Reader::new_at_offset(dev, offset);
let initial_workload = (&mut reader)
.find(|f| {
let info = f.info();
info.size > 0
&& info.file_type == FileType::RegularFile
&& info.permissions.contains(Permissions::EXECUTE)
&& info.name == "initial-workload"
})
.expect("initial workload not found");
let info = initial_workload.info();
let mut data = vec![0u8; info.size];
let n = reader
.read(&initial_workload, &mut data[..])
.expect(format!("failed to read {}", info.name).as_str());
if n != info.size {
panic!(
"failed to read {}: got {} bytes, want {}",
info.name, n, info.size
);
}
match Process::create_user_process(&info.name, &data[..]) {
Ok((_, thread_id)) => {
thread_id.resume();
}
Err(s) => panic!("failed to start process: {:?}", s),
}
});
// We've started any processes, so we
// can stop here and leave the rest
// to the scheduler.
thread::exit();
}
#[allow(dead_code)]
fn debug() {
println!();
// Virtual memory.
println!("Virtual memory manager:");
virtmem::debug(&PageTable::current());
println!();
// Physical memory.
physmem::debug();
println!();
}