Skip to content

Commit ebc3e38

Browse files
committed
First commit
1 parent 9be6565 commit ebc3e38

11 files changed

+815
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target/
2+
**/*.rs.bk

Cargo.lock

+30
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "elf_loader"
3+
version = "0.1.0"
4+
authors = ["Philipp Oppermann <[email protected]>"]
5+
6+
#[lib]
7+
#crate-type = ["staticlib"]
8+
9+
[dependencies]
10+
rlibc = "1"
11+
xmas-elf = "0.6.0"
12+
13+
[profile.dev]
14+
# debug = false
15+
panic = "abort"
16+
17+
[profile.release]
18+
panic = "abort"

build.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
println!("rerun-if-changed=linker.ld");
3+
}

linker.ld

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
ENTRY(_start)
2+
3+
SECTIONS {
4+
/* page tables */
5+
. = ALIGN(0x1000);
6+
_p4 = .;
7+
. += 0x1000;
8+
_p3 = .;
9+
. += 0x1000;
10+
_p2 = .;
11+
. += 0x1000;
12+
13+
/* bootloader */
14+
. = 0x7c00;
15+
.bootloader :
16+
{
17+
/* first stage */
18+
*(.boot)
19+
20+
/* second stage */
21+
_second_stage_start_addr = .;
22+
*(.text .text.*)
23+
*(.rodata .rodata.*)
24+
*(.data .data.*)
25+
*(.second_stage)
26+
. = ALIGN(512);
27+
_second_stage_end_addr = .;
28+
}
29+
30+
/* kernel ELF file */
31+
. = ALIGN(512);
32+
.kernel :
33+
{
34+
_kernel_start_addr = .;
35+
KEEP(*(.kernel))
36+
. = ALIGN(512);
37+
_kernel_end_addr = .;
38+
}
39+
40+
}

src/boot.s

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
.section .boot, "awx"
2+
.global _start
3+
.intel_syntax noprefix
4+
.code16
5+
6+
_start:
7+
# zero segment registers
8+
xor ax, ax
9+
mov ds, ax
10+
mov es, ax
11+
mov ss, ax
12+
mov fs, ax
13+
mov gs, ax
14+
15+
# TODO explain
16+
cld
17+
18+
19+
# initialize stack
20+
mov sp, 0x7c00
21+
22+
lea si, boot_start_str
23+
call println
24+
25+
enable_a20:
26+
# enable A20-Line via IO-Port 92, might not work on all motherboards
27+
in al, 0x92
28+
or al, 2
29+
out 0x92, al
30+
31+
enter_protected_mode:
32+
cli
33+
push ds
34+
push es
35+
36+
lgdt [gdtinfo]
37+
38+
mov eax, cr0
39+
or al, 1 # set protected mode bit
40+
mov cr0, eax
41+
42+
jmp protected_mode # tell 386/486 to not crash
43+
44+
protected_mode:
45+
mov bx, 0x8
46+
mov ds, bx # set data segment
47+
mov es, bx # set extra segment
48+
49+
and al, 0xfe # clear protected mode bit
50+
mov cr0, eax
51+
52+
unreal_mode:
53+
pop es # get back old extra segment
54+
pop ds # get back old data segment
55+
sti
56+
57+
# back to real mode, but internal data segment register is still loaded
58+
# with gdt segment -> we can access the full 4GiB of memory
59+
60+
mov bx, 0x0f01 # attrib/char of smiley
61+
mov eax, 0xb8f00 # note 32 bit offset
62+
mov word ptr ds:[eax], bx
63+
64+
check_int13h_extensions:
65+
mov ah, 0x41
66+
mov bx, 0x55aa
67+
# dl contains drive number
68+
int 0x13
69+
jc no_int13h_extensions
70+
71+
load_second_stage_from_disk:
72+
lea eax, _second_stage_start_addr
73+
74+
# start of memory buffer
75+
mov [dap_buffer_addr], ax
76+
77+
# number of disk blocks to load
78+
lea ebx, _second_stage_end_addr
79+
sub ebx, eax # second stage end - second stage start
80+
shr ebx, 9 # divide by 512 (block size)
81+
mov [dap_blocks], bx
82+
83+
# number of start block
84+
lea ebx, _start
85+
sub eax, ebx
86+
shr eax, 9 # divide by 512 (block size)
87+
mov [dap_start_lba], ax
88+
89+
lea si, dap
90+
mov ah, 0x42
91+
int 0x13
92+
jc second_stage_load_failed
93+
94+
jump_to_second_stage:
95+
jmp second_stage
96+
97+
spin:
98+
jmp spin
99+
100+
# print a string and a newline
101+
# IN
102+
# si: points at zero-terminated String
103+
# CLOBBER
104+
# ax
105+
println:
106+
call print
107+
mov al, 13 # \r
108+
call print_char
109+
mov al, 10 # \n
110+
jmp print_char
111+
112+
# print a string
113+
# IN
114+
# si: points at zero-terminated String
115+
# CLOBBER
116+
# ax
117+
print:
118+
cld
119+
print_loop:
120+
lodsb
121+
test al, al
122+
jz print_done
123+
call print_char
124+
jmp print_loop
125+
print_done:
126+
ret
127+
128+
# print a character
129+
# IN
130+
# al: character to print
131+
# CLOBBER
132+
# ah
133+
print_char:
134+
mov ah, 0x0e
135+
int 0x10
136+
ret
137+
138+
# print a number in hex
139+
# IN
140+
# bx: the number
141+
# CLOBBER
142+
# al, cx
143+
print_hex:
144+
mov cx, 4
145+
.lp:
146+
mov al, bh
147+
shr al, 4
148+
149+
cmp al, 0xA
150+
jb .below_0xA
151+
152+
add al, 'A' - 0xA - '0'
153+
.below_0xA:
154+
add al, '0'
155+
156+
call print_char
157+
158+
shl bx, 4
159+
loop .lp
160+
161+
ret
162+
163+
error:
164+
call println
165+
jmp spin
166+
167+
no_int13h_extensions:
168+
lea si, no_int13h_extensions_str
169+
jmp error
170+
171+
second_stage_load_failed:
172+
lea si, second_stage_load_failed_str
173+
jmp error
174+
175+
kernel_load_failed:
176+
lea si, kernel_load_failed_str
177+
jmp error
178+
179+
boot_start_str: .asciz "Booting (first stage)..."
180+
second_stage_start_str: .asciz "Booting (second stage)..."
181+
error_str: .asciz "Error: "
182+
no_cpuid_str: .asciz "No CPUID support"
183+
no_int13h_extensions_str: .asciz "No support for int13h extensions"
184+
second_stage_load_failed_str: .asciz "Failed to load second stage of bootloader"
185+
kernel_load_failed_str: .asciz "Failed to load kernel"
186+
no_long_mode_str: .asciz "No long mode support"
187+
188+
gdtinfo:
189+
.word gdt_end - gdt - 1 # last byte in table
190+
.word gdt # start of table
191+
192+
gdt:
193+
# entry 0 is always unused
194+
.quad 0
195+
flatdesc:
196+
.byte 0xff
197+
.byte 0xff
198+
.byte 0
199+
.byte 0
200+
.byte 0
201+
.byte 0b10010010
202+
.byte 0b11001111
203+
.byte 0
204+
gdt_end:
205+
206+
dap: # disk access packet
207+
.byte 0x10 # size of dap
208+
.byte 0 # unused
209+
dap_blocks:
210+
.word 0 # number of sectors
211+
dap_buffer_addr:
212+
.word 0 # offset to memory buffer
213+
dap_buffer_seg:
214+
.word 0 # segment of memory buffer
215+
dap_start_lba:
216+
.quad 0 # start logical block address
217+
218+
.org 510
219+
.word 0xaa55 # magic number for bootable disk

