1 ; Boot sector for GeekOS
2 ; Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
5 ; This is free software. You are permitted to use,
6 ; redistribute, and modify it as specified in the file "COPYING".
8 ; Loads setup code and a program image from sectors 1..n of a floppy
9 ; and executes the setup code (which will in turn execute
12 ; Some of this code is adapted from Kernel Toolkit 0.2
13 ; and Linux version 2.2.x, so the following copyrights apply:
15 ; Copyright (C) 1991, 1992 Linus Torvalds
16 ; modified by Drew Eckhardt
17 ; modified by Bruce Evans (bde)
18 ; adapted for Kernel Toolkit by Luigi Sgro
22 ; This macro is used to calculate padding needed
23 ; to ensure that the boot sector is exactly 512 bytes
24 ; in size. The argument is the desired offset to be
27 times (%1 - ($ - BeginText)) db 0
30 KERN_START_SEC equ (NUM_SETUP_SECTORS + 1)
32 BIOS_SIGNATURE_OFFSET equ 510
34 ; ----------------------------------------------------------------------
36 ; ----------------------------------------------------------------------
41 BeginText: ; needed to calculate padding bytes to fill the sector
43 ; Copy the boot sector into INITSEG.
45 mov ds, ax ; source segment for string copy
46 xor si, si ; source index for string copy
48 mov es, ax ; destination segment for string copy
49 xor di, di ; destination index for string copy
50 cld ; clear direction flag
51 mov cx, 256 ; number of words to copy
52 rep movsw ; copy 512 bytes
54 jmp INITSEG:after_move
57 ; Now we're executing in INITSEG
59 ; We want the data segment to refer to INITSEG
60 ; (since we've defined variables in the same place as the code)
61 mov ds, ax ; ax still contains INITSEG
63 ; Put the stack in the place where we were originally loaded.
64 ; By definition, there is nothing important there now.
67 mov sp, (BOOTSEG << 4) + 512 - 2
70 ; Load the setup code.
71 mov word [sec_count], 1
74 push ax ; 1st param to ReadSector (log sec num)
75 push word SETUPSEG ; 2nd param to ReadSector (seg base)
76 dec ax ; 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 cmp word [sec_count], NUM_SETUP_SECTORS
92 ; Load the kernel image from sectors KERN_START_SEC..n of the
93 ; floppy into memory at KERNSEG. Note that there are 128 sectors
94 ; per 64K segment. So, when figuring out which segment to
95 ; load the sector into, we shift right by 7 bits (which is
96 ; equivalent to dividing by 128).
97 mov word [sec_count], KERN_START_SEC
99 mov ax, [sec_count] ; logical sector on the floppy
100 push ax ; 1st param to ReadSector (log sec num)
101 sub ax, KERN_START_SEC ; convert to 0-indexed
102 mov cx, ax ; save in cx
103 shr ax, 7 ; divide by 128
104 shl ax, 12 ; ...and multiply by 0x1000
105 add ax, KERNSEG ; ...to get base relative to KERNSEG
106 push ax ; 2nd param to ReadSector (seg base)
107 and cx, 0x7f ; mod sector by 128
108 shl cx, 9 ; ...and multiply by 512
109 push cx ; to get offset in segment (3rd parm)
111 ; read the sector from the floppy
113 add sp, 6 ; clear 3 word params
118 ; have we loaded all of the sectors?
119 cmp word [sec_count], KERN_START_SEC+NUM_KERN_SECTORS
122 ; Now we've loaded the setup code and the kernel image.
123 ; Jump to setup code.
126 ; Read a sector from the floppy drive.
127 ; This code (and the rest of this boot sector) will have to
128 ; be re-written at some point so it reads more than one
132 ; - "logical" sector number [bp+8]
133 ; - destination segment [bp+6]
134 ; - destination offset [bp+4]
136 push bp ; set up stack frame
138 pusha ; save all registers
153 ; Sector = log_sec % SECTORS_PER_TRACK
154 ; Head = (log_sec / SECTORS_PER_TRACK) % HEADS
155 mov ax, [bp+8] ; get logical sector number from stack
156 xor dx, dx ; dx is high part of dividend (== 0)
157 mov bx, SECTORS_PER_TRACK ; divisor
158 div bx ; do the division
159 mov [sec], dx ; sector is the remainder
160 and ax, 1 ; same as mod by HEADS==2 (slight hack)
163 ; Track = log_sec / (SECTORS_PER_TRACK*HEADS)
164 mov ax, [bp+8] ; get logical sector number again
165 xor dx, dx ; dx is high part of dividend
166 mov bx, SECTORS_PER_TRACK*2 ; divisor
167 div bx ; do the division
168 mov [track], ax ; track is quotient
183 ; Now, try to actually read the sector from the floppy,
184 ; retrying up to 3 times.
186 mov [num_retries], byte 0
189 mov ax, [bp+6] ; dest segment...
190 mov es, ax ; goes in es
191 mov ax, (0x02 << 8) | 1 ; function = 02h in ah,
193 mov bx, [track] ; track number...
194 mov ch, bl ; goes in ch
195 mov bx, [sec] ; sector number...
196 mov cl, bl ; goes in cl...
197 inc cl ; but it must be 1-based, not 0-based
198 mov bx, [head] ; head number...
199 mov dh, bl ; goes in dh
200 xor dl, dl ; hard code drive=0
201 mov bx, [bp+4] ; offset goes in bx
202 ; (es:bx points to buffer)
204 ; Call the BIOS Read Diskette Sectors service
207 ; If the carry flag is NOT set, then there was no error
211 ; Error - code stored in ah
214 inc byte [num_retries]
215 cmp byte [num_retries], 3
218 ; If we got here, we failed thrice, so we give up
224 popa ; restore all regisiters
225 pop bp ; leave stack frame
228 ; Include utility routines
231 ; ----------------------------------------------------------------------
233 ; ----------------------------------------------------------------------
235 ; These are used by ReadSector
242 ; Used for loops reading sectors from floppy
246 PadFromStart BIOS_SIGNATURE_OFFSET
247 Signature dw 0xAA55 ; BIOS controls this to ensure this is a boot sector