[prefix] Add PCI bus:dev.fn to ROM product string
[people/dverkamp/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 PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
10 #define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
11 #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
12 #define PNP_GET_BBS_VERSION 0x60
13
14         .text
15         .code16
16         .arch i386
17         .section ".prefix", "ax", @progbits
18         
19         .org    0x00
20 romheader:
21         .word   0xAA55                  /* BIOS extension signature */
22 romheader_size: .byte _load_size_sect   /* Size in 512-byte blocks */
23         jmp     init                    /* Initialisation vector */
24 checksum:
25         .byte   0
26         .org    0x16
27         .word   undiheader
28         .org    0x18
29         .word   pciheader
30         .org    0x1a
31         .word   pnpheader
32         .size romheader, . - romheader
33         
34         .section ".zinfo.fixup", "a"    /* Compressor fixup information */
35         .ascii  "SUBB"
36         .long   romheader_size
37         .long   512
38         .long   0
39         .previous
40
41 pciheader:
42         .ascii  "PCIR"                  /* Signature */
43         .word   pci_vendor_id           /* Vendor ID */ 
44         .word   pci_device_id           /* Device ID */
45         .word   0x0000                  /* pointer to vital product data */
46         .word   pciheader_len           /* PCI data structure length */
47         .byte   0x00                    /* PCI data structure revision */
48         .byte   0x02                    /* Device Base Type code */
49         .byte   0x00                    /* Device Sub-Type code */
50         .byte   0x00                    /* Device Interface Type code */
51 pciheader_size: .word _load_size_sect   /* Image length same as offset 02h */
52         .word   0x0001                  /* revision level of code/data */
53         .byte   0x00                    /* code type */
54         .byte   0x80                    /* Flags (last PCI data structure) */
55         .word   0x0000                  /* reserved */
56         .equ pciheader_len, . - pciheader
57         .size pciheader, . - pciheader
58         
59         .section ".zinfo.fixup", "a"    /* Compressor fixup information */
60         .ascii  "SUBW"
61         .long   pciheader_size
62         .long   512
63         .long   0
64         .previous
65
66 pnpheader:
67         .ascii  "$PnP"                  /* Signature */
68         .byte   0x01                    /* Structure revision */
69         .byte   ( pnpheader_len / 16 )  /* Length (in 16 byte increments) */
70         .word   0x0000                  /* Offset of next header */
71         .byte   0x00                    /* Reserved */
72         .byte   0x00                    /* Checksum */
73         .long   0x00000000              /* Device identifier */
74         .word   mfgstr                  /* Manufacturer string */
75         .word   prodstr                 /* Product name */
76         .byte   0x02                    /* Device base type code */
77         .byte   0x00                    /* Device sub-type code */
78         .byte   0x00                    /* Device interface type code */
79         .byte   0x54                    /* Device indicator */
80         .word   0x0000                  /* Boot connection vector */
81         .word   0x0000                  /* Disconnect vector */
82         .word   bev_entry               /* Boot execution vector */
83         .word   0x0000                  /* Reserved */
84         .word   0x0000                  /* Static resource information vector*/
85         .equ pnpheader_len, . - pnpheader
86         .size pnpheader, . - pnpheader
87
88 /* Manufacturer string */
89 mfgstr:
90         .asciz  "http://etherboot.org"
91         .size mfgstr, . - mfgstr
92
93 /* Product string
94  *
95  * Defaults to "gPXE".  If the ROM image is writable at initialisation
96  * time, it will be filled in to include the PCI bus:dev.fn number of
97  * the card as well.
98  */
99 prodstr:
100         .ascii  "gPXE"
101 prodstr_separator:
102         .byte   0
103         .ascii  "(PCI "
104 prodstr_pci_id:
105         .asciz  "xx:xx.x)"              /* Filled in by init code */
106         .size prodstr, . - prodstr
107         
108 undiheader:
109         .ascii  "UNDI"                  /* Signature */
110         .byte   undiheader_len          /* Length of structure */
111         .byte   0                       /* Checksum */
112         .byte   0                       /* Structure revision */
113         .byte   0,1,2                   /* PXE version: 2.1.0 */
114         .word   undiloader              /* Offset to loader routine */
115         .word   _data16_size            /* Stack segment size */
116         .word   _data16_size            /* Data segment size */
117         .word   _text16_size            /* Code segment size */
118         .equ undiheader_len, . - undiheader
119         .size undiheader, . - undiheader
120
121 /* Initialisation (called once during POST)
122  *
123  * Determine whether or not this is a PnP system via a signature
124  * check.  If it is PnP, return to the PnP BIOS indicating that we are
125  * a boot-capable device; the BIOS will call our boot execution vector
126  * if it wants to boot us.  If it is not PnP, hook INT 19.
127  */
128 init:
129         /* Preserve registers, clear direction flag, set %ds=%cs */
130         pushaw
131         pushw   %ds
132         pushw   %es
133         cld
134         pushw   %cs
135         popw    %ds
136         movw    %di, %bx
137         xorw    %di, %di
138         /* Print message as early as possible */
139         movw    $init_message, %si
140         call    print_message
141         call    print_pci_busdevfn
142         /* Fill in product name string, if possible */
143         movw    $prodstr_pci_id, %di
144         call    print_pci_busdevfn
145         movb    $' ', prodstr_separator
146         xorw    %di, %di
147         /* Check for PnP BIOS */
148         testw   $0x0f, %bx      /* PnP signature must be aligned - bochs    */
149         jnz     hook_int19      /* uses unalignment to indicate 'fake' PnP. */
150         cmpl    $PNP_SIGNATURE, %es:0(%bx)
151         jne     hook_int19
152         /* Is PnP: print PnP message */
153         movw    $init_message_pnp, %si
154         call    print_message
155         /* Check for BBS */
156         pushw   %es:0x1b(%bx)   /* Real-mode data segment */
157         pushw   %ds             /* &(bbs_version) */
158         pushw   $bbs_version
159         pushw   $PNP_GET_BBS_VERSION
160         lcall   *%es:0xd(%bx)
161         addw    $8, %sp
162         testw   %ax, %ax
163         jne     hook_int19
164         movw    $init_message_bbs, %si
165         call    print_message
166         jmp     hook_bbs
167         /* Not BBS-compliant - must hook INT 19 */
168 hook_int19:
169         movw    $init_message_int19, %si
170         call    print_message
171         xorw    %ax, %ax
172         movw    %ax, %es
173         pushw   %cs
174         pushw   $int19_entry
175         popl    %es:( 0x19 * 4 )
176 hook_bbs:
177         /* Check for PMM */
178         movw    $( 0xe00 - 1 ), %bx
179 pmm_scan:
180         incw    %bx
181         jz      no_pmm
182         movw    %bx, %es
183         cmpl    $PMM_SIGNATURE, %es:0
184         jne     pmm_scan
185         xorw    %dx, %dx
186         xorw    %si, %si
187         movzbw  %es:5, %cx
188 1:      es lodsb
189         addb    %al, %dl
190         loop    1b
191         jnz     pmm_scan
192         /* PMM found: print PMM message */
193         movw    $init_message_pmm, %si
194         call    print_message
195         /* Try to allocate 2MB block via PMM */
196         pushw   $0x0006         /* Aligned, extended memory */
197         pushl   $0xffffffff     /* No handle */
198         pushl   $( 0x00200000 / 16 ) /* 2MB in paragraphs */
199         pushw   $0x0000         /* pmmAllocate */
200         lcall   *%es:7
201         addw    $12, %sp
202         testw   %dx, %dx        /* %ax==0 even on success, since align=2MB */
203         jnz     gotpmm
204         movw    $init_message_pmm_failed, %si
205         call    print_message
206         jmp     no_pmm
207 gotpmm: /* PMM allocation succeeded: copy ROM to PMM block */
208         pushal                  /* PMM presence implies 1kB stack */
209         movw    %ax, %es        /* %ax=0 already - see above */
210         pushw   %dx
211         pushw   %ax
212         popl    %edi
213         movl    %edi, image_source
214         xorl    %esi, %esi
215         movzbl  romheader_size, %ecx
216         shll    $9, %ecx
217         addr32 rep movsb        /* PMM presence implies flat real mode */
218         movl    %edi, decompress_to
219         /* Shrink ROM and update checksum */
220         xorw    %bx, %bx
221         xorw    %si, %si
222         movw    $_prefix_size_sect, %cx
223         movb    %cl, romheader_size
224         shlw    $9, %cx
225 1:      lodsb
226         addb    %al, %bl
227         loop    1b
228         subb    %bl, checksum
229         popal
230 no_pmm:
231         /* Print CRLF to terminate messages */
232         movw    $'\n', %ax
233         call    print_character
234         /* Restore registers */
235         popw    %es
236         popw    %ds
237         popaw
238         /* Indicate boot capability to PnP BIOS, if present */
239         movw    $0x20, %ax
240         lret
241         .size init, . - init
242
243 init_message:
244         .asciz  "gPXE (http://etherboot.org) - PCI "
245         .size   init_message, . - init_message
246 init_message_pnp:
247         .asciz  " PnP"
248         .size init_message_pnp, . - init_message_pnp
249 init_message_bbs:
250         .asciz  " BBS"
251         .size init_message_bbs, . - init_message_bbs
252 init_message_pmm:
253         .asciz  " PMM"
254         .size init_message_pmm, . - init_message_pmm
255 init_message_pmm_failed:
256         .asciz  "(failed)"
257         .size init_message_pmm_failed, . - init_message_pmm_failed
258 init_message_int19:
259         .asciz  " INT19"
260         .size init_message_int19, . - init_message_int19
261
262 /* ROM image location
263  *
264  * May be either within option ROM space, or within PMM-allocated block.
265  */
266 image_source:
267         .long   0
268         .size   image_source, . - image_source
269
270 /* Temporary decompression area
271  *
272  * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
273  */
274 decompress_to:
275         .long   HIGHMEM_LOADPOINT
276         .size   decompress_to, . - decompress_to
277
278 /* BBS version
279  *
280  * Filled in by BBS BIOS.  We ignore the value.
281  */
282 bbs_version:
283         .word   0
284
285 /* Boot Execution Vector entry point
286  *
287  * Called by the PnP BIOS when it wants to boot us.
288  */
289 bev_entry:
290         pushw   %cs
291         call    exec
292         lret
293         .size   bev_entry, . - bev_entry
294
295 /* INT19 entry point
296  *
297  * Called via the hooked INT 19 if we detected a non-PnP BIOS.
298  */
299 int19_entry:
300         pushw   %cs
301         call    exec
302         /* No real way to return from INT19 */
303         int     $0x18
304         .size   int19_entry, . - int19_entry
305
306 /* Execute as a boot device
307  *
308  */
309 exec:   /* Set %ds = %cs */
310         pushw   %cs
311         popw    %ds
312
313         /* Print message as soon as possible */
314         movw    $exec_message, %si
315         xorw    %di, %di
316         call    print_message
317
318         /* Store magic word on BIOS stack and remember BIOS %ss:sp */
319         pushl   $STACK_MAGIC
320         movw    %ss, %dx
321         movw    %sp, %bp
322
323         /* Obtain a reasonably-sized temporary stack */
324         xorw    %ax, %ax
325         movw    %ax, %ss
326         movw    $0x7c00, %sp
327
328         /* Install gPXE */
329         movl    image_source, %esi
330         movl    decompress_to, %edi
331         call    alloc_basemem
332         call    install_prealloc
333
334         /* Set up real-mode stack */
335         movw    %bx, %ss
336         movw    $_estack16, %sp
337
338         /* Jump to .text16 segment */
339         pushw   %ax
340         pushw   $1f
341         lret
342         .section ".text16", "awx", @progbits
343 1:      /* Call main() */
344         pushl   $main
345         pushw   %cs
346         call    prot_call
347         /* No need to clean up stack; we are about to reload %ss:sp */
348         
349         /* Restore BIOS stack */
350         movw    %dx, %ss
351         movw    %bp, %sp
352
353         /* Check magic word on BIOS stack */
354         popl    %eax
355         cmpl    $STACK_MAGIC, %eax
356         jne     1f
357         /* BIOS stack OK: return to caller */
358         lret
359 1:      /* BIOS stack corrupt: use INT 18 */
360         int     $0x18
361         .previous
362
363 exec_message:
364         .asciz  "gPXE starting boot\n"
365         .size exec_message, . - exec_message
366
367 /* UNDI loader
368  *
369  * Called by an external program to load our PXE stack.
370  */
371 undiloader:
372         /* Save registers */
373         pushl   %esi
374         pushl   %edi
375         pushw   %es
376         pushw   %bx
377         /* UNDI loader parameter structure address into %es:%di */
378         movw    %sp, %bx
379         movw    %ss:12(%bx), %di
380         movw    %ss:14(%bx), %es
381         /* Install to specified real-mode addresses */
382         pushw   %di
383         movw    %es:12(%di), %bx
384         movw    %es:14(%di), %ax
385         movl    %cs:image_source, %esi
386         movl    %cs:decompress_to, %edi
387         call    install_prealloc
388         popw    %di
389         /* Call UNDI loader C code */
390         pushl   $pxe_loader_call
391         pushw   %cs
392         pushw   $1f
393         pushw   %ax
394         pushw   $prot_call
395         lret
396 1:      popw    %bx     /* discard */
397         popw    %bx     /* discard */
398         /* Restore registers and return */
399         popw    %bx
400         popw    %es
401         popl    %edi
402         popl    %esi
403         lret
404         .size undiloader, . - undiloader