Fix up building with gcc 4.0.1 / gas 2.16.91
[gpxe.git] / src / arch / i386 / prefix / romprefix.S
1 /* At entry, the processor is in 16 bit real mode and the code is being
2  * executed from an address it was not linked to. Code must be pic and
3  * 32 bit sensitive until things are fixed up.
4  *
5  * Also be very careful as the stack is at the rear end of the interrupt
6  * table so using a noticeable amount of stack space is a no-no.
7  */
8
9 /* Define DELAYED_INT when NO_DELAYED_INT is not defined.
10  * This allows positive tests instead of tests that contain
11  * double negatives, and become confusing.
12  */
13 #ifndef NO_DELAYED_INT
14 #define DELAYED_INT
15 #endif
16
17 /* We need some unique magic ID, if we defer startup thru the INT18H or INT19H
18  * handler. This way, we can check if we have already been installed.
19  */
20 #ifndef MAGIC
21 #define MAGIC           0xE44C
22 #endif
23
24 /* Hook into INT18H or INT19H handler */
25 #ifdef  BOOT_INT18H
26 #define BOOT_INT        0x18
27 #else
28 #define BOOT_INT        0x19
29 #endif
30
31 #define BOOT_INT_VEC    BOOT_INT*4
32 #define SCRATCHVEC      0x300
33
34 /* Prefix exit codes.  We store these on the stack so that we will
35  * know how to return control to the BIOS when Etherboot exits.
36  */
37 #define EXIT_VIA_LRET           0x0
38 #define EXIT_VIA_INT_18         0x1
39 #define EXIT_VIA_BOOT_INT       0x2
40
41         .text
42         .code16
43         .arch i386
44         .org 0
45         .section ".prefix", "ax", @progbits
46 _prefix: 
47         .word 0xAA55                    /* BIOS extension signature */
48 size:   .byte 0                         /* number of 512 byte blocks */
49                                         /* = number of 256 word blocks */
50                                         /* filled in by makerom program */
51         jmp     over                    /* skip over checksum */
52         .byte 0                         /* checksum */
53         jmp     legacyentry             /* alternate entry point +6 */
54                                         /* used by mknbi-rom */
55
56 #ifdef  PCI_PNP_HEADER
57 mfgstr:
58         .asciz  "Etherboot"
59         
60 #ifdef  PXE_EXPORT
61         .org    0x16
62         .word   UNDIROMID - _prefix
63 #endif  /* PXE_EXPORT */
64         
65         .org    0x18
66         .word   PCI - _prefix
67         .word   PnP - _prefix
68
69 PCI: 
70         .ascii  "PCIR"
71         .word 0x0000                    /* vendor ID, filled in by makerom */
72         .word 0x0000                    /* device ID, filled in by makerom */
73         .word 0x0000                    /* pointer to vital product data */
74         .word 0x0018                    /* PCI data structure length */
75         .byte 0x00                      /* PCI data structure revision */
76         .byte 0x02                      /* Device Base Type code */
77         .byte 0x00                      /* Device Sub-Type code */
78         .byte 0x00                      /* Device Interface Type code */
79         .word 0x0000                    /* Image length same as offset 02h */
80         .word 0x0001                    /* revision level of code/data */
81         .byte 0x00                      /* code type */
82         .byte 0x80                      /* indicator (last PCI data structure) */
83         .word 0x0000                    /* reserved */
84
85 PnP:
86         .ascii  "$PnP"
87         .byte 0x01                      /* structure revision */
88         .byte 0x02                      /* length (in 16 byte increments) */
89         .word 0x0000                    /* offset of next header */
90         .byte 0x00                      /* Reserved */
91         .byte 0x00                      /* checksum filled by makerom */
92         .long 0x00000000                /* Device identifier */
93         .word mfgstr - _prefix
94         .word 0x0                       /* pointer to product name */
95                                         /* filled by makerom */
96         .byte 0x02                      /* Device Base Type code */
97         .byte 0x00                      /* Device Sub-Type code */
98         .byte 0x00                      /* Device Interface Type code */
99         .byte 0x14                      /* device indicator */
100         .word 0x0000                    /* boot connection vector */
101         .word 0x0000                    /* disconnect vector */
102         .word pnpentry - _prefix
103         .word 0x0000                    /* reserved */
104         .word 0x0000                    /* static resource information vector */
105 #ifdef  PXE_EXPORT
106 UNDIROMID:
107         .ascii  "UNDI"
108         .byte   UNDIROMID_end - UNDIROMID /* length of structure */
109         .byte   0                       /* Checksum */
110         .byte   0                       /* Structure revision */
111         .byte   0,1,2                   /* PXE version 2.1.0 */
112         .word   UNDILoader - _prefix    /* Offset to loader routine */
113         .word   _real_mode_stack_size   /* Stack segment size */
114         .word   _real_mode_stack_size   /* Data segment size */
115         .word   _pxe_stack_size         /* Code segment size */
116         .ascii  "PCIR"
117
118         /* The code segment contains our pxe_stack_t plus the PXE and
119          * RM callback interfaces.  We don't actually use a data
120          * segment, but we put a nonzero value here to avoid confusing
121          * things.  16k of stack space should be enough.
122          *
123          * When we claim our own memory, we fill out the data segment
124          * with the address and size of the real-mode stack, so that
125          * NBPs will free that area of memory for us.  When the UNDI
126          * loader is used to initialise us, we will never need a
127          * real-mode stack because we will only ever be called via the
128          * PXE API, hence our stack is already in base memory.
129          */
130         .equ    UNDICodeSize, _pxe_stack_size
131         .equ    UNDIDataSize, _real_mode_stack_size
132         .equ    UNDIStackSize, _real_mode_stack_size
133 UNDIROMID_end:  
134 #endif  /* PXE_EXPORT */
135         
136 #endif  /* PCI_PNP_HEADER */
137
138 /*
139  *      Explicitly specify DI is wrt ES to avoid problems with some BIOSes
140  *      Discovered by Eric Biederman
141  *      In addition, some BIOSes don't point DI to the string $PnP so
142  *      we need another #define to take care of that.
143  */
144 over:   
145 #ifdef  DEBUG_ROMPREFIX
146         call    print_bcv
147 #endif
148 /* Omit this test for ISA cards anyway */
149 #ifdef  PCI_PNP_HEADER
150 /* Accept old name too for backward compatibility */
151 #if     !defined(BBS_BUT_NOT_PNP_COMPLIANT) && !defined(PNP_BUT_NOT_BBS_COMPLIANT)
152         cmpw    $'$'+'P'*256,%es:0(%di)
153         jne     notpnp
154         cmpw    $'n'+'P'*256,%es:2(%di)
155         jne     notpnp
156 #endif  /* BBS_BUT_NOT_PNP_COMPLIANT */
157         movw    $0x20,%ax
158         lret
159 #endif  /* PCI_PNP_HEADER */
160 notpnp:
161 #ifdef  DEBUG_ROMPREFIX
162         call    print_notpnp
163 #endif
164 #ifdef  DELAYED_INT
165         pushw   %ax
166         pushw   %ds
167         xorw    %ax,%ax
168         movw    %ax,%ds                 /* access first 64kB segment */
169         movw    SCRATCHVEC+4, %ax       /* check if already installed */
170         cmpw    $MAGIC, %ax             /* check magic word */
171         jz      installed
172         movw    BOOT_INT_VEC, %ax       /* hook into INT18H or INT19H */
173         movw    %ax, SCRATCHVEC
174         movw    BOOT_INT_VEC+2, %ax
175         movw    %ax, SCRATCHVEC+2
176         movw    $start_int - _prefix, %ax
177         movw    %ax, BOOT_INT_VEC
178         movw    %cs,%ax
179         movw    %ax, BOOT_INT_VEC+2
180         movw    $MAGIC, %ax             /* set magic word */
181         movw    %ax, SCRATCHVEC+4
182 #ifdef  DEBUG_ROMPREFIX
183         call    print_installed
184 #endif
185 installed:
186         popw    %ds
187         popw    %ax
188         movw    $0x20,%ax
189         lret
190
191 start_int:                              /* clobber magic id, so that we will */
192 #ifdef  DEBUG_ROMPREFIX
193         call    print_start_int
194 #endif
195         xorw    %ax,%ax                 /* not inadvertendly end up in an */
196         movw    %ax,%ds                 /* endless loop */
197         movw    %ax, SCRATCHVEC+4
198         movw    SCRATCHVEC+2, %ax       /* restore original INT19h handler */
199         movw    %ax, BOOT_INT_VEC+2
200         movw    SCRATCHVEC, %ax
201         movw    %ax, BOOT_INT_VEC
202         pushl   %eax                    /* padding */
203         pushw   $EXIT_VIA_BOOT_INT
204         jmp     invoke
205 #endif  /* DELAYED_INT */
206
207
208
209         
210 legacyentry:
211 #ifdef  DEBUG_ROMPREFIX
212         call    print_legacyentry
213 #endif
214         pushw   $EXIT_VIA_LRET
215         jmp     invoke
216
217         
218         
219 #ifdef PCI_PNP_HEADER
220 pnpentry:
221 #ifdef  DEBUG_ROMPREFIX
222         call    print_bev
223 #endif
224         pushl   %eax                    /* padding */
225         pushw   $EXIT_VIA_INT_18
226         jmp     invoke
227 #endif /* PCI_PNP_HEADER */
228
229
230 invoke:
231         /* Store ROM segment and size on stack */
232         pushw   %ax
233         pushw   %ds
234         pushw   %cs
235         movzbw  %cs:(size-_prefix), %ax
236         shlw    $9, %ax                 /* 512-byte blocks */
237         pushw   %ax
238         /* Relocate to free base memory, switch stacks */
239         pushw   $12                     /* Preserve exit code & far ret addr */
240         call    prelocate
241         /* We are now running in RAM */
242         popw    %ax                     /* padding */
243         movw    %cs, %ax
244         movw    %ax, %ds
245         popw    %ds:(_prefix_rom+2)     /* ROM size */
246         popw    %ds:(_prefix_rom+0)     /* ROM segment */
247         popw    %ds                     /* Original %ds */
248         popw    %ax                     /* Original %ax */
249         pushw   %ax                     /* 4-byte alignment */
250         pushl   $8                      /* Preserve exit code & far ret addr */
251         pushw   $0                      /* Set null return address */
252         jmp     _start
253         
254
255         .section ".text16", "ax", @progbits
256 prefix_exit:
257         popw    %ax                     /* padding */
258         popw    %ax                     /* %ax = exit code */
259         cmpw    $EXIT_VIA_LRET, %ax
260         jne     1f
261         /* Exit via LRET */
262         lret
263 1:      addw    $4, %sp                 /* Strip padding */
264         cmpw    $EXIT_VIA_BOOT_INT, %ax
265         jne     2f
266         /* Exit via int BOOT_INT */
267         int     $BOOT_INT               /* Try original vector */
268 2:      /* Exit via int $0x18 */
269         int     $0x18                   /* As per BIOS Boot Spec, next dev */
270 prefix_exit_end:
271         .previous
272
273         
274
275 /* UNDI loader needs to be rewritten to use new mechanism */
276 #if 0
277                 
278 #ifdef  PXE_EXPORT
279
280 #define PXENV_UNDI_LOADER               0x104d
281
282         .section ".prefix"
283 UNDILoader:
284         /* Loader API is different to the usual PXE API; there is no
285          * opcode on the stack.  We arrange the stack to look like a
286          * normal PXE API call; this makes the Etherboot internals
287          * cleaner and avoids adding an extra API type just for the
288          * PXE loader.
289          */
290         pushw   %bx
291         movw    %sp, %ax                /* Store original %ss:sp */
292         pushw   %ss
293         pushw   %ax
294         pushl   %eax                    /* Space for loader structure ptr */
295         pushw   %bp
296         movw    %sp, %bp
297         movw    16(%bp), %ax            /* Copy loader structure ptr */
298         movw    %ax, 2(%bp)
299         movw    18(%bp), %ax
300         movw    %ax, 4(%bp)
301         popw    %bp
302         pushw   $PXENV_UNDI_LOADER      /* PXE 'opcode' */
303         pushl   %eax                    /* dummy return address */
304         /* Stack now looks like a normal PXE API call */
305         /* Store ROM segment and size on stack */
306         pushw   %ax
307         pushw   %cs
308         movzbw  %cs:(size-_prefix), %ax
309         shlw    $9, %ax                 /* 512-byte blocks */
310         pushw   %ax
311         /* Unpack Etherboot into temporarily claimed base memory */
312         pushw   $20                     /* Dummy ret, PXE params, orig ss:sp */
313         call    prelocate
314         popw    %ax                     /* discard */
315         popw    %cs:(_prefix_rom+2)     /* ROM size */
316         popw    %cs:(_prefix_rom+0)     /* ROM segment */
317         popw    %ax                     /* Original %ax */
318         /* Inhibit automatic deallocation of base memory */
319         movl    $0, %cs:_prefix_image_basemem
320         /* Make PXE API call to Etherboot */
321         pushl   $0x201                  /* PXE API version */
322         /* Need to USE_INTERNAL_STACK, since we will call relocate() */
323         pushl   $(EB_OPCODE_PXE|EB_USE_INTERNAL_STACK) /* PXE API call type */
324         call    _entry
325         addw    $18, %sp                /* discard */
326         popw    %bx                     /* Restore original %ss:sp */
327         popw    %ss
328         movw    %bx, %sp
329         popw    %bx
330         call    deprelocate
331         lret    $2                      /* Skip our PXE 'opcode' */
332 #endif  /* PXE_EXPORT */
333
334 #endif /* 0 */
335                         
336 #ifdef DEBUG_ROMPREFIX
337         .section ".prefix"
338
339 print_bcv:
340         pushw   %si
341         movw    $1f-_prefix, %si
342         call    print_message
343         popw    %si
344         ret
345 1:      .asciz  "ROM detected\r\n"
346
347 print_bev:
348         pushw   %si
349         movw    $1f-_prefix, %si
350         call    print_message
351         popw    %si
352         ret
353 1:      .asciz  "booting\r\n"
354
355 print_notpnp:
356         pushw   %si
357         movw    $1f-_prefix, %si
358         call    print_message
359         popw    %si
360         ret
361 1:      .asciz  ": Non-PnP BIOS detected!\r\n"
362
363 print_legacyentry:
364         pushw   %si
365         movw    $1f-_prefix, %si
366         call    print_message
367         popw    %si
368         ret
369 1:      .asciz  "ROM using legacy boot mechanism\r\n"
370
371 print_installed:
372         pushw   %si
373         movw    $1f-_prefix, %si
374         call    print_message
375         popw    %si
376         ret
377 1:      .ascii  "hooked boot via INT"
378 #ifdef  BOOT_INT18H
379         .asciz  "18\r\n"
380 #else
381         .asciz  "19\r\n"
382 #endif
383
384 print_start_int:
385         pushw   %si
386         movw    $1f-_prefix, %si
387         call    print_message
388         popw    %si
389         ret
390 1:      .asciz  "booting via hooked interrupt\r\n"
391
392 print_message:
393         pushaw
394         pushw   %ds
395         pushw   %cs
396         popw    %ds
397         pushw   %si
398         movw    $1f-_prefix, %si
399         call    print_string
400         popw    %si
401         call    print_string
402         popw    %ds
403         popaw
404         ret
405 1:      .asciz  "Etherboot "
406
407 print_string:
408 1:      lodsb
409         testb   %al,%al
410         je      2f
411         movw    $0x0007, %bx            /* page 0, attribute 7 (normal) */
412         movb    $0x0e, %ah              /* write char, tty mode */
413         int     $0x10
414         jmp     1b
415 2:      ret
416         
417 #endif