-
Notifications
You must be signed in to change notification settings - Fork 13
/
lib.rs
390 lines (313 loc) · 10.6 KB
/
lib.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
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
//! Userspace library
//!
//! Provides an allocator, various lang items.
#![no_std]
#![feature(global_asm, asm, start, lang_items, core_intrinsics, const_fn, alloc, box_syntax, untagged_unions, naked_functions)]
// rustc warnings
#![warn(unused)]
#![warn(missing_debug_implementations)]
#![allow(unused_unsafe)]
#![allow(unreachable_code)]
#![allow(dead_code)]
#![cfg_attr(test, allow(unused_imports))]
#![allow(non_upper_case_globals)] // I blame roblabla.
// rustdoc warnings
#![warn(missing_docs)] // hopefully this will soon become deny(missing_docs)
#![deny(intra_doc_link_resolution_failure)]
#[macro_use]
extern crate alloc;
#[macro_use]
extern crate bitfield;
#[macro_use]
extern crate kfs_libutils;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
pub mod caps;
pub mod syscalls;
pub mod mem;
pub mod types;
pub mod ipc;
pub mod sm;
pub mod vi;
pub mod ahci;
pub mod error;
pub mod allocator;
pub mod terminal;
pub mod window;
pub mod zero_box;
mod log_impl;
pub use kfs_libutils::io;
use core::intrinsics;
use core::ptr;
use kfs_libutils as utils;
/// Global allocator. Every implicit allocation in the rust liballoc library (for
/// instance for Vecs, Arcs, etc...) are allocated with this allocator.
#[cfg(not(test))]
#[global_allocator]
static ALLOCATOR: allocator::Allocator = allocator::Allocator::new();
// Runtime functions
//
// Functions beyond this lines are required by the rust compiler when building
// for no_std. Care should be exercised when changing them, as lang items are
// extremely picky about how their types or implementation.
/// The exception handling personality function for use in the bootstrap.
///
/// We currently have no userspace exception handling, so make it do nothing.
#[cfg(target_os = "none")]
#[lang = "eh_personality"] #[no_mangle] pub extern fn eh_personality() {}
/// Function called on `panic!` invocation. Prints the panic information to the
/// kernel debug logger, and exits the process.
#[cfg(target_os = "none")]
#[panic_handler] #[no_mangle]
pub extern fn panic_fmt(p: &core::panic::PanicInfo<'_>) -> ! {
let _ = syscalls::output_debug_string(&format!("{}", p));
syscalls::exit_process();
}
use core::alloc::Layout;
// TODO: Don't panic in the oom handler, exit instead.
// BODY: Panicking may allocate, so calling panic in the OOM handler is a
// BODY: terrible idea.
/// OOM handler. Causes a panic.
#[cfg(target_os = "none")]
#[lang = "oom"]
#[no_mangle]
pub fn rust_oom(_: Layout) -> ! {
panic!("OOM")
}
// Assembly blob can't get documented, but clippy requires it.
#[allow(clippy::missing_docs_in_private_items)]
mod module_header {
global_asm!(r#"
.section .rodata.mod0
.global module_header
module_header:
.ascii "MOD0"
.int DYNAMIC - module_header
.int BSS_START - module_header
.int BSS_END - module_header
.int EH_FRAME_HDR_START - module_header
.int EH_FRAME_HDR_END - module_header
.int 0 // TODO: runtime-generated module object offset for rtld
"#);
}
/// The definition of a MOD0 header.
#[repr(C)]
#[derive(Debug)]
pub struct ModuleHeader {
/// The magic value of the MOD header.
pub magic: u32,
/// The offset of the dynamic section.
pub dynamic_off: u32,
/// The offset of the start of the bss section.
pub bss_start_off: u32,
/// The offset of the end of the bss section.
pub bss_end_off: u32,
/// The offset of the start of the eh_frame_hdr section.
pub unwind_start_off: u32,
/// The offset of the end of the eh_frame_hdr section.
pub unwind_end_off: u32,
/// The offset of the module object that will be used by the rtld.
pub module_object_off: u32
}
impl ModuleHeader {
/// Module Header Magic.
pub const MAGIC: u32 = 0x30444F4D;
}
/// A simple definition of a ELF Dynamic section entry.
#[repr(C)]
#[derive(Debug)]
struct ElfDyn {
/// The tag of the dynamic entry.
tag: isize,
/// The value of the dynamic entry.
val: usize,
}
/// Marks the end of the _DYNAMIC array.
const DT_NULL: isize = 0;
/// The address of a relocation table.
/// This element requires the DT_RELASZ and DT_RELAENT elements also be present.
/// When relocation is mandatory for a file, either DT_RELA or DT_REL can occur.
const DT_RELA: isize = 7;
/// The total size, in bytes, of the DT_RELA relocation table.
const DT_RELASZ: isize = 8;
/// The size, in bytes, of the DT_RELA relocation entry.
const DT_RELAENT: isize = 9;
/// Indicates that all ElfRela RELATIVE relocations have been concatenated together, and specifies the RELATIVE relocation count.
const DT_RELACOUNT: isize = 0x6ffffff9;
/// Similar to DT_RELA, except its table has implicit addends.
/// This element requires that the DT_RELSZ and DT_RELENT elements also be present.
const DT_REL: isize = 17;
/// The total size, in bytes, of the DT_REL relocation table.
const DT_RELSZ: isize = 18;
/// The size, in bytes, of the DT_REL relocation entry.
const DT_RELENT: isize = 19;
/// Indicates that all ElfRel RELATIVE relocations have been concatenated together, and specifies the RELATIVE relocation count.
const DT_RELCOUNT: isize = 0x6ffffffa;
/// Relocation table entry without addend.
#[repr(C)]
struct ElfRel {
/// The offset of the entry to relocate.
offset: usize,
/// The info about of the relocation to perform and its symbol offset.
info: usize
}
/// Relocation table entry with addend.
#[repr(C)]
struct ElfRela {
/// The offset of the entry to relocate.
offset: usize,
/// The info about of the relocation to perform and its symbol offset.
info: usize,
/// Addend.
addend: isize
}
/// The runtime linker computes the corresponding virtual address by adding the virtual address at which the shared object is loaded to the relative address.
const R_386_RELATIVE: usize = 8;
/// Executable entrypoint. Handle relocations and calls real_start.
#[cfg(target_os = "none")]
#[naked]
#[no_mangle]
#[link_section = ".text.crt0"]
pub unsafe extern fn start() -> ! {
asm!("
.intel_syntax noprefix
get_aslr_base:
call _start_shim
eip_pos:
.int module_header - get_aslr_base
// As x86 has variable instruction length, this is going to be the offset to the aslr base
.int eip_pos - get_aslr_base
_start_shim:
pop eax
// Save eip_pos address
mov ebx, eax
// Compute ASLR base because hey we don't have a choice
sub eax, [eax + 0x4]
mov ecx, eax
// Compute mod0 offset
add ecx, [ebx]
push ecx
push eax
// TODO: check error
call prepare_start
call real_start
");
intrinsics::unreachable();
}
/// Handle basic relocation and clean bss. Return a non zero value if failed.
#[cfg(target_os = "none")]
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern fn prepare_start(aslr_base: *mut u8, module_header: *const ModuleHeader) -> u32 {
let module_header_address = module_header as *const u8;
let module_header = &(*module_header);
if module_header.magic != ModuleHeader::MAGIC {
return 1;
}
let mut dynamic = module_header_address.add(module_header.dynamic_off as usize) as *const ElfDyn;
let mut rela_offset = None;
let mut rela_entry_size = 0;
let mut rela_count = 0;
let mut rel_offset = None;
let mut rel_entry_size = 0;
let mut rel_count = 0;
while (*dynamic).tag != DT_NULL {
match (*dynamic).tag {
DT_RELA => {
rela_offset = Some((*dynamic).val);
},
DT_RELAENT => {
rela_entry_size = (*dynamic).val;
},
DT_REL => {
rel_offset = Some((*dynamic).val);
},
DT_RELENT => {
rel_entry_size = (*dynamic).val;
},
DT_RELACOUNT => {
rela_count = (*dynamic).val;
},
DT_RELCOUNT => {
rel_count = (*dynamic).val;
},
_ => {}
}
dynamic = dynamic.offset(1);
}
if let Some(rela_offset) = rela_offset {
if rela_entry_size != core::mem::size_of::<ElfRela>() {
return 2;
}
let rela_base = (aslr_base.add(rela_offset)) as *mut ElfRela;
for i in 0..rela_count {
let rela = rela_base.add(i);
let reloc_type = (*rela).info & 0xff;
if let R_386_RELATIVE = reloc_type {
*(aslr_base.add((*rela).offset) as *mut *mut ()) = aslr_base.offset((*rela).addend) as _;
}
}
}
if let Some(rel_offset) = rel_offset {
if rel_entry_size != core::mem::size_of::<ElfRel>() {
return 3;
}
let rel_base = (aslr_base.add(rel_offset)) as *mut ElfRel;
for i in 0..rel_count {
let rel = rel_base.add(i);
let reloc_type = (*rel).info & 0xff;
if let R_386_RELATIVE = reloc_type {
let ptr = aslr_base.add((*rel).offset) as *mut usize;
*ptr += aslr_base as usize;
}
}
}
// Clean .bss
let bss_start_address = module_header_address.add(module_header.bss_start_off as usize) as *mut u8;
let bss_end_address = module_header_address.add(module_header.bss_end_off as usize) as *mut u8;
let count = bss_end_address as usize - bss_start_address as usize;
ptr::write_bytes(bss_start_address, 0, count);
0
}
/// calls logger initialization, main, and finally exits the
/// process.
#[cfg(target_os = "none")]
#[no_mangle]
pub unsafe extern fn real_start() -> ! {
extern {
fn main(argc: isize, argv: *const *const u8) -> i32;
}
log_impl::init();
let _ret = main(0, core::ptr::null());
syscalls::exit_process();
}
/// A trait for implementing arbitrary return types in the `main` function.
///
/// The c-main function only supports to return integers as return type.
/// So, every type implementing the `Termination` trait has to be converted
/// to an integer.
///
/// The default implementations are returning 0 to indicate a successful
/// execution. In case of a failure, 1 is returned.
#[cfg(target_os = "none")]
#[lang = "termination"]
trait Termination {
/// Is called to get the representation of the value as status code.
/// This status code is returned to the operating system.
fn report(self) -> i32;
}
#[cfg(target_os = "none")]
impl Termination for () {
#[inline]
fn report(self) -> i32 { 0 }
}
#[cfg(target_os = "none")]
#[lang = "start"]
#[allow(clippy::unit_arg)]
fn main<T: Termination>(main: fn(), _argc: isize, _argv: *const *const u8) -> isize {
main().report() as isize
}