-
Notifications
You must be signed in to change notification settings - Fork 3
/
loader.asm
183 lines (142 loc) · 5.52 KB
/
loader.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
[BITS 16]
[ORG 0x7E00]
; Produce a map file containing all symbols and sections.
[map all ../../build/boot/loader.map]
;===============================================================================
; loader
;
; Second-stage boot loader entry point
;
; Due to the limited size of the first-stage boot loader, its only mission in
; life is to load the Second-stage boot leader. The second-stage boot loader is
; responsible for essentially preparing the system to enter into the protected
; mode.
;
; Input registers:
;
; DL Boot drive number
;
; Memory layout before this code starts running:
;
; 00000000 - 000003ff 1,024 bytes Real mode IVT
; 00000400 - 000004ff 256 bytes BIOS data area
; 00000500 - 00007bff 30,464 bytes Free
; 00007c00 - 00007dff 512 bytes First-stage boot loader (MBR)
; 00007e00 - 0009fbff 622,080 bytes Free -> We are here now
; 0009fc00 - 0009ffff 1,024 bytes Extended BIOS data area (EBDA)
; 000a0000 - 000bffff 131,072 bytes BIOS video memory
; 000c0000 - 000fffff 262,144 bytes ROM
;===============================================================================
; jump to start procedure
jmp start
; Include functions/constants that are useful in real mode
%include "../../include/boot/global/const.asm"
%include "../../include/boot/global/mem.asm"
%include "../../include/boot/global/gdt.asm"
%include "../../include/boot/mode/realmode.asm"
%include "../../include/boot/second_stage_loader.asm"
start:
; Proper initialisation of stack during BIOS bootloader
; https://stackoverflow.com/a/33975465/832748
xor ax, ax
mov ds, ax
mov es, ax
mov bx, Loader.Mem.Stack.Top
; Turn off interrupts for SS:SP update to avoid a problem with buggy 8088 CPUs
cli
; SS = 0x0000
mov ss, ax
; SP = 0x7c00
; Set the stack starting just below where the bootloader is at 0x0:0x7c00.
mov sp, bx
; Turn interrupts back on
sti
boot:
; Save DriveId for later
mov [BIOS.Drive.Id], dl
; Print booting message
mov si, Realmode.SecondStage.Booting.Msg
call display_string
; Get memory map
call bios_e820_memory_map
; Attempt to enable the A20 line if necessary.
call enable_A20
; read kernel from disk and move it to memory
call read_kernel_from_disk
; read user prog from disk and move it to memory
call read_userprog_from_disk
; Check whether we are running on a 64-bit processor
call cpu_supports_64_bit_mode
; Prepare to enter protected mode
call enter_protected_mode
; enter a endless loop. This instruction should never be reached
jmp endless_loop
[BITS 32]
; Include Constants/Variables/routines useful in protected mode
%include "../../include/boot/mode/protectedmode.asm"
protected_mode_boot:
; Accoring to Intel 64 manual
; Section: 9.9.1 Switching to Protected Mode
;
; 9. After entering protected mode, the segment registers continue to hold the
; contents they had in real-address mode. The JMP or CALL instruction in
; step 4 resets the CS register. Perform one of the following operations to
; update the contents of the remaining segment registers.
;
; — Reload segment registers DS, SS, ES, FS, and GS.
; If the ES, FS, and/or GS registers are not going to be used,
; load them with a null selector.
; Turn off interrupts for SS:SP update to avoid a problem with buggy 8088 CPUs
; Also, interrupts will be disabled all the way to long mode as I don't need
; them in protected mode for anything. In fact, this was causing a weird
; race condition on QEMU that took me a few months to figure the culprit out
cli
; 0x10 = 16 which points to the GDT Data Segment (and the right DPL too)
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, Loader.Mem.Stack.Top
; fix video text printing
call pm_retrive_video_cursor_settings
; display status message
mov eax, ProtectedMode.SecondStage.Booting.Msg
call pm_display_string
; copy kernel to the right location
call pm_move_kernel
; Setup paging
call pm_setup_page_tables
; Enter Long monde (finally!)
call pm_enter_long_mode
; enter a endless loop. This instruction should never be reached
jmp pm_endless_loop
[BITS 64]
; Include Constants/Variables/routines useful in protected mode
%include "../../include/boot/mode/longmode.asm"
;-------------------------------------------------------------------------
; Launch the 64-bit kernel
;-------------------------------------------------------------------------
long_mode_boot:
; It is very important that you don't enable the interrupts (unless you have set up a 64-bit IDT of course).
; 0x10 = 16 which points to the GDT Data Segment (and the right DPL too)
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov rsp, Kernel.New.Start.VirtualAddress
; display status message
mov rax, LongMode.SecondStage.Booting.Msg
call lm_display_string
; jump to memory address in which the kernel should be (fingers crossed)
jmp Kernel.New.Start.VirtualAddress + Kernel.New.ELFTextHeader.Offset
; TODO: learn about which elf sections must be aligned... I'm still not convinced
; On physical devices this isn't required because the BIOS will
; pull the x number of blocks regardless of their content, however,
; if you are using QEMU and a raw image, it will strugle to Read
; the BIOS Disk Access Packet (DAP ) because the file finishes
; way earlier than the number of blocks requested.
times (Loader.File.NumberOfBlocks * 512) - ($ - $$) db 0