]> git.dujemihanovic.xyz Git - nameless-os.git/blob - boot.s
Better gitignore and tidier string
[nameless-os.git] / boot.s
1 bits 16 ; boot sectors run in real mode
2 org 7C00h ; BIOS loads us at 0x7c00
3
4 KERNEL_OFFSET equ 1000h ; where we will load our kernel
5
6 mov [BOOT_DRIVE], dl ; BIOS puts the number of our boot drive in dl, so we will want to remember this
7
8 mov bp, 9000h ; initialize stack at a spot sufficiently distanced from this code
9 mov sp, bp
10
11 mov di, 0
12
13 xor ax, ax ; clear accumulator
14 int 13h ; BIOS disk services, with a cleared accumulator this will reset the disk controller
15 jc reset_error ; halt if controller reset fails
16
17 mov ah, 2 ; instruct BIOS's interrupt 13h to read sectors
18 mov al, 10 ; load 10 sectors, might be excessive (for now) but it's still good to do so
19 xor ch, ch ; read from 1st cylinder
20 mov cl, 2 ; start reading from 2nd sector, right after the boot sector
21 xor dh, dh ; read from 1st head
22 xor bx, bx ; clear B register
23 mov es, bx ; clear extended segment
24 mov bx, KERNEL_OFFSET ; put the sectors in our desired offset
25 ; dl holds the number of the drive to read from, but BIOS already filled this in
26 int 13h ; do the read
27 jc read_error ; halt if read fails
28 cmp al, 10 ; make sure we actually read 10 sectors
29 jl read_error ; halt if we didn't
30 jmp switch_to_pm ; if all is good, begin the switch to 32-bit protected mode
31
32 reset_error
33 mov bx, 0B800h
34 mov es, bx
35 mov byte [es:di], '1'
36 jmp halt
37
38 read_error
39 mov bx, 0B800h
40 mov es, bx
41 mov byte [es:di], '2'
42 jmp halt
43
44 call switch_to_pm
45
46 halt
47 jmp $
48
49 switch_to_pm
50 mov bx, 0B800h
51 mov es, bx ; set extra segment to starting address of video RAM
52 mov byte [es:0], 'L' ; print an L to screen, to let us know that we actually got here
53
54 cli ; disable interrupts
55 xor ax, ax ; clear accumulator
56 mov ds, ax ; clear data segment, this makes sure the next instruction reads from the right place
57 lgdt [gdt_desc] ; load the Global Descriptor Table
58
59 mov eax, cr0 ; move Control Register 0 to accumulator
60 or eax, 1 ; flip the bit which controls memory protection
61 mov cr0, eax ; move the accumulator back to CR0
62 jmp CODE_SEG:protected ; not quite there yet, need to do a far jump to clean the pipeline from any 16-bit instructions
63 ; note that the jump does not have to be physically far away, it just needs to use a segmented address
64
65 bits 32 ; we are finally in 32-bit mode
66 protected
67 mov ax, DATA_SEG ; put the selector for the data segment in the accumulator
68 ; in real mode, segmentation works by taking one of these segment registers, shifting it right by 4 bits or 1 hex digit
69 ; and then adding a 16-bit offset to form a 20-bit address
70 ; example: 1234h:5678h
71 ; 1234h is shifted to 12340h, 12340h + 5678h is 179B8h
72 ; in 32-bit protected mode, these segment registers do not hold the segment address itself, but a selector in the GDT
73 ; so we have to update the segment registers accordingly
74 mov ds, ax
75 mov ss, ax
76 mov es, ax
77 mov fs, ax
78 mov gs, ax
79
80 ; reinitialize the stack at a safe location
81 mov ebp, 090000h
82 mov esp, ebp
83
84 ; print a string to let us know that we survived the switch
85 mov ebx, pm_success
86 call pmprint
87
88 ; transfer control to the kernel
89 call KERNEL_OFFSET
90
91 ; above call should not return in normal circumstances, but if it does hang forever
92 jmp $
93
94 pmprint
95 pusha ; save registers to stack
96 mov edx, video_memory ; initialize dx with location of VRAM
97
98 .loop
99 mov al, [ebx] ; read next char and put it in al
100 mov ah, 00000111b ; puts the VGA text mode color white on black into ah
101
102 cmp al, 0 ; if the next character is null, we reached end of string
103 je .done ; so return the instruction
104
105 mov [edx], al ; otherwise put the next character in the video memory
106 mov [edx+1], ah ; do the same for its color
107
108 inc ebx ; point to next character in string
109 add edx, 2 ; point to next character in VRAM
110
111 jmp .loop ; go back to the loop
112
113 .done
114 popa ; restore registers from stack
115 ret ; return
116
117 pm_success db "Now in protected mode", 0
118 video_memory equ 0B8000h
119
120 ; the actual Global Descriptor Table
121 ; refer to Volume 3, Chapter 2, 2.1.1 of Intel's 64 and IA-32 Software Developer's Manual for more info
122 gdt_start
123 null_seg
124 dq 0
125 code_seg
126 dw 0FFFFh
127 dw 0
128 db 0
129 db 10011010b
130 db 11001111b
131 db 0
132 data_seg
133 dw 0FFFFh
134 dw 0
135 db 0
136 db 10010010b
137 db 11001111b
138 db 0
139 gdt_end
140 gdt_desc
141 dw gdt_end - gdt_start - 1
142 dd gdt_start
143 CODE_SEG equ code_seg - gdt_start
144 DATA_SEG equ data_seg - gdt_start
145
146 BOOT_DRIVE db 0 ; reserve a spot in RAM for our boot drive variable
147
148 times 510-($-$$) db 0
149 dw 0AA55h ; MBR signature