1 ; Boot sector for GeekOS
2 ; Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
3 ; Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
6 ; This is free software. You are permitted to use,
7 ; redistribute, and modify it as specified in the file "COPYING".
9 ; Loads setup code and a program image from sectors 1..n of a floppy
10 ; and executes the setup code (which will in turn execute
13 ; Some of this code is adapted from Kernel Toolkit 0.2
14 ; and Linux version 2.2.x, so the following copyrights apply:
16 ; Copyright (C) 1991, 1992 Linus Torvalds
17 ; modified by Drew Eckhardt
18 ; modified by Bruce Evans (bde)
19 ; adapted for Kernel Toolkit by Luigi Sgro
23 ; Pad to desired offset from start symbol.
24 ; Usage: Pad_From_Symbol offset, symbol
25 %macro Pad_From_Symbol 2
26 times (%1 - ($ - %2)) db 0
29 ; ----------------------------------------------------------------------
31 ; ----------------------------------------------------------------------
36 BeginText: ; needed to calculate padding bytes to fill the sector
38 ; Copy the boot sector into INITSEG.
40 mov ds, ax ; source segment for string copy
41 xor si, si ; source index for string copy
43 mov es, ax ; destination segment for string copy
44 xor di, di ; destination index for string copy
45 cld ; clear direction flag
46 mov cx, 256 ; number of words to copy
47 rep movsw ; copy 512 bytes
49 jmp INITSEG:after_move
52 ; Now we're executing in INITSEG
55 ; We want the data segment to refer to INITSEG
56 ; (since we've defined variables in the same place as the code)
57 mov ds, ax ; ax still contains INITSEG
59 ; Put the stack in the place where we were originally loaded.
60 ; By definition, there is nothing important there now.
63 mov sp, (BOOTSEG << 4) + 512 - 2
67 ; Load the setup code.
68 mov ax, word [setupStart]
69 mov word [sec_count], ax
71 mov word [max_sector], ax
74 push ax ; 1st param to ReadSector (log sec num)
75 push word SETUPSEG ; 2nd param to ReadSector (seg base)
76 sub ax, [setupStart] ; convert to 0-indexed
77 shl ax, 9 ; multiply by 512
78 push ax ; ...to get 3rd param (byte offset)
80 ; read the sector from the floppy
82 add sp, 6 ; clear 3 word params
88 mov bx, word [max_sector]
89 cmp word [sec_count], bx
93 ; Load the kernel image from sectors KERN_START_SEC..n of the
94 ; floppy into memory at KERNSEG. Note that there are 128 sectors
95 ; per 64K segment. So, when figuring out which segment to
96 ; load the sector into, we shift right by 7 bits (which is
97 ; equivalent to dividing by 128).
99 ; Figure out start sector and max sector
101 mov ax, word [kernelStart]
102 mov word [sec_count], ax
103 add ax, word [kernelSize]
104 mov word [max_sector], ax
106 mov ax, [sec_count] ; logical sector on the floppy
110 push ax ; 1st param to ReadSector (log sec num)
111 sub ax, [kernelStart] ; convert to 0-indexed
112 mov cx, ax ; save in cx
113 shr ax, 7 ; divide by 128
114 shl ax, 12 ; ...and multiply by 0x1000
115 add ax, KERNSEG ; ...to get base relative to KERNSEG
119 push ax ; 2nd param to ReadSector (seg base)
120 and cx, 0x7f ; mod sector by 128
121 shl cx, 9 ; ...and multiply by 512
122 push cx ; to get offset in segment (3rd parm)
128 ; read the sector from the floppy
130 add sp, 6 ; clear 3 word params
136 ; have we loaded all of the sectors?
137 mov bx, word [max_sector]
138 cmp word [sec_count], bx
142 ; Load the guest image starting at 1MB
143 ; floppy into memory at KERNSEG. Note that there are 128 sectors
144 ; per 64K segment. So, when figuring out which segment to
145 ; load the sector into, we shift right by 7 bits (which is
146 ; equivalent to dividing by 128).
148 ; Figure out start sector and max sector
149 mov ax, word [vmStart]
150 mov word [sec_count], ax
151 add ax, word [vmSize]
152 mov word [max_sector], ax
155 mov ax, [sec_count] ; logical sector on the floppy
156 push ax ; 1st param to ReadSector (log sec num)
162 mov ax, VMSEG ; ...to get base relative to VMSEG
163 push ax ; 2nd param to ReadSector (seg base)
169 mov ax, 2000h ; Always write at the start of the segment
170 push ax ; 3rd parameter
176 ; read the sector from the floppy
178 add sp, 6 ; clear 3 word params
208 ; update the low->high copy table for the bios
209 ; mov ax, word [bootsect_src_base] ;
213 ; adc byte [bootsect_src_base+2], 0
214 ; mov word [bootsect_src_base],ax
216 mov ax, word [bootsect_dst_base] ;
218 adc byte [bootsect_dst_base+2], 0
219 mov word [bootsect_dst_base],ax
221 ; have we loaded all of the sectors?
223 mov bx, word [max_sector]
224 cmp word [sec_count], bx
227 ; Now we've loaded the setup code and the kernel image.
228 ; Jump to setup code.
231 ; Read a sector from the floppy drive.
232 ; This code (and the rest of this boot sector) will have to
233 ; be re-written at some point so it reads more than one
237 ; - "logical" sector number [bp+8]
238 ; - destination segment [bp+6]
239 ; - destination offset [bp+4]
241 push bp ; set up stack frame
243 pusha ; save all registers
258 ; Sector = log_sec % SECTORS_PER_TRACK
259 ; Head = (log_sec / SECTORS_PER_TRACK) % HEADS
260 mov ax, [bp+8] ; get logical sector number from stack
261 xor dx, dx ; dx is high part of dividend (== 0)
262 mov bx, SECTORS_PER_TRACK ; divisor
263 div bx ; do the division
264 mov [sec], dx ; sector is the remainder
265 and ax, 1 ; same as mod by HEADS==2 (slight hack)
268 ; Track = log_sec / (SECTORS_PER_TRACK*HEADS)
269 mov ax, [bp+8] ; get logical sector number again
270 xor dx, dx ; dx is high part of dividend
271 mov bx, SECTORS_PER_TRACK*2 ; divisor
272 div bx ; do the division
273 mov [track], ax ; track is quotient
288 ; Now, try to actually read the sector from the floppy,
289 ; retrying up to 3 times.
291 mov [num_retries], byte 0
294 mov ax, [bp+6] ; dest segment...
295 mov es, ax ; goes in es
296 mov ax, (0x02 << 8) | 1 ; function = 02h in ah,
298 mov bx, [track] ; track number...
299 mov ch, bl ; goes in ch
300 mov bx, [sec] ; sector number...
301 mov cl, bl ; goes in cl...
302 inc cl ; but it must be 1-based, not 0-based
303 mov bx, [head] ; head number...
304 mov dh, bl ; goes in dh
305 xor dl, dl ; hard code drive=0
306 mov bx, [bp+4] ; offset goes in bx
307 ; (es:bx points to buffer)
310 ; Call the BIOS Read Diskette Sectors service
313 ; If the carry flag is NOT set, then there was no error
317 ; Error - code stored in ah
320 inc byte [num_retries]
321 cmp byte [num_retries], 3
324 ; If we got here, we failed thrice, so we give up
330 popa ; restore all regisiters
331 pop bp ; leave stack frame
334 ; Include utility routines:
336 ; REPLACED WITH FOLLOWING WHICH MUST BE COMPILED 16 FOR USE IN THIS CODE
339 mov cx, 4 ; 4 hex digits
341 rol dx, 4 ; rotate so that lowest 4 bits are used
342 mov ax, 0E0Fh ; ah = request, al = mask for nybble
344 add al, 90h ; convert al to ascii hex (four instructions)
345 daa ; I've spent 1 hour to understand how it works..
354 PrintNL: ; print CR and NL
365 ; ----------------------------------------------------------------------
367 ; ----------------------------------------------------------------------
369 ; These are used by ReadSector
375 ; Used for loops reading sectors from floppy
388 db 0,02,9 ; ! base = 0x092000
390 dw 0 ; ! limit16,base24 =0
394 db 0,0,0x10 ; ! base = 0x100000
396 dw 0 ; ! limit16,base24 =0
397 dw 0,0,0,0 ; ! BIOS CS
398 dw 0,0,0,0 ; ! BIOS DS
401 ; Padding to make the PFAT Boot Record sit just before the BIOS signature.
402 ;Pad_From_Symbol PFAT_BOOT_RECORD_OFFSET, BeginText
405 ; Describes how to load the setup program and kernel.
406 ; The default values are appropriate for creating a boot
407 ; floppy by concatenating the boot sector, setup program,
408 ; and kernel image. The buildFat program will change
409 ; these values if the boot floppy is formatted as a PFAT
426 ;; part of pfat boot record
428 dw 1 ; by default, setup is at first sector
430 ;; part of pfat boot record
432 dw NUM_SETUP_SECTORS ; number of sectors in setup
434 ;; part of pfat boot record
436 dw 1+NUM_SETUP_SECTORS ; default start sector for kernel
438 ;; part of pfat boot record
442 ;; part of pfat boot record
444 dw 1+NUM_SETUP_SECTORS+NUM_KERN_SECTORS
445 ;; part of pfat boot record
448 dw NUM_VM_KERNEL_SECTORS
451 ; Finish by writing the BIOS signature to mark this as
452 ; a valid boot sector.
453 Pad_From_Symbol BIOS_SIGNATURE_OFFSET, BeginText
454 Signature dw 0xAA55 ; BIOS controls this to ensure this is a boot sector