lib.rs 4.76 KB
Newer Older
Stefan Lankes's avatar
Stefan Lankes committed
1
2
3
4
5
6
7
// Copyright (c) 2018 Colin Finck, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

8
#![feature(alloc_error_handler)]
9
#![feature(asm)]
Martin Kröning's avatar
Martin Kröning committed
10
#![cfg_attr(target_arch = "aarch64", feature(global_asm))]
Stefan Lankes's avatar
Stefan Lankes committed
11
#![feature(panic_info_message)]
12
#![allow(incomplete_features)]
Stefan Lankes's avatar
Stefan Lankes committed
13
14
#![feature(specialization)]
#![no_std]
Martin Kröning's avatar
Martin Kröning committed
15
#![warn(rust_2018_idioms)]
Martin Kröning's avatar
Martin Kröning committed
16
#![allow(clippy::missing_safety_doc)]
Stefan Lankes's avatar
Stefan Lankes committed
17
18

// EXTERNAL CRATES
Martin Kröning's avatar
Martin Kröning committed
19
#[cfg(target_arch = "x86_64")]
Stefan Lankes's avatar
Stefan Lankes committed
20
21
22
#[macro_use]
extern crate bitflags;

23
24
25
26
#[cfg(target_arch = "x86_64")]
use crate::arch::x86_64::paging::{LargePageSize, PageSize};
use crate::arch::{get_memory, BOOT_INFO, ELF_ARCH};
use core::convert::TryInto;
27
use core::ptr::{self, copy_nonoverlapping, write_bytes};
28
29
30
use goblin::elf;
use goblin::elf::program_header::{PT_LOAD, PT_TLS};
use goblin::elf64::reloc::*;
31

Stefan Lankes's avatar
Stefan Lankes committed
32
33
34
35
36
37
// MODULES
#[macro_use]
pub mod macros;

pub mod arch;
pub mod console;
38
pub mod mm;
Stefan Lankes's avatar
Stefan Lankes committed
39
40
41
mod runtime_glue;

extern "C" {
42
43
	#[allow(dead_code)]
	static kernel_end: u8;
Stefan Lankes's avatar
Stefan Lankes committed
44
45
46
47
	static bss_end: u8;
	static mut bss_start: u8;
}

48
#[global_allocator]
49
static ALLOCATOR: mm::allocator::Allocator = mm::allocator::Allocator;
50

Stefan Lankes's avatar
Stefan Lankes committed
51
52
53
54
55
56
57
58
59
60
// FUNCTIONS
pub unsafe fn sections_init() {
	// Initialize .bss section
	ptr::write_bytes(
		&mut bss_start as *mut u8,
		0,
		&bss_end as *const u8 as usize - &bss_start as *const u8 as usize,
	);
}

