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.


This code now successfully does the Linux kernel load and
[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.3 $
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
181
182 ; execute bios call
183
184         push    cx
185         push    si
186         push    bx
187         push    es              ; 
188
189         push    cs
190         pop     es
191         mov     si, bootsect_gdt
192         mov     ax, 0x8700      ;
193         int     0x15
194
195         mov     dx, ax
196         call    PrintHex
197         call    PrintNL
198
199         pop     es              ;
200         pop     bx
201         pop     si
202         pop     cx
203         
204         ; on to next sector
205         inc     word [sec_count]
206
207
208         ; update the low->high copy table for the bios
209 ;       mov     ax, word [bootsect_src_base] ;
210 ;       add     ax, 512
211 ;       mov     dx,ax;
212 ;       call    PrintHex
213 ;       adc     byte [bootsect_src_base+2], 0
214 ;       mov     word [bootsect_src_base],ax
215
216         mov     ax, word [bootsect_dst_base] ;
217         add     ax, 512
218         adc     byte [bootsect_dst_base+2], 0
219         mov     word [bootsect_dst_base],ax
220         
221         ; have we loaded all of the sectors?
222
223         mov     bx, word [max_sector]
224         cmp     word [sec_count], bx
225         jl      .again2
226
227         ; Now we've loaded the setup code and the kernel image.
228         ; Jump to setup code.
229         jmp     SETUPSEG:0
230
231 ; Read a sector from the floppy drive.
232 ; This code (and the rest of this boot sector) will have to
233 ; be re-written at some point so it reads more than one
234 ; sector at a time.
235 ;
236 ; Parameters:
237 ;     - "logical" sector number   [bp+8]
238 ;     - destination segment       [bp+6]
239 ;     - destination offset        [bp+4]
240 ReadSector:
241         push    bp                      ; set up stack frame
242         mov     bp, sp                  ; "
243         pusha                           ; save all registers
244
245 %if 0
246 ; debug params
247         mov     dx, [bp+8]
248         call    PrintHex
249         call    PrintNL
250         mov     dx, [bp+6]
251         call    PrintHex
252         call    PrintNL
253         mov     dx, [bp+4]
254         call    PrintHex
255         call    PrintNL
256 %endif
257
258         ; Sector = log_sec % SECTORS_PER_TRACK
259         ; Head = (log_sec / SECTORS_PER_TRACK) % HEADS
260         mov     ax, [bp+8]              ; get logical sector number from stack
261         xor     dx, dx                  ; dx is high part of dividend (== 0)
262         mov     bx, SECTORS_PER_TRACK   ; divisor
263         div     bx                      ; do the division
264         mov     [sec], dx               ; sector is the remainder
265         and     ax, 1                   ; same as mod by HEADS==2 (slight hack)
266         mov     [head], ax
267
268         ; Track = log_sec / (SECTORS_PER_TRACK*HEADS)
269         mov     ax, [bp+8]              ; get logical sector number again
270         xor     dx, dx                  ; dx is high part of dividend
271         mov     bx, SECTORS_PER_TRACK*2 ; divisor
272         div     bx                      ; do the division
273         mov     [track], ax             ; track is quotient
274
275 %if 0
276 ; debugging code
277         mov     dx, [sec]
278         call    PrintHex
279         call    PrintNL
280         mov     dx, [head]
281         call    PrintHex
282         call    PrintNL
283         mov     dx, [track]
284         call    PrintHex
285         call    PrintNL
286 %endif
287
288         ; Now, try to actually read the sector from the floppy,
289         ; retrying up to 3 times.
290
291         mov     [num_retries], byte 0
292
293 .again:
294         mov     ax, [bp+6]              ; dest segment...
295         mov     es, ax                  ;   goes in es
296         mov     ax, (0x02 << 8) | 1     ; function = 02h in ah,
297                                         ;   # secs = 1 in al
298         mov     bx, [track]             ; track number...
299         mov     ch, bl                  ;   goes in ch
300         mov     bx, [sec]               ; sector number...
301         mov     cl, bl                  ;   goes in cl...
302         inc     cl                      ;   but it must be 1-based, not 0-based
303         mov     bx, [head]              ; head number...
304         mov     dh, bl                  ;   goes in dh
305         xor     dl, dl                  ; hard code drive=0
306         mov     bx, [bp+4]              ; offset goes in bx
307                                         ;   (es:bx points to buffer)
308
309
310         ; Call the BIOS Read Diskette Sectors service
311         int     0x13
312
313         ; If the carry flag is NOT set, then there was no error
314         ; and we're done.
315         jnc     .done
316
317         ; Error - code stored in ah
318         mov     dx, ax
319         call PrintHex
320         inc     byte [num_retries]
321         cmp     byte [num_retries], 3
322         jne     .again
323
324         ; If we got here, we failed thrice, so we give up
325         mov     dx, 0xdead
326         call    PrintHex
327 .here:  jmp     .here
328
329 .done:
330         popa                            ; restore all regisiters
331         pop     bp                      ; leave stack frame
332         ret
333
334 ; Include utility routines:
335 ;%include "util.asm"
336 ; REPLACED WITH FOLLOWING WHICH MUST BE COMPILED 16 FOR USE IN THIS CODE
337 PrintHex:
338         pusha
339         mov   cx, 4             ; 4 hex digits
340 .PrintDigit:
341         rol   dx, 4             ; rotate so that lowest 4 bits are used
342         mov   ax, 0E0Fh         ; ah = request, al = mask for nybble
343         and   al, dl
344         add   al, 90h           ; convert al to ascii hex (four instructions)
345         daa                     ; I've spent 1 hour to understand how it works..
346         adc   al, 40h
347         daa
348         int   10h
349         loop  .PrintDigit
350         popa
351         ret
352
353 ; Print a newline.
354 PrintNL:                        ; print CR and NL
355         push    ax
356         mov     ax, 0E0Dh       ; CR
357         int     10h
358         mov     al, 0Ah         ; LF
359         int     10h
360         pop     ax
361         ret
362
363
364
365 ; ----------------------------------------------------------------------
366 ; Variables
367 ; ----------------------------------------------------------------------
368
369 ; These are used by ReadSector
370 head: dw 0
371 track: dw 0
372 sec: dw 0
373 num_retries: db 0
374
375 ; Used for loops reading sectors from floppy
376 sec_count: dw 0
377 max_sector: dw 0
378
379
380
381
382 bootsect_gdt:
383         dw      0,0,0,0
384         dw      0,0,0,0
385 bootsect_src:
386         dw      0x200-1                
387 bootsect_src_base:
388         db      0,02,9          ;       ! base = 0x092000 
389         db      0x93            ;       ! typbyte
390         dw      0               ;       ! limit16,base24 =0
391 bootsect_dst:
392         dw      0x200-1
393 bootsect_dst_base:
394         db      0,0,0x10        ;       ! base = 0x100000
395         db      0x93            ;       ! typbyte
396         dw      0               ;       ! limit16,base24 =0
397         dw      0,0,0,0         ;       ! BIOS CS
398         dw      0,0,0,0         ;       ! BIOS DS
399
400
401 ; Padding to make the PFAT Boot Record sit just before the BIOS signature.
402 ;Pad_From_Symbol PFAT_BOOT_RECORD_OFFSET, BeginText
403
404 ; PFAT boot record
405 ; Describes how to load the setup program and kernel.
406 ; The default values are appropriate for creating a boot
407 ; floppy by concatenating the boot sector, setup program,
408 ; and kernel image.  The buildFat program will change
409 ; these values if the boot floppy is formatted as a PFAT
410 ; filesystem.
411         dw      0
412         dw      0
413
414         dw      0
415         dw      0
416
417         dw      0
418         dw      0
419
420         dw      0
421         dw      0
422
423         dw      0
424         dw      0
425
426 ;; part of pfat boot record
427 setupStart:             
428         dw      1                       ; by default, setup is at first sector  
429
430 ;; part of pfat boot record
431 setupSize:
432         dw      NUM_SETUP_SECTORS       ; number of sectors in setup
433
434 ;; part of pfat boot record
435 kernelStart:
436         dw      1+NUM_SETUP_SECTORS     ; default start sector for kernel
437
438 ;; part of pfat boot record
439 kernelSize:
440         dw      NUM_KERN_SECTORS
441
442         ;; part of pfat boot record
443 vmStart:
444         dw      1+NUM_SETUP_SECTORS+NUM_KERN_SECTORS
445         ;; part of pfat boot record
446
447 vmSize:
448         dw      NUM_VM_KERNEL_SECTORS
449
450
451         ; Finish by writing the BIOS signature to mark this as
452 ; a valid boot sector.
453 Pad_From_Symbol BIOS_SIGNATURE_OFFSET, BeginText
454 Signature   dw 0xAA55   ; BIOS controls this to ensure this is a boot sector