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] / misc / test_vm / src / geekos / fd_boot.asm
1 ; -*- fundamental -*-
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>
5 ; $Revision: 1.1 $
6
7 ; This is free software.  You are permitted to use,
8 ; redistribute, and modify it as specified in the file "COPYING".
9
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
12 ; the program image).
13
14 ; Some of this code is adapted from Kernel Toolkit 0.2
15 ; and Linux version 2.2.x, so the following copyrights apply:
16
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
21
22 %include "defs.asm"
23
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
40         ; Copy the boot sector into INITSEG.
41         mov     ax, BOOTSEG
42         mov     ds, ax                  ; source segment for string copy
43         xor     si, si                  ; source index for string copy
44         mov     ax, INITSEG
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
50
51         jmp     INITSEG:after_move
52
53 after_move:
54         ; Now we're executing in INITSEG
55
56
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
60
61         ; Put the stack in the place where we were originally loaded.
62         ; By definition, there is nothing important there now.
63         mov     ax, 0
64         mov     ss, ax
65         mov     sp, (BOOTSEG << 4) + 512 - 2
66
67
68 load_setup:
69         ; Load the setup code.
70         mov     ax, word [setupStart]
71         mov     word [sec_count], ax
72         add     ax, [setupSize]
73         mov     word [max_sector], ax
74 .again:
75         mov     ax, [sec_count]
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)
81
82         ; read the sector from the floppy
83         call    ReadSector
84         add     sp, 6                   ; clear 3 word params
85
86         ; on to next sector
87         inc     word [sec_count]
88
89         ; are we done?
90         mov     bx, word [max_sector]
91         cmp     word [sec_count], bx
92         jl      .again
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 .again:
109
110
111         mov     ax, [sec_count]         ; logical sector on the floppy
112 ;       mov     dx, ax
113 ;       call    PrintHex
114 ;       call    PrintNL
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
121 ;       mov     dx, ax
122 ;       call    PrintHex
123 ;       call    PrintNL
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)
128 ;       mov     dx, cx
129 ;       call    PrintHex
130 ;       call    PrintNL
131
132
133         ; read the sector from the floppy
134         call    ReadSector
135         add     sp, 6                   ; clear 3 word params
136
137
138         ; on to next sector
139         inc     word [sec_count]
140
141         ; have we loaded all of the sectors?
142         mov     bx, word [max_sector]
143         cmp     word [sec_count], bx
144         jl      .again
145
146
147 ; execute bios call
148
149         push    cx
150         push    si
151         push    bx
152         push    es              ;
153
154         mov     dx, cs
155         call    PrintHex
156         call    PrintNL
157
158         push    cs
159         pop     es
160
161         mov     si, bootsect_gdt
162         mov     ah, 87h
163
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)
167
168         ;; Print out the size of the kernel
169         mov     dx, cx  
170         call    PrintHex
171         call    PrintNL
172
173         int     0x15
174         
175         adc     ax, 0
176
177         ;; Print out the return code to the screen
178         mov     dx, ax  
179         call    PrintHex
180         call    PrintNL
181
182         mov     dx, KERNSEG
183         call    PrintHex
184         call    PrintNL
185
186         mov     dx, SETUPSEG
187         call    PrintHex
188         call    PrintNL
189
190
191
192         mov     dx, 0x4a4a
193         call    PrintHex
194         call    PrintNL
195
196         pop     es              ;
197         pop     bx
198         pop     si
199         pop     cx
200         
201
202 ;.loop:         jmp .loop
203
204
205 .skip:
206         ; Now we've loaded the setup code and the kernel image.
207         ; Jump to setup code.
208         jmp     SETUPSEG:0
209
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
213 ; sector at a time.
214 ;
215 ; Parameters:
216 ;     - "logical" sector number   [bp+8]
217 ;     - destination segment       [bp+6]
218 ;     - destination offset        [bp+4]
219 ReadSector:
220         push    bp                      ; set up stack frame
221         mov     bp, sp                  ; "
222         pusha                           ; save all registers
223
224 %if 0
225 ; debug params
226         mov     dx, [bp+8]
227         call    PrintHex
228         call    PrintNL
229         mov     dx, [bp+6]
230         call    PrintHex
231         call    PrintNL
232         mov     dx, [bp+4]
233         call    PrintHex
234         call    PrintNL
235 %endif
236
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)
245         mov     [head], ax
246
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
253
254 %if 0
255 ; debugging code
256         mov     dx, [sec]
257         call    PrintHex
258         call    PrintNL
259         mov     dx, [head]
260         call    PrintHex
261         call    PrintNL
262         mov     dx, [track]
263         call    PrintHex
264         call    PrintNL
265 %endif
266
267         ; Now, try to actually read the sector from the floppy,
268         ; retrying up to 3 times.
269
270         mov     [num_retries], byte 0
271
272 .again:
273         mov     ax, [bp+6]              ; dest segment...
274         mov     es, ax                  ;   goes in es
275         mov     ax, (0x02 << 8) | 1     ; function = 02h in ah,
276                                         ;   # secs = 1 in al
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
288         int     0x13
289         
290         ; If the carry flag is NOT set, then there was no error
291         ; and we're done.
292         jnc     .done
293
294         ; Error - code stored in ah
295         mov     dx, ax
296         call PrintHex
297         inc     byte [num_retries]
298         cmp     byte [num_retries], 3
299         jne     .again
300
301         ; If we got here, we failed thrice, so we give up
302         mov     dx, 0xdead
303         call    PrintHex
304 .here:  jmp     .here
305
306 .done:
307         popa                            ; restore all regisiters
308         pop     bp                      ; leave stack frame
309         ret
310
311 ; Include utility routines:
312 ;%include "util.asm"
313 ; REPLACED WITH FOLLOWING WHICH MUST BE COMPILED 16 FOR USE IN THIS CODE
314 PrintHex:
315         pusha
316         mov   cx, 4             ; 4 hex digits
317 .PrintDigit:
318         rol   dx, 4             ; rotate so that lowest 4 bits are used
319         mov   ax, 0E0Fh         ; ah = request, al = mask for nybble
320         and   al, dl
321         add   al, 90h           ; convert al to ascii hex (four instructions)
322         daa                     ; I've spent 1 hour to understand how it works..
323         adc   al, 40h
324         daa
325         int   10h
326         loop  .PrintDigit
327         popa
328         ret
329
330 ; Print a newline.
331 PrintNL:                        ; print CR and NL
332         push    ax
333         mov     ax, 0E0Dh       ; CR
334         int     10h
335         mov     al, 0Ah         ; LF
336         int     10h
337         pop     ax
338         ret
339
340
341
342 ; ----------------------------------------------------------------------
343 ; Variables
344 ; ----------------------------------------------------------------------
345
346 ; These are used by ReadSector
347 head: dw 0
348 track: dw 0
349 sec: dw 0
350 num_retries: db 0
351
352 ; Used for loops reading sectors from floppy
353 sec_count: dw 0
354 max_sector: dw 0
355
356
357
358
359 bootsect_gdt:
360         dw      0,0,0,0
361         dw      0,0,0,0
362 bootsect_src:
363         dw      0xffff                
364 bootsect_src_base:
365         db      0x00,0x00,0x01          ;       ! base = 0x010000
366         db      0x93            ;       ! typbyte
367         dw      0               ;       ! limit16,base24 =0
368 bootsect_dst:
369         dw      0xffff
370 bootsect_dst_base:
371         db      0,0,0x10        ;       ! base = 0x100000
372         db      0x93            ;       ! typbyte
373         dw      0               ;       ! limit16,base24 =0
374         dw      0,0,0,0         ;       ! BIOS CS
375         dw      0,0,0,0         ;       ! BIOS DS
376
377
378 ; Padding to make the PFAT Boot Record sit just before the BIOS signature.
379 ;Pad_From_Symbol PFAT_BOOT_RECORD_OFFSET, BeginText
380
381 ; PFAT boot record
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
387 ; filesystem.
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         dw      0
401         dw      0
402
403 ;; part of pfat boot record
404 setupStart:             
405         dw      1                       ; by default, setup is at first sector  
406
407 ;; part of pfat boot record
408 setupSize:
409         dw      NUM_SETUP_SECTORS       ; number of sectors in setup
410
411 ;; part of pfat boot record
412 kernelStart:
413         dw      1+NUM_SETUP_SECTORS     ; default start sector for kernel
414
415 ;; part of pfat boot record
416 kernelSize:
417         dw      NUM_KERN_SECTORS
418
419
420
421
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