Skip to main content

rustubs/proc/
loader.rs

1//! a simple loader for statically linked elf.
2use crate::arch::x86_64::paging::get_root;
3use crate::arch::x86_64::paging::map_vma;
4use crate::black_magic;
5use crate::fs;
6use crate::mm::vmm::{VMArea, VMPerms, VMType};
7use crate::proc::task::Task;
8use alloc::string::String;
9use core::ops::Range;
10use core::str::FromStr;
11use xmas_elf::header::HeaderPt2;
12use xmas_elf::program::{ProgramHeader, Type};
13use xmas_elf::ElfFile;
14pub fn cat_elf(f: &fs::File) {
15	let elf = ElfFile::new(f.file).unwrap();
16	println!("{:?}", elf.header);
17}
18
19// this loads a file into task address space
20// half baked!
21// 0. find and parse elf
22// 1. creates VMAs
23// 2. create paging structs and copy memory if necessary
24pub fn load(file: &fs::File) -> Option<u64> {
25	let task = Task::current().unwrap();
26	let mm = &mut task.mm;
27	let elf = ElfFile::new(file.file).ok()?;
28	let pt_root = get_root();
29
30	let mut header_ok = true;
31	for hdr in elf.program_iter() {
32		// you stupid rust force people to do 20000 levels of
33		// indentations of if let and match. Why can't we have nice
34		// thing?
35		if let ProgramHeader::Ph32(_) = hdr {
36			println!("not an 64 bit elf header");
37			header_ok = false;
38			break;
39		}
40		// I know for sure now this is Ph64, I just want to unwrap it. Why the
41		// heck can't I do it? Why the heck do I need yet another level of
42		// indentation???
43		let h = match hdr {
44			ProgramHeader::Ph64(h) => h,
45			_ => panic!(),
46		};
47
48		// skip non-load sections
49		if h.get_type() != Ok(Type::Load) {
50			continue;
51		}
52
53		sprintln!(
54			"{:?} VA:{:#X}+{:#X}, FILE:{:#X}+{:#X}",
55			h.type_,
56			h.virtual_addr,
57			h.mem_size,
58			h.offset,
59			h.file_size,
60		);
61		let fstart = h.offset as usize;
62		let fend = fstart + h.file_size as usize;
63		if fstart >= file.file.len() || fend >= file.file.len() {
64			println!("bad size");
65		}
66
67		if h.mem_size > h.file_size {
68			sprintln!(
69				"including BSS: {:#X} - {:#X}",
70				h.virtual_addr + h.file_size,
71				h.virtual_addr + h.mem_size
72			);
73		}
74		// black magic in sight! this converts a reference to static lifetime,
75		// which is UB, but I know what I'm doing here. The file backing ARE
76		// static!
77		let vma = VMArea {
78			vm_range: Range::<u64> {
79				start: h.virtual_addr,
80				end: h.virtual_addr + h.mem_size,
81			},
82			tag: String::from_str("USER BITS").unwrap(),
83			user_perms: VMPerms::all(),
84			backing: match h.file_size {
85				0 => VMType::ANOM,
86				_ => VMType::FILE(unsafe {
87					black_magic::make_static(&file.file[fstart..fend])
88				}),
89			},
90		};
91
92		let res = unsafe { map_vma(pt_root, &vma, true) };
93		if !res {
94			println!("failed to push vma: {:#X?}", &vma);
95			return None;
96		}
97		mm.vmas.push(vma);
98	}
99
100	if !header_ok {
101		println!("bad header");
102		return None;
103	}
104	match &elf.header.pt2 {
105		HeaderPt2::Header64(pt2) => return Some(pt2.entry_point),
106		_ => {
107			println!("bad header, not entry point");
108			return None;
109		}
110	};
111}