Skip to content

Commit d31c8d9

Browse files
committed
Use LLD for linking and reorganize assembly stages
1 parent 967a09b commit d31c8d9

File tree

8 files changed

+136
-127
lines changed

8 files changed

+136
-127
lines changed

linker.ld

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ 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.*)
4040
. = ALIGN(512);
41-
_second_stage_end_addr = .;
41+
_rest_of_bootloader_end_addr = .;
4242
}
4343

4444
_kernel_info_block_start = .;

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: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.section .boot, "awx"
1+
.section .boot-first-stage, "awx"
22
.global _start
33
.intel_syntax noprefix
44
.code16
@@ -16,7 +16,6 @@ _start:
1616
# instructions like lodsb)
1717
cld
1818

19-
2019
# initialize stack
2120
mov sp, 0x7c00
2221

@@ -70,15 +69,15 @@ check_int13h_extensions:
7069
int 0x13
7170
jc no_int13h_extensions
7271

73-
load_second_stage_from_disk:
74-
lea eax, _second_stage_start_addr
72+
load_rest_of_bootloader_from_disk:
73+
lea eax, _rest_of_bootloader_start_addr
7574

7675
# start of memory buffer
7776
mov [dap_buffer_addr], ax
7877

7978
# number of disk blocks to load
8079
lea ebx, _kernel_info_block_end
81-
sub ebx, eax # second stage end - second stage start
80+
sub ebx, eax # end - start
8281
shr ebx, 9 # divide by 512 (block size)
8382
mov [dap_blocks], bx
8483

@@ -91,10 +90,10 @@ load_second_stage_from_disk:
9190
lea si, dap
9291
mov ah, 0x42
9392
int 0x13
94-
jc second_stage_load_failed
93+
jc rest_of_bootloader_load_failed
9594

9695
jump_to_second_stage:
97-
lea eax, second_stage
96+
lea eax, [stage_2]
9897
jmp eax
9998

10099
spin:
@@ -174,20 +173,15 @@ no_int13h_extensions:
174173
lea si, no_int13h_extensions_str
175174
jmp error
176175

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
176+
rest_of_bootloader_load_failed:
177+
lea si, rest_of_bootloader_load_failed_str
183178
jmp error
184179

185180
boot_start_str: .asciz "Booting (first stage)..."
186-
second_stage_start_str: .asciz "Booting (second stage)..."
187181
error_str: .asciz "Error: "
188182
no_cpuid_str: .asciz "No CPUID support"
189183
no_int13h_extensions_str: .asciz "No support for int13h extensions"
190-
second_stage_load_failed_str: .asciz "Failed to load second stage of bootloader"
184+
rest_of_bootloader_load_failed_str: .asciz "Failed to load rest of bootloader"
191185

192186
gdtinfo:
193187
.word gdt_end - gdt - 1 # last byte in table

src/stage_2.s

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

src/second_stage.s renamed to src/stage_3.s

Lines changed: 8 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,10 @@
1-
.section .second_stage, "awx"
1+
.section .boot, "awx"
22
.intel_syntax noprefix
3-
.code16
3+
.code32
44

5-
loading_kernel_block_str: .asciz "loading kernel block..."
6-
kernel_load_failed_str: .asciz "Failed to load kernel"
75
no_long_mode_str: .asciz "No long mode support"
86