src/kernel.s

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.section ".kernel", "a"
2+
.incbin "kernel.bin"

src/main.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#![feature(lang_items)]
2+
#![feature(global_asm)]
3+
#![no_std]
4+
#![no_main]
5+
6+
extern crate rlibc;
7+
extern crate xmas_elf;
8+
9+
use core::slice;
10+
11+
global_asm!(include_str!("boot.s"));
12+
global_asm!(include_str!("second_stage.s"));
13+
global_asm!(include_str!("kernel.s"));
14+
15+
#[no_mangle]
16+
pub extern "C" fn load_elf(kernel_start: *const u8, kernel_size: usize) -> ! {
17+
let kernel = unsafe { slice::from_raw_parts(kernel_start, kernel_size) };
18+
let elf_file = xmas_elf::ElfFile::new(kernel).unwrap();
19+
xmas_elf::header::sanity_check(&elf_file).unwrap();
20+
loop {}
21+
}
22+
23+
#[lang = "panic_fmt"]
24+
#[no_mangle]
25+
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
26+
_file: &'static str,
27+
_line: u32,
28+
_column: u32) -> ! {
29+
const VGA_BUFFER: *mut u8 = 0xb8000 as *mut _;
30+
31+
unsafe {
32+
let vga_buffer = slice::from_raw_parts_mut(VGA_BUFFER, 25 * 80 *2);
33+
vga_buffer[0] = b'E'; vga_buffer[1] = 0x4f;
34+
vga_buffer[2] = b'R'; vga_buffer[3] = 0x4f;
35+
vga_buffer[4] = b'R'; vga_buffer[5] = 0x4f;
36+
}
37+
38+
loop {}
39+
}
40+
41+
#[lang = "eh_personality"]
42+
#[no_mangle]
43+
pub extern fn eh_personality() { loop {} }
44+
45+
#[no_mangle]
46+
pub extern fn _Unwind_Resume() { loop {} }

0 commit comments

Comments
 (0)