-
Notifications
You must be signed in to change notification settings - Fork 18
/
main.rs
238 lines (198 loc) · 7.53 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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
use std::{
sync::atomic::{AtomicBool, Ordering},
thread::{sleep, spawn},
};
use abi::bbqueue_ipc::BBBuffer;
use clap::Parser;
use melpomene::{
cli::{self, MelpomeneOptions},
sim_drivers::{delay::Delay, tcp_serial::TcpSerial},
};
use mnemos_kernel::{
drivers::serial_mux::{SerialMux, SerialMuxHandle},
Kernel, KernelSettings,
};
use tokio::{
task,
time::{self, Duration},
};
use tracing::Instrument;
const HEAP_SIZE: usize = 192 * 1024;
static KERNEL_LOCK: AtomicBool = AtomicBool::new(true);
fn main() {
let args = cli::Args::parse();
args.tracing.setup_tracing();
let _span = tracing::info_span!("Melpo").entered();
run_melpomene(args.melpomene);
}
#[tokio::main(flavor = "current_thread")]
async fn run_melpomene(opts: cli::MelpomeneOptions) {
println!("========================================");
let kernel = task::spawn_blocking(move || {
kernel_entry(opts);
});
tracing::info!("Kernel started.");
// Wait for the kernel to complete initialization...
while KERNEL_LOCK.load(Ordering::Acquire) {
task::yield_now().await;
}
tracing::debug!("Kernel initialized.");
// let userspace = spawn(move || {
// userspace_entry();
// });
// println!("[Melpo]: Userspace started.");
// println!("========================================");
// let uj = userspace.join();
println!("========================================");
time::sleep(Duration::from_millis(50)).await;
// println!("[Melpo]: Userspace ended: {:?}", uj);
let kj = kernel.await;
time::sleep(Duration::from_millis(50)).await;
tracing::info!("Kernel ended: {:?}", kj);
println!("========================================");
tracing::error!("You've met with a terrible fate, haven't you?");
}
#[tracing::instrument(name = "Kernel", level = "info", skip(opts))]
fn kernel_entry(opts: MelpomeneOptions) {
// First, we'll do some stuff that later the linker script will do...
let kernel_heap = Box::into_raw(Box::new([0u8; HEAP_SIZE]));
let user_heap = Box::into_raw(Box::new([0u8; HEAP_SIZE]));
let settings = KernelSettings {
heap_start: kernel_heap.cast(),
heap_size: HEAP_SIZE,
max_drivers: 16,
k2u_size: 4096,
u2k_size: 4096,
};
let k = unsafe { Kernel::new(settings).unwrap().leak().as_ref() };
// First let's make a dummy driver just to make sure some stuff happens
let initialization_future = async move {
// Delay for one second, just for funsies
Delay::new(Duration::from_secs(1)).await;
// Set up the bidirectional, async bbqueue channel between the TCP port
// (acting as a serial port) and the virtual serial port mux.
//
// Create the buffer, and spawn the worker task, giving it one of the
// queue handles
TcpSerial::register(k, opts.serial_addr, 4096, 4096).await.unwrap();
// Now, right now this is a little awkward, but what I'm doing here is spawning
// a new virtual mux, and configuring it with:
// * Up to 4 virtual ports max
// * Framed messages up to 512 bytes max each
SerialMux::register(k, 4, 512).await.unwrap();
let mux_hdl = SerialMuxHandle::from_registry(k).await.unwrap();
let p0 = mux_hdl.register_port(0, 1024).await.unwrap();
let p1 = mux_hdl.register_port(1, 1024).await.unwrap();
drop(mux_hdl);
k.spawn(async move {
loop {
let rgr = p0.consumer().read_grant().await;
let len = rgr.len();
p0.send(&rgr).await;
rgr.release(len);
}
}
.instrument(tracing::info_span!("Loopback")))
.await;
// Now we just send out data every second
k.spawn(async move {
loop {
Delay::new(Duration::from_secs(1)).await;
p1.send(b"hello\r\n").await;
}
}
.instrument(tracing::info_span!("Hello Loop")))
.await;
}
.instrument(tracing::info_span!("Initialize"));
k.initialize(initialization_future).unwrap();
//////////////////////////////////////////////////////////////////////////////
// TODO: Userspace doesn't really do anything yet! Simulate initialization of
// the userspace structures, and just periodically wake the kernel for now.
//////////////////////////////////////////////////////////////////////////////
let rings = k.rings();
unsafe {
let urings = mstd::executor::mailbox::Rings {
u2k: BBBuffer::take_framed_producer(rings.u2k.as_ptr()),
k2u: BBBuffer::take_framed_consumer(rings.k2u.as_ptr()),
};
mstd::executor::mailbox::MAILBOX.set_rings(urings);
mstd::executor::EXECUTOR.initialize(user_heap.cast(), HEAP_SIZE);
}
let _userspace = spawn(|| {
let _span = tracing::info_span!("userspace").entered();
loop {
while KERNEL_LOCK.load(Ordering::Acquire) {
sleep(Duration::from_millis(10));
}
mstd::executor::EXECUTOR.run();
KERNEL_LOCK.store(true, Ordering::Release);
}
});
loop {
while !KERNEL_LOCK.load(Ordering::Acquire) {
sleep(Duration::from_millis(10));
}
k.tick();
KERNEL_LOCK.store(false, Ordering::Release);
}
}
// fn userspace_entry() {
// use mstd::alloc::HEAP;
// // Set up kernel rings
// let u2k = unsafe { BBBuffer::take_framed_producer(abi::U2K_RING.load(Ordering::Acquire)) };
// let k2u = unsafe { BBBuffer::take_framed_consumer(abi::K2U_RING.load(Ordering::Acquire)) };
// // Set up allocator
// let mut hg = HEAP.init_exclusive(
// abi::HEAP_PTR.load(Ordering::Acquire) as usize,
// abi::HEAP_LEN.load(Ordering::Acquire),
// ).unwrap();
// // Set up executor
// let terpsichore = &mstd::executor::EXECUTOR;
// // Spawn the `main` task
// let mtask = mstd::executor::Task::new(async move {
// aman().await
// });
// let hbmtask = hg.alloc_box(mtask).map_err(drop).unwrap();
// drop(hg);
// let hg2 = HEAP.lock().unwrap();
// drop(hg2);
// let _mhdl = mstd::executor::spawn_allocated(hbmtask);
// let rings = Rings {
// u2k,
// k2u,
// };
// mstd::executor::mailbox::MAILBOX.set_rings(rings);
// let start = Instant::now();
// loop {
// *mstd::executor::time::CURRENT_TIME.borrow_mut().unwrap() = start.elapsed().as_micros() as u64;
// terpsichore.run();
// KERNEL_LOCK.store(true, Ordering::Release);
// while KERNEL_LOCK.load(Ordering::Acquire) {
// sleep(Duration::from_millis(50));
// }
// }
// }
// async fn aman() -> Result<(), ()> {
// mstd::executor::spawn(async {
// for _ in 0..3 {
// println!("[ST1] Hi, I'm aman's subtask!");
// Sleepy::new(Duration::from_secs(3)).await;
// }
// println!("[ST1] subtask done!");
// }).await;
// mstd::executor::spawn(async {
// for _ in 0..3 {
// let msg = UserRequestBody::Serial(SerialRequest::Flush);
// println!("[ST2] Sending to kernel: {:?}", msg);
// let resp = MAILBOX.request(msg).await;
// println!("[ST2] Kernel said: {:?}", resp);
// Sleepy::new(Duration::from_secs(2)).await;
// }
// println!("[ST2] subtask done!");
// }).await;
// loop {
// println!("[MT] Hi, I'm aman!");
// Sleepy::new(Duration::from_secs(1)).await;
// }
// }