2 ; Boot sector for GeekOS
3 ; Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
4 ; Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
7 ; This is free software. You are permitted to use,
8 ; redistribute, and modify it as specified in the file "COPYING".
10 ; Loads setup code and a program image from sectors 1..n of a floppy
11 ; and executes the setup code (which will in turn execute
14 ; Some of this code is adapted from Kernel Toolkit 0.2
15 ; and Linux version 2.2.x, so the following copyrights apply:
17 ; Copyright (C) 1991, 1992 Linus Torvalds
18 ; modified by Drew Eckhardt
19 ; modified by Bruce Evans (bde)
20 ; adapted for Kernel Toolkit by Luigi Sgro
25 ; Pad to desired offset from start symbol.
26 ; Usage: Pad_From_Symbol offset, symbol
27 %macro Pad_From_Symbol 2
28 times (%1 - ($ - %2)) db 0
31 ; ----------------------------------------------------------------------
33 ; ----------------------------------------------------------------------
38 BeginText: ; needed to calculate padding bytes to fill the sector
40 ; Copy the boot sector into INITSEG.
42 mov ds, ax ; source segment for string copy
43 xor si, si ; source index for string copy
45 mov es, ax ; destination segment for string copy
46 xor di, di ; destination index for string copy
47 cld ; clear direction flag
48 mov cx, 256 ; number of words to copy
49 rep movsw ; copy 512 bytes
51 jmp INITSEG:after_move
54 ; Now we're executing in INITSEG
57 ; We want the data segment to refer to INITSEG
58 ; (since we've defined variables in the same place as the code)
59 mov ds, ax ; ax still contains INITSEG
61 ; Put the stack in the place where we were originally loaded.
62 ; By definition, there is nothing important there now.
65 mov sp, (BOOTSEG << 4) + 512 - 2
69 ; Load the setup code.
70 mov ax, word [setupStart]
71 mov word [sec_count], ax
73 mov word [max_sector], ax
76 push ax ; 1st param to ReadSector (log sec num)
77 push word SETUPSEG ; 2nd param to ReadSector (seg base)
78 sub ax, [setupStart] ; convert to 0-indexed
79 shl ax, 9 ; multiply by 512
80 push ax ; ...to get 3rd param (byte offset)
82 ; read the sector from the floppy
84 add sp, 6 ; clear 3 word params
90 mov bx, word [max_sector]
91 cmp word [sec_count], bx
96 ; Load the kernel image from sectors KERN_START_SEC..n of the
97 ; floppy into memory at KERNSEG. Note that there are 128 sectors
98 ; per 64K segment. So, when figuring out which segment to
99 ; load the sector into, we shift right by 7 bits (which is
100 ; equivalent to dividing by 128).
102 ; Figure out start sector and max sector
104 mov ax, word [kernelStart]
105 mov word [sec_count], ax
106 add ax, word [kernelSize]
107 mov word [max_sector], ax
111 mov ax, [sec_count] ; logical sector on the floppy
115 push ax ; 1st param to ReadSector (log sec num)
116 sub ax, [kernelStart] ; convert to 0-indexed
117 mov cx, ax ; save in cx
118 shr ax, 7 ; divide by 128
119 shl ax, 12 ; ...and multiply by 0x1000
120 add ax, KERNSEG ; ...to get base relative to KERNSEG
124 push ax ; 2nd param to ReadSector (seg base)
125 and cx, 0x7f ; mod sector by 128
126 shl cx, 9 ; ...and multiply by 512
127 push cx ; to get offset in segment (3rd parm)
133 ; read the sector from the floppy
135 add sp, 6 ; clear 3 word params
141 ; have we loaded all of the sectors?
142 mov bx, word [max_sector]
143 cmp word [sec_count], bx
164 ;; determine the actual kernel size
165 mov cx, word [kernelSize] ; number of 512 byte sectors
166 shl cx, 8 ; multiply by 9-1 to get number of bytes / 2 (words)
168 ;; Print out the size of the kernel
177 ;; Print out the return code to the screen
206 ; Now we've loaded the setup code and the kernel image.
207 ; Jump to setup code.
210 ; Read a sector from the floppy drive.
211 ; This code (and the rest of this boot sector) will have to
212 ; be re-written at some point so it reads more than one
216 ; - "logical" sector number [bp+8]
217 ; - destination segment [bp+6]
218 ; - destination offset [bp+4]
220 push bp ; set up stack frame
222 pusha ; save all registers
237 ; Sector = log_sec % SECTORS_PER_TRACK
238 ; Head = (log_sec / SECTORS_PER_TRACK) % HEADS
239 mov ax, [bp+8] ; get logical sector number from stack
240 xor dx, dx ; dx is high part of dividend (== 0)
241 mov bx, SECTORS_PER_TRACK ; divisor
242 div bx ; do the division
243 mov [sec], dx ; sector is the remainder
244 and ax, 1 ; same as mod by HEADS==2 (slight hack)
247 ; Track = log_sec / (SECTORS_PER_TRACK*HEADS)
248 mov ax, [bp+8] ; get logical sector number again
249 xor dx, dx ; dx is high part of dividend
250 mov bx, SECTORS_PER_TRACK*2 ; divisor
251 div bx ; do the division
252 mov [track], ax ; track is quotient
267 ; Now, try to actually read the sector from the floppy,
268 ; retrying up to 3 times.
270 mov [num_retries], byte 0
273 mov ax, [bp+6] ; dest segment...
274 mov es, ax ; goes in es
275 mov ax, (0x02 << 8) | 1 ; function = 02h in ah,
277 mov bx, [track] ; track number...
278 mov ch, bl ; goes in ch
279 mov bx, [sec] ; sector number...
280 mov cl, bl ; goes in cl...
281 inc cl ; but it must be 1-based, not 0-based
282 mov bx, [head] ; head number...
283 mov dh, bl ; goes in dh
284 xor dl, dl ; hard code drive=0
285 mov bx, [bp+4] ; offset goes in bx
286 ; (es:bx points to buffer)
287 ; Call the BIOS Read Diskette Sectors service
290 ; If the carry flag is NOT set, then there was no error
294 ; Error - code stored in ah
297 inc byte [num_retries]
298 cmp byte [num_retries], 3
301 ; If we got here, we failed thrice, so we give up
307 popa ; restore all regisiters
308 pop bp ; leave stack frame
311 ; Include utility routines:
313 ; REPLACED WITH FOLLOWING WHICH MUST BE COMPILED 16 FOR USE IN THIS CODE
316 mov cx, 4 ; 4 hex digits
318 rol dx, 4 ; rotate so that lowest 4 bits are used
319 mov ax, 0E0Fh ; ah = request, al = mask for nybble
321 add al, 90h ; convert al to ascii hex (four instructions)
322 daa ; I've spent 1 hour to understand how it works..
331 PrintNL: ; print CR and NL
342 ; ----------------------------------------------------------------------
344 ; ----------------------------------------------------------------------
346 ; These are used by ReadSector
352 ; Used for loops reading sectors from floppy
365 db 0x00,0x00,0x01 ; ! base = 0x010000
367 dw 0 ; ! limit16,base24 =0
371 db 0,0,0x10 ; ! base = 0x100000
373 dw 0 ; ! limit16,base24 =0
374 dw 0,0,0,0 ; ! BIOS CS
375 dw 0,0,0,0 ; ! BIOS DS
378 ; Padding to make the PFAT Boot Record sit just before the BIOS signature.
379 ;Pad_From_Symbol PFAT_BOOT_RECORD_OFFSET, BeginText
382 ; Describes how to load the setup program and kernel.
383 ; The default values are appropriate for creating a boot
384 ; floppy by concatenating the boot sector, setup program,
385 ; and kernel image. The buildFat program will change
386 ; these values if the boot floppy is formatted as a PFAT
403 ;; part of pfat boot record
405 dw 1 ; by default, setup is at first sector
407 ;; part of pfat boot record
409 dw NUM_SETUP_SECTORS ; number of sectors in setup
411 ;; part of pfat boot record
413 dw 1+NUM_SETUP_SECTORS ; default start sector for kernel
415 ;; part of pfat boot record
422 ; Finish by writing the BIOS signature to mark this as
423 ; a valid boot sector.
424 Pad_From_Symbol BIOS_SIGNATURE_OFFSET, BeginText
425 Signature dw 0xAA55 ; BIOS controls this to ensure this is a boot sector