Martin Kröning's avatar
Martin Kröning committed
61
pub unsafe fn load_kernel(elf: &elf::Elf<'_>, elf_start: u64, mem_size: u64) -> (u64, u64) {
62
	loaderlog!("start {:#x}, size {:#x}", elf_start, mem_size);
Martin Kröning's avatar
Martin Kröning committed
63
	if !elf.libraries.is_empty() {
64
65
66
67
		panic!(
			"Error: file depends on following libraries: {:?}",
			elf.libraries
		);
68
69
	}

70
71
72
73
74
	// Verify that this module is a HermitCore ELF executable.
	assert!(elf.header.e_type == elf::header::ET_DYN);
	assert!(elf.header.e_machine == ELF_ARCH);

	if elf.header.e_ident[7] != 0xFF {
75
		loaderlog!("Unsupported OS ABI {:#x}", elf.header.e_ident[7]);
76
	}
77

78
	let address = get_memory(mem_size);
79
	loaderlog!("Load HermitCore Application at {:#x}", address);
80

81
82
83
84
	// load application
	for program_header in &elf.program_headers {
		if program_header.p_type == PT_LOAD {
			let pos = program_header.p_vaddr;
85
86

			copy_nonoverlapping(
87
				(elf_start + program_header.p_offset) as *const u8,
88
				(address + pos) as *mut u8,
89
				program_header.p_filesz.try_into().unwrap(),
90
91
			);
			write_bytes(
92
				(address + pos + program_header.p_filesz) as *mut u8,
93
				0,
94
95
96
97
98
99
100
101
102
103
				(program_header.p_memsz - program_header.p_filesz)
					.try_into()
					.unwrap(),
			);
		} else if program_header.p_type == PT_TLS {
			BOOT_INFO.tls_start = address + program_header.p_vaddr as u64;
			BOOT_INFO.tls_filesz = program_header.p_filesz as u64;
			BOOT_INFO.tls_memsz = program_header.p_memsz as u64;

			loaderlog!(
104
				"Found TLS starts at {:#x} (size {} Bytes)",
105
106
				BOOT_INFO.tls_start,
				BOOT_INFO.tls_memsz
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
	// relocate entries (strings, copy-data, etc.) without an addend
	for rel in &elf.dynrels {
		loaderlog!("Unsupported relocation type {}", rel.r_type);
	}

	// relocate entries (strings, copy-data, etc.) with an addend
	for rela in &elf.dynrelas {
		match rela.r_type {
			#[cfg(target_arch = "x86_64")]
			R_X86_64_RELATIVE => {
				let offset = (address + rela.r_offset) as *mut u64;
				let new_addr =
					align_up!(&kernel_end as *const u8 as usize, LargePageSize::SIZE) as u64;
				*offset = (new_addr as i64 + rela.r_addend.unwrap_or(0)) as u64;
			}
			#[cfg(target_arch = "aarch64")]
			R_AARCH64_RELATIVE => {
				let offset = (address + rela.r_offset) as *mut u64;
				*offset = (address as i64 + rela.r_addend.unwrap_or(0)) as u64;
			}
			_ => {
				loaderlog!("Unsupported relocation type {}", rela.r_type);
			}
		}
	}

	(address, elf.entry + address)
138
139
}

Martin Kröning's avatar
Martin Kröning committed
140
pub fn check_kernel_elf_file(elf: &elf::Elf<'_>) -> u64 {
Martin Kröning's avatar
Martin Kröning committed
141
	if !elf.libraries.is_empty() {
142
143
144
145
146
147
		panic!(
			"Error: file depends on following libraries: {:?}",
			elf.libraries
		);
	}

Stefan Lankes's avatar
Stefan Lankes committed
148
	// Verify that this module is a HermitCore ELF executable.
149
150
	assert!(elf.header.e_type == elf::header::ET_DYN);
	assert!(elf.header.e_machine == ELF_ARCH);
Stefan Lankes's avatar
Stefan Lankes committed
151
152
153
	loaderlog!("This is a supported HermitCore Application");

	// Get all necessary information about the ELF executable.
154
155
	let mut file_size: u64 = 0;
	let mut mem_size: u64 = 0;
Stefan Lankes's avatar
Stefan Lankes committed
156

157
158
159
160
	for program_header in &elf.program_headers {
		if program_header.p_type == PT_LOAD {
			file_size = program_header.p_vaddr + program_header.p_filesz;
			mem_size = program_header.p_vaddr + program_header.p_memsz;
Stefan Lankes's avatar
Stefan Lankes committed
161
162
163
164
165
166
		}
	}

	// Verify the information.
	assert!(file_size > 0);
	assert!(mem_size > 0);
167
	loaderlog!("Found entry point: {:#x}", elf.entry);
Stefan Lankes's avatar
Stefan Lankes committed
168
169
170
	loaderlog!("File Size: {} Bytes", file_size);
	loaderlog!("Mem Size:  {} Bytes", mem_size);

171
	mem_size
Stefan Lankes's avatar
Stefan Lankes committed
172
}