compiler.h is now always included on the command line.
[people/balajirrao/gpxe.git] / src / arch / i386 / prefix / dskprefix.S
1 /* NOTE: this boot sector contains instructions that need at least an 80186.
2  * Yes, as86 has a bug somewhere in the valid instruction set checks.
3  *
4  * SYS_SIZE is the number of clicks (16 bytes) to be loaded.
5  */
6 .equ    SYSSIZE, 8192   # 8192 * 16 bytes = 128kB maximum size of .ROM file
7
8 /*      floppyload.S Copyright (C) 1991, 1992 Linus Torvalds
9  *      modified by Drew Eckhardt
10  *      modified by Bruce Evans (bde)
11  *
12  * floppyprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines.
13  *
14  * It then loads the system at SYSSEG<<4, using BIOS interrupts.
15  *
16  * The loader has been made as simple as possible, and continuous read errors
17  * will result in a unbreakable loop. Reboot by hand. It loads pretty fast by
18  * getting whole tracks at a time whenever possible.
19  */
20
21 .equ    BOOTSEG, 0x07C0                 /* original address of boot-sector */
22
23 .equ    SYSSEG, 0x1000                  /* system loaded at SYSSEG<<4 */
24
25         .org    0
26         .arch i386
27         .text
28         .section ".prefix", "ax", @progbits
29         .code16
30
31         jmp     $BOOTSEG, $go           /* reload cs:ip to match relocation addr */
32 go: 
33         movw    $0x2000-12, %di         /* 0x2000 is arbitrary value >= length */
34                                         /* of bootsect + room for stack + 12 for */
35                                         /* saved disk parm block */
36
37         movw    $BOOTSEG, %ax
38         movw    %ax,%ds
39         movw    %ax,%es
40         movw    %ax,%ss                 /* put stack at BOOTSEG:0x4000-12. */
41         movw    %di,%sp
42
43 /* Many BIOS's default disk parameter tables will not recognize multi-sector
44  * reads beyond the maximum sector number specified in the default diskette
45  * parameter tables - this may mean 7 sectors in some cases.
46  *
47  * Since single sector reads are slow and out of the question, we must take care
48  * of this by creating new parameter tables (for the first disk) in RAM.  We
49  * will set the maximum sector count to 36 - the most we will encounter on an
50  * ED 2.88.  High doesn't hurt. Low does.
51  *
52  * Segments are as follows: ds=es=ss=cs - BOOTSEG
53  */
54
55         xorw    %cx,%cx
56         movw    %cx,%es                 /* access segment 0 */
57         movw    $0x78, %bx              /* 0:bx is parameter table address */
58         pushw   %ds                     /* save ds */
59 /* 0:bx is parameter table address */
60         ldsw    %es:(%bx),%si           /* loads ds and si */
61
62         movw    %ax,%es                 /* ax is BOOTSECT (loaded above) */
63         movb    $6, %cl                 /* copy 12 bytes */
64         cld
65         pushw   %di                     /* keep a copy for later */
66         rep
67         movsw                           /* ds:si is source, es:di is dest */
68         popw    %di
69
70         movb    $36,%es:4(%di)
71
72         movw    %cx,%ds                 /* access segment 0 */
73         xchgw   %di,(%bx)
74         movw    %es,%si
75         xchgw   %si,2(%bx)
76         popw    %ds                     /* restore ds */
77         movw    %di, dpoff              /* save old parameters */
78         movw    %si, dpseg              /* to restore just before finishing */
79         pushw   %ds
80         popw    %es                     /* reload es */
81
82 /* Note that es is already set up.  Also cx is 0 from rep movsw above. */
83
84         xorb    %ah,%ah                 /* reset FDC */
85         xorb    %dl,%dl
86         int     $0x13
87
88 /* Get disk drive parameters, specifically number of sectors/track.
89  *
90  * It seems that there is no BIOS call to get the number of sectors.  Guess
91  * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
92  * 15 if sector 15 can be read. Otherwise guess 9.
93  */
94
95         movw    $disksizes, %si         /* table of sizes to try */
96
97 probe_loop: 
98         lodsb
99         cbtw                            /* extend to word */
100         movw    %ax, sectors
101         cmpw    $disksizes+4, %si
102         jae     got_sectors             /* if all else fails, try 9 */
103         xchgw   %cx,%ax                 /* cx = track and sector */
104         xorw    %dx,%dx                 /* drive 0, head 0 */
105         movw    $0x0200, %bx            /* address after boot sector */
106                                         /*   (512 bytes from origin, es = cs) */
107         movw    $0x0201, %ax            /* service 2, 1 sector */
108         int     $0x13
109         jc      probe_loop              /* try next value */
110
111 got_sectors: 
112         movw    $msg1end-msg1, %cx
113         movw    $msg1, %si
114         call    print_str
115
116 /* ok, we've written the Loading... message, now we want to load the system */
117
118         movw    $SYSSEG, %ax
119         movw    %ax,%es                 /* segment of SYSSEG<<4 */
120         pushw   %es
121         call    read_it
122
123 /* This turns off the floppy drive motor, so that we enter the kernel in a
124  * known state, and don't have to worry about it later.
125  */
126         movw    $0x3f2, %dx
127         xorb    %al,%al
128         outb    %al,%dx
129
130         call    print_nl
131         pop     %es                     /* = SYSSEG */
132
133 /* Restore original disk parameters */
134         movw    $0x78, %bx
135         movw    dpoff, %di
136         movw    dpseg, %si
137         xorw    %ax,%ax
138         movw    %ax,%ds
139         movw    %di,(%bx)
140         movw    %si,2(%bx)
141
142         /* Everything now loaded.  %es = SYSSEG, so %es:0000 points to
143          * start of loaded image.
144          */
145
146 start_runtime:
147
148 #ifdef  COMPRESS
149         /* Decompress runtime image.  %es:0000 points to decompressed
150          * image on exit.
151          */
152         lcall   $SYSSEG, $decompress16
153 #endif
154         
155         /* Set up internal environment.  Address of entry-point
156          * function is returned in %es:di.
157          */
158         pushw   %es             /* setup16 says %ds:0000 must point to image */
159         popw    %ds
160         movw    $setup16, %di
161         pushw   %cs
162         call    ljmp_to_es_di
163
164         /* Call to arch_main.  Register INT19 as an exit path.  This
165          * call will never return.
166          */
167         movl    $exit_via_int19, %eax
168         pushl   $arch_main
169         pushl   %eax            /* Dummy return address */
170
171         /* Do the equivalent of ljmp *%es:di */
172 ljmp_to_es_di:  
173         pushw   %es
174         pushw   %di
175         lret
176
177 /* This routine loads the system at address SYSSEG<<4, making sure no 64kB
178  * boundaries are crossed. We try to load it as fast as possible, loading whole
179  * tracks whenever we can.
180  *
181  * in:  es - starting address segment (normally SYSSEG)
182  */
183 read_it: 
184         movw    $1,sread                /* don't reload the prefix */
185         movw    %es,%ax
186         testw   $0x0fff, %ax
187 die:    jne     die                     /* es must be at 64kB boundary */
188         xorw    %bx,%bx                 /* bx is starting address within segment */
189 rp_read: 
190         movw    %es,%ax
191         movw    %bx,%dx
192         movb    $4, %cl
193         shrw    %cl,%dx                 /* bx is always divisible by 16 */
194         addw    %dx,%ax
195         cmpw    $SYSSEG+SYSSIZE, %ax    /* have we loaded all yet? */
196         jb      ok1_read
197         ret
198 ok1_read: 
199         movw    sectors, %ax
200         subw    sread, %ax
201         movw    %ax,%cx
202         shlw    $9, %cx
203         addw    %bx,%cx
204         jnc     ok2_read
205         je      ok2_read
206         xorw    %ax,%ax
207         subw    %bx,%ax
208         shrw    $9, %ax
209 ok2_read: 
210         call    read_track
211         movw    %ax,%cx
212         addw    sread, %ax
213         cmpw    sectors, %ax
214         jne     ok3_read
215         movw    $1, %ax
216         subw    head, %ax
217         jne     ok4_read
218         incw    track
219 ok4_read: 
220         movw    %ax, head
221         xorw    %ax,%ax
222 ok3_read: 
223         movw    %ax, sread
224         shlw    $9, %cx
225         addw    %cx,%bx
226         jnc     rp_read
227         movw    %es,%ax
228         addb    $0x10, %ah
229         movw    %ax,%es
230         xorw    %bx,%bx
231         jmp     rp_read
232
233 read_track: 
234         pusha
235         pushw   %ax
236         pushw   %bx
237         pushw   %bp                     /* just in case the BIOS is buggy */
238         movw    $0x0e2e, %ax            /* 0x2e = . */
239         movw    $0x0007, %bx
240         int     $0x10
241         popw    %bp
242         popw    %bx
243         popw    %ax
244
245         movw    track, %dx
246         movw    sread, %cx
247         incw    %cx
248         movb    %dl,%ch
249         movw    head, %dx
250         movb    %dl,%dh
251         andw    $0x0100, %dx
252         movb    $2, %ah
253
254         pushw   %dx                     /* save for error dump */
255         pushw   %cx
256         pushw   %bx
257         pushw   %ax
258
259         int     $0x13
260         jc      bad_rt
261         addw    $8, %sp
262         popa
263         ret
264
265 bad_rt: pushw   %ax                     /* save error code */
266         call    print_all               /* ah = error, al = read */
267
268         xorb    %ah,%ah
269         xorb    %dl,%dl
270         int     $0x13
271
272         addw    $10, %sp
273         popa
274         jmp     read_track
275
276 /* print_all is for debugging purposes. It will print out all of the registers.
277  * The assumption is that this is called from a routine, with a stack frame like
278  *      dx
279  *      cx
280  *      bx
281  *      ax
282  *      error
283  *      ret <- sp
284  */
285
286 print_all: 
287         call    print_nl                /* nl for readability */
288         movw    $5, %cx                 /* error code + 4 registers */
289         movw    %sp,%bp
290
291 print_loop: 
292         pushw   %cx                     /* save count left */
293
294         cmpb    $5, %cl
295         jae     no_reg                  /* see if register name is needed */
296
297         movw    $0x0007, %bx            /* page 0, attribute 7 (normal) */
298         movw    $0xe05+0x41-1, %ax
299         subb    %cl,%al
300         int     $0x10
301
302         movb    $0x58, %al              /* 'X' */
303         int     $0x10
304
305         movb    $0x3A, %al              /* ':' */
306         int     $0x10
307
308 no_reg: 
309         addw    $2, %bp                 /* next register */
310         call    print_hex               /* print it */
311         movb    $0x20, %al              /* print a space */
312         int     $0x10
313         popw    %cx
314         loop    print_loop
315         call    print_nl                /* nl for readability */
316         ret
317
318 print_str: 
319         movw    $0x0007, %bx            /* page 0, attribute 7 (normal) */
320         movb    $0x0e, %ah              /* write char, tty mode */
321 prloop: 
322         lodsb
323         int     $0x10
324         loop    prloop
325         ret
326
327 print_nl: 
328         movw    $0x0007, %bx            /* page 0, attribute 7 (normal) */
329         movw    $0xe0d, %ax             /* CR */
330         int     $0x10
331         movb    $0xa, %al               /* LF */
332         int     $0x10
333         ret
334
335 /* print_hex prints the word pointed to by ss:bp in hexadecimal. */
336
337 print_hex: 
338         movw    (%bp),%dx               /* load word into dx */
339         movb    $4, %cl
340         movb    $0x0e, %ah              /* write char, tty mode */
341         movw    $0x0007, %bx            /* page 0, attribute 7 (normal) */
342         call    print_digit
343         call    print_digit
344         call    print_digit
345 /* fall through */
346 print_digit: 
347         rol     %cl,%dx                 /* rotate so that lowest 4 bits are used */
348         movb    $0x0f, %al              /* mask for nybble */
349         andb    %dl,%al
350         addb    $0x90, %al              /* convert al to ascii hex (four instructions) */
351         daa
352         adcb    $0x40, %al
353         daa
354         int     $0x10
355         ret
356
357 sread:  .word 0                         /* sectors read of current track */
358 head:   .word 0                         /* current head */
359 track:  .word 0                         /* current track */
360
361 sectors: 
362         .word 0
363
364 dpseg:  .word 0
365 dpoff:  .word 0
366
367 disksizes: 
368         .byte 36,18,15,9
369
370 msg1: 
371         .ascii "Loading ROM image"
372 msg1end: 
373
374         .org 510, 0
375         .word 0xAA55
376