9-
second_stage:
10-
lea si, second_stage_start_str
11-
call println
12-
13-
set_target_operating_mode:
14-
# Some BIOSs assume the processor will only operate in Legacy Mode. We change the Target
15-
# Operating Mode to "Long Mode Target Only", so the firmware expects each CPU to enter Long Mode
16-
# once and then stay in it. This allows the firmware to enable mode-specifc optimizations.
17-
# We save the flags, because CF is set if the callback is not supported (in which case, this is
18-
# a NOP)
19-
pushf
20-
mov ax, 0xec00
21-
mov bl, 0x2
22-
int 0x15
23-
popf
24-
25-
load_kernel_from_disk:
26-
# start of memory buffer
27-
lea eax, _kernel_buffer
28-
mov [dap_buffer_addr], ax
29-
30-
# number of disk blocks to load
31-
mov word ptr [dap_blocks], 1
32-
33-
# number of start block
34-
lea eax, _kernel_start_addr
35-
lea ebx, _start
36-
sub eax, ebx
37-
shr eax, 9 # divide by 512 (block size)
38-
mov [dap_start_lba], eax
39-
40-
# destination address
41-
mov edi, 0x400000
42-
43-
# block count
44-
mov ecx, _kib_kernel_size
45-
add ecx, 511 # align up
46-
shr ecx, 9
47-
48-
load_next_kernel_block_from_disk:
49-
# load block from disk
50-
lea si, dap
51-
mov ah, 0x42
52-
int 0x13
53-
jc kernel_load_failed
54-
55-
# copy block to 2MiB
56-
push ecx
57-
push esi
58-
mov ecx, 512 / 4
59-
# move with zero extension
60-
# because we are moving a word ptr
61-
# to esi, a 32-bit register.
62-
movzx esi, word ptr [dap_buffer_addr]
63-
# move from esi to edi ecx times.
64-
rep movsd [edi], [esi]
65-
pop esi
66-
pop ecx
67-
68-
# next block
69-
mov eax, [dap_start_lba]
70-
add eax, 1
71-
mov [dap_start_lba], eax
72-
73-
sub ecx, 1
74-
jnz load_next_kernel_block_from_disk
75-
76-
create_memory_map:
77-
lea di, es:[_memory_map]
78-
call do_e820
79-
7+
stage_3:
808
check_cpu:
819
call check_cpuid
8210
call check_long_mode
@@ -144,7 +72,6 @@ set_up_page_tables:
14472
shr ecx, 12
14573
mov [_p1 + ecx * 8], eax
14674

147-
14875
enable_paging:
14976
# load P4 to cr3 register (cpu uses this to access the P4 table)
15077
lea eax, [_p4]
@@ -171,12 +98,12 @@ load_64bit_gdt:
17198

17299
jump_to_long_mode:
173100
push 0x8
174-
lea eax, [long_mode]
101+
lea eax, [stage_4]
175102
push eax
176103
retf # Load CS with 64 bit segment and flush the instruction cache
177104

178-
jmp spin
179-
105+
spin_here:
106+
jmp spin_here
180107

181108
check_cpuid:
182109
# Check if CPUID is supported by attempting to flip the ID bit (bit 21)
@@ -212,7 +139,7 @@ check_cpuid:
212139
ret
213140
no_cpuid:
214141
lea si, no_cpuid_str
215-
jmp error
142+
jmp no_cpuid
216143

217144
check_long_mode:
218145
# test if extended processor info in available
@@ -229,7 +156,7 @@ check_long_mode:
229156
ret
230157
no_long_mode:
231158
lea si, no_long_mode_str
232-
jmp error
159+
jmp no_long_mode
233160

234161

235162
.align 4
@@ -248,22 +175,3 @@ gdt_64:
248175
gdt_64_pointer:
249176
.word gdt_64_pointer - gdt_64 - 1 # 16-bit Size (Limit) of GDT.
250177
.long gdt_64 # 32-bit Base Address of GDT. (CPU will zero extend to 64-bit)
251-
252-
253-
.code64
254-
255-
long_mode:
256-
# call load_elf with kernel start address, size, and memory map as arguments
257-
movabs rdi, 0x400000 # move absolute 64-bit to register
258-
mov rsi, _kib_kernel_size
259-
lea rdx, _memory_map
260-
movzx rcx, word ptr mmap_ent
261-
lea r8, __page_table_start
262-
lea r9, __page_table_end
263-
lea rax, __bootloader_end
264-
push rax
265-
lea rax, __bootloader_start
266-
push rax
267-
call load_elf
268-
spin64:
269-
jmp spin64

src/stage_4.s

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.section .boot, "awx"
2+
.intel_syntax noprefix
3+
.code64
4+
5+
stage_4:
6+
# call load_elf with kernel start address, size, and memory map as arguments
7+
movabs rdi, 0x400000 # move absolute 64-bit to register
8+
mov rsi, _kib_kernel_size
9+
lea rdx, _memory_map
10+
movzx rcx, word ptr mmap_ent
11+
lea r8, __page_table_start
12+
lea r9, __page_table_end
13+
lea rax, __bootloader_end
14+
push rax
15+
lea rax, __bootloader_start
16+
push rax
17+
call load_elf
18+
spin64:
19+
jmp spin64

x86_64-bootloader.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"llvm-target": "x86_64-unknown-none-gnu",
33
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
4-
"linker-flavor": "ld",
5-
"linker": "ld.bfd",
4+
"linker-flavor": "ld.lld",
5+
"linker": "rust-lld",
66
"pre-link-args": {
7-
"ld": [
7+
"ld.lld": [
88
"--script=linker.ld"
99
]
1010
},

0 commit comments

Comments
 (0)