PageRenderTime 41ms CodeModel.GetById 15ms app.highlight 18ms RepoModel.GetById 2ms app.codeStats 0ms

/bootloader/stage2.asm

http://github.com/Pokelover980/Poke-and-Necro-Hobby-OS
Assembly | 306 lines | 257 code | 33 blank | 16 comment | 0 complexity | 31317b6405af56d1720196b9bc3ec892 MD5 | raw file
  1; -------------------------------------------------------------
  2; Pokelover and Necro's Hobby OS Bootloader - Stage 2
  3; 
  4; Reuses some code from stage1 to help with disk loading. This
  5; stage simply loads the kernel, sets up 32 bit protected mode,
  6; and then jumps to the kernel for execution. Fun!
  7; -------------------------------------------------------------
  8
  9[BITS 16]
 10
 11Start:                       ; A lot of code here is reused from stage1 so we can
 12                             ; load the kernel before entering protected mode
 13	mov ax, 0x0200           ; This is our entry point
 14	add ax, 544              ; 544 paragraph disk buffer
 15	cli                      ; No interrupts while changing stack!
 16	mov ss, ax
 17	mov sp, 4096
 18	sti                      ; Now we can have interrupts back :D
 19	mov ax, 0x0200           ; Set data segment to where we're loaded
 20	mov ds, ax
 21	mov byte [BootDev], dl   ; Save boot device number
 22	mov eax, 0               ; May be needed by older BIOSes
 23	mov si, S2Message
 24	call PrintString
 25	
 26FloppyOk:                    ; Ready to read first block of data
 27	mov ax, 19               ; Root dir starts at logical sector 19
 28	call l2hts
 29	mov si, Buffer           ; Set ES:BX to our buffer
 30	mov bx, ds
 31	mov es, bx
 32	mov bx, si
 33	mov ah, 2                ; int 0x13 params: Read floppy sectors
 34	mov al, 14               ; 14 floppy sectors to read
 35	pusha                    ; Push registers to stack to prepare for loop
 36	
 37ReadRootDir:
 38	popa                     ; Just in case int 0x13 modified anything
 39	pusha
 40	stc                      ; Not all BIOSes set properly on error
 41	int 0x13                 ; Read sectors
 42	jnc SearchDir            ; If read was OK, skip ahead
 43	call ResetFloppy         ; If not, reset floppy and try again
 44	jnc ReadRootDir          ; Did the floppy reset fine?
 45	jmp Reboot               ; If it didn't, double error, restart
 46	
 47SearchDir:
 48	popa
 49	mov ax, ds               ; Root dir is now in [Buffer]
 50	mov es, ax               ; Give this info to DI
 51	mov di, Buffer
 52	mov cx, word [224]       ; Search all entries
 53	mov ax, 0                ; Start at 0
 54	
 55NextRootEntry:
 56	xchg cx, dx              ; We use cx in the inner loop
 57	mov si, BootFileName     ; Start searching for stage2 filename
 58	mov cx, 11
 59	rep cmpsb
 60	je FoundFileToLoad       ; Pointer DI will be at offset 11
 61	add ax, 32               ; Bump by one entry (32 bytes per entry)
 62	mov di, Buffer           ; Point to next entry
 63	add di, ax
 64	xchg dx, cx              ; Get cx back
 65	loop NextRootEntry
 66	mov si, NoFile
 67	call PrintString
 68	jmp Reboot
 69	
 70FoundFileToLoad:             ; Let's load the FAT into RAM
 71	mov ax, word[es:di+0x0F] ; Offset 11+15=26 contains our first cluster
 72	mov word[Cluster], ax
 73	mov ax, 1                ; Sector 1 = first sector of FAT
 74	call l2hts
 75	mov di, Buffer
 76	mov bx, di               ; ES:BX points to our buffer
 77	mov ah, 2                ; int 0x13 params: read FAT sectors
 78	mov al, 9                ; All 9 sectors of first FAT
 79	pusha                    ; Push registers to stack to prepare for loop
 80	
 81ReadFat:
 82	popa                     ; In case int 0x13 modified anything
 83	pusha
 84	stc
 85	int 0x13                 ; Read sectors using BIOS
 86	jnc ReadFatOkay          ; If read was okay, skip ahead
 87	call ResetFloppy         ; Otherwise, reset floppy and try again
 88	jnc ReadFat              ; Floppy reset OK?
 89	mov si, DiskError
 90	call PrintString         ; If not, print an error and reboot
 91	jmp Reboot
 92
 93ReadFatOkay:
 94	popa
 95	mov ax, 0x7E00           ; Segment where we're loading kernel
 96	mov es, ax
 97	mov bx, 0
 98	mov ah, 2                ; int 0x13 read params
 99	mov al, 1
