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.


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