Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / geekos / fd_boot.asm
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>
4 ; Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu
5 ; Copyright (c) 2008, Peter Dinda <pdinda@northwestern.edu
6 ; $Revision: 1.8 $
7
8 ; This is free software.  You are permitted to use,
9 ; redistribute, and modify it as specified in the file "COPYING".
10
11 ; Loads setup code and a program image from sectors 1..n of a floppy
12 ; and executes the setup code (which will in turn execute
13 ; the program image).
14
15 ; Some of this code is adapted from Kernel Toolkit 0.2
16 ; and Linux version 2.2.x, so the following copyrights apply:
17
18 ; Copyright (C) 1991, 1992 Linus Torvalds
19 ; modified by Drew Eckhardt
20 ; modified by Bruce Evans (bde)
21 ; adapted for Kernel Toolkit by Luigi Sgro
22
23 %include "defs.asm"
24
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
29 %endmacro
30
31 ; ----------------------------------------------------------------------
32 ; The actual code
33 ; ----------------------------------------------------------------------
34
35 [BITS 16]
36 [ORG 0x0]
37
38 BeginText:      ; needed to calculate padding bytes to fill the sector
39         ; Copy the boot sector into INITSEG.
40         mov     ax, BOOTSEG
41         mov     ds, ax                  ; source segment for string copy
42         xor     si, si                  ; source index for string copy
43         mov     ax, INITSEG
44         mov     es, ax                  ; destination segment for string copy
45         xor     di, di                  ; destination index for string copy
46         cld                             ; clear direction flag
47         mov     cx, 256                 ; number of words to copy
48         rep     movsw                   ; copy 512 bytes
49
50         jmp     INITSEG:after_move
51
52 after_move:
53         ; Now we're executing in INITSEG
54
55
56         ; We want the data segment to refer to INITSEG
57         ; (since we've defined variables in the same place as the code)
58         mov     ds, ax                  ; ax still contains INITSEG
59
60         ; Put the stack in the place where we were originally loaded.
61         ; By definition, there is nothing important there now.
62         mov     ax, 0
63         mov     ss, ax
64         mov     sp, (BOOTSEG << 4) + 512 - 2
65
66
67 load_setup:
68         ; Load the setup code.
69         mov     ax, word [setupStart]
70         mov     word [sec_count], ax
71         add     ax, [setupSize]
72         mov     word [max_sector], ax
73 .again:
74         mov     ax, [sec_count]
75         push    ax                      ; 1st param to ReadSector (log sec num)
76         push    word SETUPSEG           ; 2nd param to ReadSector (seg base)
77         sub     ax, [setupStart]        ; convert to 0-indexed
78         shl     ax, 9                   ; multiply by 512
79         push    ax                      ;  ...to get 3rd param (byte offset)
80
81         ; read the sector from the floppy
82         call    ReadSector
83         add     sp, 6                   ; clear 3 word params
84
85         ; on to next sector
86         inc     word [sec_count]
87
88         ; are we done?
89         mov     bx, word [max_sector]
90         cmp     word [sec_count], bx
91         jl      .again
92
93
94         
95 load_kernel:
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).
101
102         ; Figure out start sector and max sector
103
104         mov     ax, word [kernelStart]
105         mov     word [sec_count], aX
106         add     ax, word [kernelSize]
107         mov     word [max_sector], ax
108
109         
110 .again2:
111
112         mov     ax, [sec_count]         ; logical sector on the floppy
113         push    ax                      ; 1st param to ReadSector (log sec num)
114
115 ;       mov     dx, ax
116 ;       call    PrintHex
117 ;       call    PrintNL
118
119         mov     ax, VMSEG               ;  ...to get base relative to VMSEG
120         push    ax                      ; 2nd param to ReadSector (seg base)
121         
122 ;       mov     dx, ax          ; 
123 ;       call    PrintHex
124 ;       call    PrintNL
125
126         mov     ax, 2000h               ; Always write at the start of the segment
127         push    ax              ; 3rd parameter
128
129 ;       mov     dx, ax
130 ;       call    PrintHex
131 ;       call    PrintNL
132
133         ; read the sector from the floppy
134         call    ReadSector
135         add     sp, 6                   ; clear 3 word params
136
137         push    VMSEG
138         pop     es
139
140 ;       mov     dx, word [es:2000h] ;
141 ;       call    PrintHex
142 ;       call    PrintNL
143         
144         
145
146 ; execute bios call
147
148         push    cx
149         push    si
150         push    bx
151         push    es              ; 
152
153         push    cs
154         pop     es
155         mov     si, bootsect_gdt
156         mov     ah, 87h
157
158         mov     cx, 100h
159
160         int     0x15
161         
162         adc     ax, 0
163
164 ;       mov     dx, ax  
165 ;       call    PrintHex
166 ;       call    PrintNL
167
168
169
170         pop     es              ;
171         pop     bx
172         pop     si
173         pop     cx
174         
175         ; on to next sector
176         inc     word [sec_count]
177
178
179         ; update the low->high copy table for the bios
180 ;       mov     ax, word [bootsect_src_base] ;
181 ;       add     ax, 512
182 ;       mov     dx,ax;
183 ;       call    PrintHex
184 ;       adc     byte [bootsect_src_base+2], 0
185 ;       mov     word [bootsect_src_base],ax
186
187         mov     ax, word [bootsect_dst_base] ;
188         add     ax, 512
189         adc     byte [bootsect_dst_base+2], 0
190         mov     word [bootsect_dst_base],ax
191         
192         ; have we loaded all of the sectors?
193
194         mov     bx, word [max_sector]
195         cmp     word [sec_count], bx
196
197
198 .stall
199 ;       jmp     .skip
200         jl      .again2
201
202 .skip
203         ; Now we've loaded the setup code and the kernel image.
204         ; Jump to setup code.
205         jmp     SETUPSEG:0
206
207 ; Read a sector from the floppy drive.
208 ; This code (and the rest of this boot sector) will have to
209 ; be re-written at some point so it reads more than one
210 ; sector at a time.
211 ;
212 ; Parameters:
213 ;     - "logical" sector number   [bp+8]
214 ;     - destination segment       [bp+6]
215 ;     - destination offset        [bp+4]
216 ReadSector:
217         push    bp                      ; set up stack frame
218         mov     bp, sp                  ; "
219         pusha                           ; save all registers
220
221 %if 0
222 ; debug params
223         mov     dx, [bp+8]
224         call    PrintHex
225         call    PrintNL
226         mov     dx, [bp+6]
227         call    PrintHex
228         call    PrintNL
229         mov     dx, [bp+4]
230         call    PrintHex
231         call    PrintNL
232 %endif
233
234         ; Sector = log_sec % SECTORS_PER_TRACK
235         ; Head = (log_sec / SECTORS_PER_TRACK) % HEADS
236         mov     ax, [bp+8]              ; get logical sector number from stack
237         xor     dx, dx                  ; dx is high part of dividend (== 0)
238         mov     bx, SECTORS_PER_TRACK   ; divisor
239         div     bx                      ; do the division
240         mov     [sec], dx               ; sector is the remainder
241         and     ax, 1                   ; same as mod by HEADS==2 (slight hack)
242         mov     [head], ax
243
244         ; Track = log_sec / (SECTORS_PER_TRACK*HEADS)
245         mov     ax, [bp+8]              ; get logical sector number again
246         xor     dx, dx                  ; dx is high part of dividend
247         mov     bx, SECTORS_PER_TRACK*2 ; divisor
248         div     bx                      ; do the division
249         mov     [track], ax             ; track is quotient
250
251 %if 0
252 ; debugging code
253         mov     dx, [sec]
254         call    PrintHex
255         call    PrintNL
256         mov     dx, [head]
257         call    PrintHex
258         call    PrintNL
259         mov     dx, [track]
260         call    PrintHex
261         call    PrintNL
262 %endif
263
264         ; Now, try to actually read the sector from the floppy,
265         ; retrying up to 3 times.
266
267         mov     [num_retries], byte 0
268
269 .again:
270         mov     ax, [bp+6]              ; dest segment...
271         mov     es, ax                  ;   goes in es
272         mov     ax, (0x02 << 8) | 1     ; function = 02h in ah,
273                                         ;   # secs = 1 in al
274         mov     bx, [track]             ; track number...
275         mov     ch, bl                  ;   goes in ch
276         mov     bx, [sec]               ; sector number...
277         mov     cl, bl                  ;   goes in cl...
278         inc     cl                      ;   but it must be 1-based, not 0-based
279         mov     bx, [head]              ; head number...
280         mov     dh, bl                  ;   goes in dh
281         xor     dl, dl                  ; hard code drive=0
282         mov     bx, [bp+4]              ; offset goes in bx
283                                         ;   (es:bx points to buffer)
284         ; Call the BIOS Read Diskette Sectors service
285         int     0x13
286         
287         ; If the carry flag is NOT set, then there was no error
288         ; and we're done.
289         jnc     .done
290
291         ; Error - code stored in ah
292         mov     dx, ax
293         call PrintHex
294         inc     byte [num_retries]
295         cmp     byte [num_retries], 3
296         jne     .again
297
298         ; If we got here, we failed thrice, so we give up
299         mov     dx, 0xdead
300         call    PrintHex
301 .here:  jmp     .here
302
303 .done:
304         popa                            ; restore all regisiters
305         pop     bp                      ; leave stack frame
306         ret
307
308 ; Include utility routines:
309 ;%include "util.asm"
310 ; REPLACED WITH FOLLOWING WHICH MUST BE COMPILED 16 FOR USE IN THIS CODE
311 PrintHex:
312         pusha
313         mov   cx, 4             ; 4 hex digits
314 .PrintDigit:
315         rol   dx, 4             ; rotate so that lowest 4 bits are used
316         mov   ax, 0E0Fh         ; ah = request, al = mask for nybble
317         and   al, dl
318         add   al, 90h           ; convert al to ascii hex (four instructions)
319         daa                     ; I've spent 1 hour to understand how it works..
320         adc   al, 40h
321         daa
322         int   10h
323         loop  .PrintDigit
324         popa
325         ret
326
327 ; Print a newline.
328 PrintNL:                        ; print CR and NL
329         push    ax
330         mov     ax, 0E0Dh       ; CR
331         int     10h
332         mov     al, 0Ah         ; LF
333         int     10h
334         pop     ax
335         ret
336
337
338
339 ; ----------------------------------------------------------------------
340 ; Variables
341 ; ----------------------------------------------------------------------
342
343 ; These are used by ReadSector
344 head: dw 0
345 track: dw 0
346 sec: dw 0
347 num_retries: db 0
348
349 ; Used for loops reading sectors from floppy
350 sec_count: dw 0
351 max_sector: dw 0
352
353
354
355
356 bootsect_gdt:
357         dw      0,0,0,0
358         dw      0,0,0,0
359 bootsect_src:
360         dw      0xffff                
361 bootsect_src_base:
362         db      0,0x20,0x08             ;       ! base = 0x082000 
363         db      0x93            ;       ! typbyte
364         dw      0               ;       ! limit16,base24 =0
365 bootsect_dst:
366         dw      0xffff
367 bootsect_dst_base:
368         db      0,0,0x10        ;       ! base = 0x100000
369         db      0x93            ;       ! typbyte
370         dw      0               ;       ! limit16,base24 =0
371         dw      0,0,0,0         ;       ! BIOS CS
372         dw      0,0,0,0         ;       ! BIOS DS
373
374
375 ; Padding to make the PFAT Boot Record sit just before the BIOS signature.
376 ;Pad_From_Symbol PFAT_BOOT_RECORD_OFFSET, BeginText
377
378 ; PFAT boot record
379 ; Describes how to load the setup program and kernel.
380 ; The default values are appropriate for creating a boot
381 ; floppy by concatenating the boot sector, setup program,
382 ; and kernel image.  The buildFat program will change
383 ; these values if the boot floppy is formatted as a PFAT
384 ; filesystem.
385         dw      0
386         dw      0
387
388         dw      0
389         dw      0
390
391         dw      0
392         dw      0
393
394         dw      0
395         dw      0
396
397         dw      0
398         dw      0
399
400 ;; part of pfat boot record
401 setupStart:             
402         dw      1                       ; by default, setup is at first sector  
403
404 ;; part of pfat boot record
405 setupSize:
406         dw      NUM_SETUP_SECTORS       ; number of sectors in setup
407
408 ;; part of pfat boot record
409 kernelStart:
410         dw      1+NUM_SETUP_SECTORS     ; default start sector for kernel
411
412 ;; part of pfat boot record
413 kernelSize:
414         dw      NUM_KERN_SECTORS
415
416
417
418
419         ; Finish by writing the BIOS signature to mark this as
420 ; a valid boot sector.
421 Pad_From_Symbol BIOS_SIGNATURE_OFFSET, BeginText
422 Signature   dw 0xAA55   ; BIOS controls this to ensure this is a boot sector