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.


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