Skip to content

Commit 0606dfd

Browse files
authored
Merge pull request rust-osdev#28 from rust-osdev/lld-new
Use LLD for linking, fix page table zeroing, increase memory map size, improve errors
2 parents 967a09b + 46d3ca0 commit 0606dfd

File tree

10 files changed

+251
-156
lines changed

10 files changed

+251
-156
lines changed

Cargo.lock

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

linker.ld

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,18 @@ SECTIONS {
2828
.bootloader :
2929
{
3030
/* first stage */
31-
*(.boot)
31+
*(.boot-first-stage)
3232

33-
/* second stage */
34-
_second_stage_start_addr = .;
35-
*(.second_stage)
33+
/* rest of bootloader */
34+
_rest_of_bootloader_start_addr = .;
35+
*(.boot)
3636
*(.context_switch)
3737
*(.text .text.*)
3838
*(.rodata .rodata.*)
3939
*(.data .data.*)
40+
*(.got)
4041
. = ALIGN(512);
41-
_second_stage_end_addr = .;
42+
_rest_of_bootloader_end_addr = .;
4243
}
4344

4445
_kernel_info_block_start = .;

src/bootinfo/memory_map.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ use core::ops::{Deref, DerefMut};
33

44
const PAGE_SIZE: u64 = 4096;
55

6+
const MAX_MEMORY_MAP_SIZE: usize = 64;
7+
68
#[repr(C)]
79
pub struct MemoryMap {
8-
entries: [MemoryRegion; 32],
10+
entries: [MemoryRegion; MAX_MEMORY_MAP_SIZE],
911
// u64 instead of usize so that the structure layout is platform
1012
// independent
1113
next_entry_index: u64,
@@ -14,12 +16,14 @@ pub struct MemoryMap {
1416
impl MemoryMap {
1517
pub fn new() -> Self {
1618
MemoryMap {
17-
entries: [MemoryRegion::empty(); 32],
19+
entries: [MemoryRegion::empty(); MAX_MEMORY_MAP_SIZE],
1820
next_entry_index: 0,
1921
}
2022
}
2123

2224
pub fn add_region(&mut self, region: MemoryRegion) {
25+
assert!(self.next_entry_index() < MAX_MEMORY_MAP_SIZE,
26+
"too many memory regions in memory map");
2327
self.entries[self.next_entry_index()] = region;
2428
self.next_entry_index += 1;
2529
self.sort();

src/memory_map.s renamed to src/e820.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.section .second_stage, "awx"
1+
.section .boot, "awx"
22
.intel_syntax noprefix
33
.code16
44

src/main.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ use x86_64::ux::u9;
2525
pub use x86_64::PhysAddr;
2626
use x86_64::VirtAddr;
2727

28-
global_asm!(include_str!("boot.s"));
29-
global_asm!(include_str!("second_stage.s"));
30-
global_asm!(include_str!("memory_map.s"));
28+
global_asm!(include_str!("stage_1.s"));
29+
global_asm!(include_str!("stage_2.s"));
30+
global_asm!(include_str!("e820.s"));
31+
global_asm!(include_str!("stage_3.s"));
32+
global_asm!(include_str!("stage_4.s"));
3133
global_asm!(include_str!("context_switch.s"));
3234

3335
extern "C" {

src/boot.s renamed to src/stage_1.s

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
.section .boot, "awx"
1+
.section .boot-first-stage, "awx"
22
.global _start
33
.intel_syntax noprefix
44
.code16
55

6+
# This stage initializes the stack, enables the A20 line, loads the rest of
7+
# the bootloader from disk, and jumps to stage_2.
8+
69
_start:
710
# zero segment registers
811
xor ax, ax
@@ -16,7 +19,6 @@ _start:
1619
# instructions like lodsb)
1720
cld
1821

19-
2022
# initialize stack
2123
mov sp, 0x7c00
2224

@@ -35,7 +37,7 @@ enter_protected_mode:
3537
push ds
3638
push es
3739

38-
lgdt [gdtinfo]
40+
lgdt [gdt32info]
3941

4042
mov eax, cr0
4143
or al, 1 # set protected mode bit
@@ -44,7 +46,7 @@ enter_protected_mode:
4446
jmp protected_mode # tell 386/486 to not crash
4547

4648
protected_mode:
47-
mov bx, 0x8
49+
mov bx, 0x10
4850
mov ds, bx # set data segment
4951
mov es, bx # set extra segment
5052

@@ -70,15 +72,15 @@ check_int13h_extensions:
7072
int 0x13
7173
jc no_int13h_extensions
7274

73-
load_second_stage_from_disk:
74-
lea eax, _second_stage_start_addr
75+
load_rest_of_bootloader_from_disk:
76+
lea eax, _rest_of_bootloader_start_addr
7577

7678
# start of memory buffer
7779
mov [dap_buffer_addr], ax
7880

7981
# number of disk blocks to load
8082
lea ebx, _kernel_info_block_end
81-
sub ebx, eax # second stage end - second stage start
83+
sub ebx, eax # end - start
8284
shr ebx, 9 # divide by 512 (block size)
8385
mov [dap_blocks], bx
8486

@@ -91,10 +93,10 @@ load_second_stage_from_disk:
9193
lea si, dap
9294
mov ah, 0x42
9395
int 0x13
94-
jc second_stage_load_failed
96+
jc rest_of_bootloader_load_failed
9597

9698
jump_to_second_stage:
97-
lea eax, second_stage
99+
lea eax, [stage_2]
98100
jmp eax
99101

100102
spin:
@@ -174,29 +176,33 @@ no_int13h_extensions:
174176
lea si, no_int13h_extensions_str
175177
jmp error
176178

177-
second_stage_load_failed:
178-
lea si, second_stage_load_failed_str
179-
jmp error
180-
181-
kernel_load_failed:
182-
lea si, kernel_load_failed_str
179+
rest_of_bootloader_load_failed:
180+
lea si, rest_of_bootloader_load_failed_str
183181
jmp error
184182

185183
boot_start_str: .asciz "Booting (first stage)..."
186-
second_stage_start_str: .asciz "Booting (second stage)..."
187184
error_str: .asciz "Error: "
188185
no_cpuid_str: .asciz "No CPUID support"
189186
no_int13h_extensions_str: .asciz "No support for int13h extensions"
190-
second_stage_load_failed_str: .asciz "Failed to load second stage of bootloader"
187+
rest_of_bootloader_load_failed_str: .asciz "Failed to load rest of bootloader"
191188

192-
gdtinfo:
193-
.word gdt_end - gdt - 1 # last byte in table
194-
.word gdt # start of table
189+
gdt32info:
190+
.word gdt32_end - gdt32 - 1 # last byte in table
191+
.word gdt32 # start of table
195192

196-
gdt:
193+
gdt32:
197194
# entry 0 is always unused
198195
.quad 0
199-
flatdesc:
196+
codedesc:
197+
.byte 0xff
198+
.byte 0xff
199+
.byte 0
200+
.byte 0
201+
.byte 0
202+
.byte 0x9a
203+
.byte 0xcf
204+
.byte 0
205+
datadesc:
200206
.byte 0xff
201207
.byte 0xff
202208
.byte 0
@@ -205,7 +211,7 @@ flatdesc:
205211
.byte 0x92
206212
.byte 0xcf
207213
.byte 0
208-
gdt_end:
214+
gdt32_end:
209215

210216
dap: # disk access packet
211217
.byte 0x10 # size of dap

src/stage_2.s

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
.section .boot, "awx"
2+
.intel_syntax noprefix
3+
.code16
4+
5+
# This stage sets the target operating mode, loads the kernel from disk,
6+
# creates an e820 memory map, enters protected mode, and jumps to the
7+
# third stage.
8+
9+
second_stage_start_str: .asciz "Booting (second stage)..."
10+
kernel_load_failed_str: .asciz "Failed to load kernel from disk"
11+
12+
kernel_load_failed:
13+
lea si, [kernel_load_failed_str]
14+
call println
15+
kernel_load_failed_spin:
16+
jmp kernel_load_failed_spin
17+
18+
stage_2:
19+
lea si, [second_stage_start_str]
20+
call println
21+
22+
set_target_operating_mode:
23+
# Some BIOSs assume the processor will only operate in Legacy Mode. We change the Target
24+
# Operating Mode to "Long Mode Target Only", so the firmware expects each CPU to enter Long Mode
25+
# once and then stay in it. This allows the firmware to enable mode-specifc optimizations.
26+
# We save the flags, because CF is set if the callback is not supported (in which case, this is
27+
# a NOP)
28+
pushf
29+
mov ax, 0xec00
30+
mov bl, 0x2
31+
int 0x15
32+
popf
33+
34+
load_kernel_from_disk:
35+
# start of memory buffer
36+
lea eax, _kernel_buffer
37+
mov [dap_buffer_addr], ax
38+
39+
# number of disk blocks to load
40+
mov word ptr [dap_blocks], 1
41+
42+
# number of start block
43+
lea eax, _kernel_start_addr
44+
lea ebx, _start
45+
sub eax, ebx
46+
shr eax, 9 # divide by 512 (block size)
47+
mov [dap_start_lba], eax
48+
49+
# destination address
50+
mov edi, 0x400000
51+
52+
# block count
53+
mov ecx, _kib_kernel_size
54+
add ecx, 511 # align up
55+
shr ecx, 9
56+
57+
load_next_kernel_block_from_disk:
58+
# load block from disk
59+
lea si, dap
60+
mov ah, 0x42
61+
int 0x13
62+
jc kernel_load_failed
63+
64+
# copy block to 2MiB
65+
push ecx
66+
push esi
67+
mov ecx, 512 / 4
68+
# move with zero extension
69+
# because we are moving a word ptr
70+
# to esi, a 32-bit register.
71+
movzx esi, word ptr [dap_buffer_addr]
72+
# move from esi to edi ecx times.
73+
rep movsd [edi], [esi]
74+
pop esi
75+
pop ecx
76+
77+
# next block
78+
mov eax, [dap_start_lba]
79+
add eax, 1
80+
mov [dap_start_lba], eax
81+
82+
sub ecx, 1
83+
jnz load_next_kernel_block_from_disk
84+
85+
create_memory_map:
86+
lea di, es:[_memory_map]
87+
call do_e820
88+
89+
enter_protected_mode_again:
90+
cli
91+
lgdt [gdt32info]
92+
mov eax, cr0
93+
or al, 1 # set protected mode bit
94+
mov cr0, eax
95+
96+
push 0x8
97+
lea eax, [stage_3]
98+
push eax
99+
retf
100+
101+
spin32:
102+
jmp spin32

0 commit comments

Comments
 (0)