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.


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