100	push ax                  ; Save in case it gets lost
101	
102; We're gonna load the FAT from the disk now
103
104LoadFileSector:
105	mov ax, word [Cluster]   ; Convert sector to logical
106	add ax, 31
107	call l2hts
108	mov ax, 0x7E00           ; Set buffer past what we've read
109	mov es, ax
110	mov bx, word [Pointer]
111	pop ax                   ; Save in case it gets lost
112	push ax
113	stc
114	int 0x13
115	jnc CalculateNextCluster ; If there's no error
116	call ResetFloppy         ; If there is, reset floppy
117	jmp LoadFileSector
118	
119CalculateNextCluster:
120	mov ax, [Cluster]
121	mov dx, 0
122	mov bx, 3
123	mul bx
124	mov bx, 2
125	div bx                   ; DX = [Cluster] mod 2
126	mov si, Buffer
127	add si, ax               ; AX = word in FAT for 12 bit entry
128	mov ax, word [ds:si]
129	or dx, dx                ; If DX = 0 [Cluster] is even; if 1, [Cluster] is odd
130	jz even                  ; If [Cluster] is even, drop last 4 bits of word with
131	                         ; next clusters; if odd, drop first 4 bits
132							 
133odd:
134	shr ax, 4
135	jmp short NextClusterCont
136	
137even:
138	and ax, 0x0FFF           ; Mask out final four bits
139	
140NextClusterCont:
141	mov word [Cluster], ax   ; Store cluster
142	cmp ax, 0x0FF8           ; 0xFF8 = end of file in FAT12
143	jae end
144	add word [Pointer], 512  ; Increase buffer point 1 sector
145	jmp LoadFileSector
146	
147end:                         ; Hooray, we've reached the end and got the file to load!
148	pop ax                   ; Clean up stack, as we pushed AX earlier
149	mov dl, byte[BootDev]    ; Provide Kernel with boot device info
150	
151	mov si, BeforePMode
152	call PrintString
153	
154	                         ; BEFORE WE JUMP TO KERNEL BELOW WE WANT TO SET UP PROTECTED MODE!
155							 
156	cli                      ; We can't use these anymore!
157	; We have to enable the A20 line first, so that's what we'll do. It's boring and stupid.
158	call wkc                 ; Wait for keyboard buffer to clear
159	mov al, 0xD1             ; We want to write to output port
160	out 0x64, al
161	call wkc                 ; Wait for keyboard buffer again
162	mov al, 0xDF             ; Set A20 gate
163	out 0x60, al             ; Send value to data reg
164	call wkc                 ; Again...
165	mov cx, 0x10
166	kbdwait:
167		xor ax, ax           ; Waste time
168		out 0xE0, ax         ; Waste more time
169		loop kbdwait         ; Loop and waste even more time
170		
171	; Was A20 enabled?
172	mov al, 0xD0
173	out 0x64, al             ; Tell the controller we want to read output port
174	call wkf                 ; Wait for the data to get in it
175	in al, 0x60              ; Get it
176	test al, 2               ; Is A20 on?
177	jnz A20On                ; Not zero - we're good
178	                         ; Otherwise, we failed
179	mov si, A20Failure
180	call PrintString
181	hlt
182	jmp $
183	
184A20On:
185	xor ax, ax
186	mov ds, ax
187	lgdt [gdt_desc]
188	mov eax, cr0             ; Clear this bit, signaling the processor to enter protected mode
189	or eax, 1
190	mov cr0, eax
191	jmp 0x08:ClearPipe
192
193[BITS 32]
194ClearPipe:                    ; We need 32 bit now
195	mov ax, 0x10              ; Save data segment identifier
196	mov ds, ax                ; Move valid data segment into data segment register
197	mov ss, ax                ; Move valid data segment into stack segment register
198	mov esp, 0x090000         ; Move stack pointer to 0x090000
199	mov byte [ds:0x0B8000], 'P'
200	mov byte [ds:0x0B8000], 0x1B ; Here we're just testing to make sure we entered
201								 ; protected mode without issues.
202	jmp 0x08:0x07E00           ; Jump to entry point of stage2!
203	jmp $                     ; Continually jump here just in case kernel decides to return
204	
205; Subroutines below
206[BITS 16]
207Reboot:
208	mov ax, 0
209	int 0x16                 ; Wait for keystroke
210	mov ax, 0
211	int 0x19                 ; Reboot
212	
213PrintString:
214	pusha
215	mov ax, 0x0E
216	
217.repeat:
218	lodsb
219	cmp al, 0
220	je .done                 ; If char is 0, we've reached the end of the string
221	int 0x10                 ; Otherwise, we print it
222	jmp short .repeat
223	
224.done:
225	popa
226	ret
227	
228ResetFloppy:                 ; Carry set on error
229	push ax
230	push dx
231	mov ax, 0
232	mov dl, byte [BootDev]
233	stc
234	int 0x13
235	pop dx
236	pop ax
237	ret
238	
239l2hts:                       ; Calculate head, track and sector for int 0x13
240	push bx
241	push ax
242	mov bx, ax
243	mov dx, 0
244	div word [18]
245	add dl, 0x01
246	mov cl, dl
247	mov ax, bx
248	mov dx, 0
249	div word [18]
250	mov dx, 0
251	div word [2]
252	mov dh, dl
253	mov ch, al
254	pop ax
255	pop bx
256	mov dl, byte [BootDev]
257	ret
258	
259wkc:
260	xor al, al
261	in al, 0x64
262	test al, 2
263	jnz wkc
264	ret
265	
266wkf:
267	xor cx, cx
268	in al, 0x64
269	test al, 1
270	jz wkf
271	ret
272	
273BootFileName db "KERNEL  BIN"
274DiskError db "FATAL: Disk error! Press any key to reboot...", 0
275NoFile db "FATAL: KERNEL.BIN not found!", 0
276A20Failure db "FATAL: A20 failed to enable!", 0
277BeforePMode db "About to enter protected mode...", 0
278S2Message db "Stage2 entered", 0
279BootDev db 0
280Cluster dw 0
281Pointer dw 0
282
283gdt:
284gdt_null:
285	dd 0
286	dd 0
287gdt_code:
288	dw 0x0FFFF
289	dw 0
290	db 0
291	db 10011010b
292	db 11001111b
293	db 0
294gdt_data:
295	dw 0x0FFFF
296	dw 0
297	db 0
298	db 10010010b
299	db 11001111b
300	db 0
301gdt_end:
302gdt_desc:
303	dw gdt_end - gdt - 1
304	dd gdt
305	
306Buffer: