Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / prefix / mromprefix.S
1 /*
2  * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  */
20
21 FILE_LICENCE ( GPL2_OR_LATER )
22
23 #define PCIBIOS_READ_CONFIG_WORD        0xb109
24 #define PCIBIOS_READ_CONFIG_DWORD       0xb10a
25 #define PCIBIOS_WRITE_CONFIG_WORD       0xb10c
26 #define PCIBIOS_WRITE_CONFIG_DWORD      0xb10d
27 #define PCI_COMMAND                     0x04
28 #define PCI_COMMAND_MEM                         0x02
29 #define PCI_BAR_0                       0x10
30 #define PCI_BAR_5                       0x24
31 #define PCI_BAR_EXPROM                  0x30
32
33 #define PCIR_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( 'R' << 24 ) )
34
35 #define ROMPREFIX_EXCLUDE_PAYLOAD 1
36 #define ROMPREFIX_MORE_IMAGES 1
37 #define _pcirom_start _mrom_start
38 #include "pciromprefix.S"
39
40         .text
41         .arch i386
42         .code16
43
44 /* Obtain access to payload by exposing the expansion ROM BAR at the
45  * address currently used by a suitably large memory BAR on the same
46  * device.  The memory BAR is temporarily disabled.  Using a memory
47  * BAR on the same device means that we don't have to worry about the
48  * configuration of any intermediate PCI bridges.
49  *
50  * Parameters:
51  *   %ds:0000 : Prefix
52  *   %esi : Buffer for copy of image source (or zero if no buffer available)
53  *   %ecx : Expected offset within buffer of first payload block
54  * Returns:
55  *   %esi : Valid image source address (buffered or unbuffered)
56  *   %ecx : Actual offset within buffer of first payload block
57  *   CF set on error
58  */
59         .section ".text16.early", "awx", @progbits
60         .globl  open_payload
61 open_payload:
62         /* Preserve registers */
63         pushl   %eax
64         pushw   %bx
65         pushl   %edx
66         pushl   %edi
67         pushw   %bp
68         pushw   %es
69         pushw   %ds
70
71         /* Retrieve bus:dev.fn from .prefix */
72         movw    init_pci_busdevfn, %bx
73
74         /* Set up %ds for access to .text16.early */
75         pushw   %cs
76         popw    %ds
77
78         /* Set up %es for access to flat address space */
79         xorw    %ax, %ax
80         movw    %ax, %es
81
82         /* Store bus:dev.fn to .text16.early */
83         movw    %bx, payload_pci_busdevfn
84
85         /* Get expansion ROM BAR current value */
86         movw    $PCI_BAR_EXPROM, %di
87         call    pci_read_bar
88         movl    %eax, rom_bar_orig_value
89
90         /* Get expansion ROM BAR size */
91         call    pci_size_mem_bar_low
92         movl    %ecx, rom_bar_size
93
94         /* Find a suitable memory BAR to use */
95         movw    $PCI_BAR_0, %di         /* %di is PCI BAR register */
96         xorw    %bp, %bp                /* %bp is increment */
97 find_mem_bar:
98         /* Move to next BAR */
99         addw    %bp, %di
100         cmpw    $PCI_BAR_5, %di
101         jle     1f
102         stc
103         movl    $0xbabababa, %esi       /* Report "No suitable BAR" */
104         movl    rom_bar_size, %ecx
105         jmp     99f
106 1:      movw    $4, %bp
107
108         /* Get BAR current value */
109         call    pci_read_bar
110
111         /* Skip non-existent BARs */
112         notl    %eax
113         testl   %eax, %eax
114         notl    %eax
115         jz      find_mem_bar
116
117         /* Skip I/O BARs */
118         testb   $0x01, %al
119         jnz     find_mem_bar
120
121         /* Set increment to 8 for 64-bit BARs */
122         testb   $0x04, %al
123         jz      1f
124         movw    $8, %bp
125 1:
126         /* Skip 64-bit BARs with high dword set; we couldn't use this
127          * address for the (32-bit) expansion ROM BAR anyway
128          */
129         testl   %edx, %edx
130         jnz     find_mem_bar
131
132         /* Get low dword of BAR size */
133         call    pci_size_mem_bar_low
134
135         /* Skip BARs smaller than the expansion ROM BAR */
136         cmpl    %ecx, rom_bar_size
137         ja      find_mem_bar
138
139         /* We have a memory BAR with a 32-bit address that is large
140          * enough to use.  Store BAR number and original value.
141          */
142         movw    %di, stolen_bar_register
143         movl    %eax, stolen_bar_orig_value
144
145         /* Remove flags from BAR address */
146         xorb    %al, %al
147
148         /* Write zero to our stolen BAR.  This doesn't technically
149          * disable it, but it's a pretty safe bet that the PCI bridge
150          * won't pass through accesses to this region anyway.  Note
151          * that the high dword (if any) must already be zero.
152          */
153         xorl    %ecx, %ecx
154         call    pci_write_config_dword
155
156         /* Enable expansion ROM BAR at stolen BAR's address */
157         movl    %eax, %ecx
158         orb     $0x1, %cl
159         movw    $PCI_BAR_EXPROM, %di
160         call    pci_write_config_dword
161
162         /* Locate our ROM image */
163 1:      movl    $0xaa55, %ecx                           /* 55aa signature */
164         addr32 es cmpw %cx, (%eax)
165         jne     2f
166         movl    $PCIR_SIGNATURE, %ecx                   /* PCIR signature */
167         addr32 es movzwl 0x18(%eax), %edx
168         addr32 es cmpl %ecx, (%eax,%edx)
169         jne     2f
170         addr32 es cmpl $_build_id, build_id(%eax)       /* iPXE build ID */
171         je      3f
172         movl    $0x80, %ecx                             /* Last image */
173         addr32 es testb %cl, 0x15(%eax,%edx)
174         jnz     2f
175         addr32 es movzwl 0x10(%eax,%edx), %ecx          /* PCIR image length */
176         shll    $9, %ecx
177         addl    %ecx, %eax
178         jmp     1b
179 2:      /* Failure */
180         stc
181         movl    %eax, %esi              /* Report failure address */
182         jmp     99f
183 3:
184
185         /* Copy payload to buffer, or set buffer address to BAR address */
186         testl   %esi, %esi
187         jz      1f
188         /* We have a buffer; copy payload to it.  Since .mrom is
189          * designed specifically for real hardware, we assume that
190          * flat real mode is working properly.  (In the unlikely event
191          * that this code is run inside a hypervisor that doesn't
192          * properly support flat real mode, it will die horribly.)
193          */
194         pushl   %esi
195         movl    %esi, %edi
196         movl    %eax, %esi
197         addr32 es movzbl 2(%esi), %ecx
198         shll    $7, %ecx
199         addr32 es movzwl mpciheader_image_length(%esi,%ecx,4), %edx
200         shll    $7, %edx
201         addl    %edx, %ecx
202         addr32 es rep movsl
203         popl    %esi
204         jmp     2f
205 1:      /* We have no buffer; set %esi to the BAR address */
206         movl    %eax, %esi
207 2:
208
209         /* Locate first payload block (after the dummy ROM header) */
210         addr32 es movzbl 2(%esi), %ecx
211         shll    $9, %ecx
212         addl    $_pprefix_skip, %ecx
213
214         clc
215         /* Restore registers and return */
216 99:     popw    %ds
217         popw    %es
218         popw    %bp
219         popl    %edi
220         popl    %edx
221         popw    %bx
222         popl    %eax
223         lret
224         .size   open_payload, . - open_payload
225
226         .section ".text16.early.data", "aw", @progbits
227 payload_pci_busdevfn:
228         .word   0
229         .size   payload_pci_busdevfn, . - payload_pci_busdevfn
230
231         .section ".text16.early.data", "aw", @progbits
232 rom_bar_orig_value:
233         .long   0
234         .size   rom_bar_orig_value, . - rom_bar_orig_value
235
236         .section ".text16.early.data", "aw", @progbits
237 rom_bar_size:
238         .long   0
239         .size   rom_bar_size, . - rom_bar_size
240
241         .section ".text16.early.data", "aw", @progbits
242 stolen_bar_register:
243         .word   0
244         .size   stolen_bar_register, . - stolen_bar_register
245
246         .section ".text16.early.data", "aw", @progbits
247 stolen_bar_orig_value:
248         .long   0
249         .size   stolen_bar_orig_value, . - stolen_bar_orig_value
250
251 /* Restore original BAR values
252  *
253  * Parameters:
254  *   none
255  * Returns:
256  *   none
257  */
258         .section ".text16.early", "awx", @progbits
259         .globl  close_payload
260 close_payload:
261         /* Preserve registers */
262         pushw   %bx
263         pushw   %di
264         pushl   %ecx
265         pushw   %ds
266
267         /* Set up %ds for access to .text16.early */
268         pushw   %cs
269         popw    %ds
270
271         /* Retrieve stored bus:dev.fn */
272         movw    payload_pci_busdevfn, %bx
273
274         /* Restore expansion ROM BAR original value */
275         movw    $PCI_BAR_EXPROM, %di
276         movl    rom_bar_orig_value, %ecx
277         call    pci_write_config_dword
278
279         /* Restore stolen BAR original value */
280         movw    stolen_bar_register, %di
281         movl    stolen_bar_orig_value, %ecx
282         call    pci_write_config_dword
283
284         /* Restore registers and return */
285         popw    %ds
286         popl    %ecx
287         popw    %di
288         popw    %bx
289         lret
290         .size   close_payload, . - close_payload
291
292 /* Get PCI BAR value
293  *
294  * Parameters:
295  *   %bx : PCI bus:dev.fn
296  *   %di : PCI BAR register number
297  * Returns:
298  *   %edx:%eax : PCI BAR value
299  */
300         .section ".text16.early", "awx", @progbits
301 pci_read_bar:
302         /* Preserve registers */
303         pushl   %ecx
304         pushw   %di
305
306         /* Read low dword value */
307         call    pci_read_config_dword
308         movl    %ecx, %eax
309
310         /* Read high dword value, if applicable */
311         xorl    %edx, %edx
312         andb    $0x07, %cl
313         cmpb    $0x04, %cl
314         jne     1f
315         addw    $4, %di
316         call    pci_read_config_dword
317         movl    %ecx, %edx
318 1:
319         /* Restore registers and return */
320         popw    %di
321         popl    %ecx
322         ret
323         .size   pci_read_bar, . - pci_read_bar
324
325 /* Get low dword of PCI memory BAR size
326  *
327  * Parameters:
328  *   %bx : PCI bus:dev.fn
329  *   %di : PCI BAR register number
330  *   %eax : Low dword of current PCI BAR value
331  * Returns:
332  *   %ecx : PCI BAR size
333  */
334         .section ".text16.early", "awx", @progbits
335 pci_size_mem_bar_low:
336         /* Preserve registers */
337         pushw   %dx
338
339         /* Disable memory accesses */
340         xorw    %dx, %dx
341         call    pci_set_mem_access
342
343         /* Write all ones to BAR */
344         xorl    %ecx, %ecx
345         decl    %ecx
346         call    pci_write_config_dword
347
348         /* Read back BAR */
349         call    pci_read_config_dword
350
351         /* Calculate size */
352         notl    %ecx
353         orb     $0x0f, %cl
354         incl    %ecx
355
356         /* Restore original value */
357         pushl   %ecx
358         movl    %eax, %ecx
359         call    pci_write_config_dword
360         popl    %ecx
361
362         /* Enable memory accesses */
363         movw    $PCI_COMMAND_MEM, %dx
364         call    pci_set_mem_access
365
366         /* Restore registers and return */
367         popw    %dx
368         ret
369         .size   pci_size_mem_bar_low, . - pci_size_mem_bar_low
370
371 /* Read PCI config dword
372  *
373  * Parameters:
374  *   %bx : PCI bus:dev.fn
375  *   %di : PCI register number
376  * Returns:
377  *   %ecx : Dword value
378  */
379         .section ".text16.early", "awx", @progbits
380 pci_read_config_dword:
381         /* Preserve registers */
382         pushl   %eax
383         pushl   %ebx
384         pushl   %edx
385
386         /* Issue INT 0x1a,b10a */
387         movw    $PCIBIOS_READ_CONFIG_DWORD, %ax
388         int     $0x1a
389
390         /* Restore registers and return */
391         popl    %edx
392         popl    %ebx
393         popl    %eax
394         ret
395         .size   pci_read_config_dword, . - pci_read_config_dword
396
397 /* Write PCI config dword
398  *
399  * Parameters:
400  *   %bx : PCI bus:dev.fn
401  *   %di : PCI register number
402  *   %ecx : PCI BAR value
403  * Returns:
404  *   none
405  */
406         .section ".text16.early", "awx", @progbits
407 pci_write_config_dword:
408         /* Preserve registers */
409         pushal
410
411         /* Issue INT 0x1a,b10d */
412         movw    $PCIBIOS_WRITE_CONFIG_DWORD, %ax
413         int     $0x1a
414
415         /* Restore registers and return */
416         popal
417         ret
418         .size   pci_write_config_dword, . - pci_write_config_dword
419
420 /* Enable/disable memory access response in PCI command word
421  *
422  * Parameters:
423  *   %bx : PCI bus:dev.fn
424  *   %dx : PCI_COMMAND_MEM, or zero
425  * Returns:
426  *   none
427  */
428         .section ".text16.early", "awx", @progbits
429 pci_set_mem_access:
430         /* Preserve registers */
431         pushal
432
433         /* Read current value of command register */
434         pushw   %bx
435         pushw   %dx
436         movw    $PCI_COMMAND, %di
437         movw    $PCIBIOS_READ_CONFIG_WORD, %ax
438         int     $0x1a
439         popw    %dx
440         popw    %bx
441
442         /* Set memory access enable as appropriate */
443         andw    $~PCI_COMMAND_MEM, %cx
444         orw     %dx, %cx
445
446         /* Write new value of command register */
447         movw    $PCIBIOS_WRITE_CONFIG_WORD, %ax
448         int     $0x1a
449
450         /* Restore registers and return */
451         popal
452         ret
453         .size   pci_set_mem_access, . - pci_set_mem_access
454
455 /* Payload prefix
456  *
457  * We include a dummy ROM header to cover the "hidden" portion of the
458  * overall ROM image.
459  */
460         .globl  _payload_align
461         .equ    _payload_align, 512
462         .section ".pprefix", "ax", @progbits
463         .org    0x00
464 mromheader:
465         .word   0xaa55                  /* BIOS extension signature */
466         .org    0x18
467         .word   mpciheader
468         .org    0x1a
469         .word   0
470         .size   mromheader, . - mromheader
471
472 mpciheader:
473         .ascii  "PCIR"                  /* Signature */
474         .word   pci_vendor_id           /* Vendor identification */
475         .word   pci_device_id           /* Device identification */
476         .word   0x0000                  /* Device list pointer */
477         .word   mpciheader_len          /* PCI data structure length */
478         .byte   0x03                    /* PCI data structure revision */
479         .byte   0x02, 0x00, 0x00        /* Class code */
480 mpciheader_image_length:
481         .word   0                       /* Image length */
482         .word   0x0001                  /* Revision level */
483         .byte   0xff                    /* Code type */
484         .byte   0x80                    /* Last image indicator */
485 mpciheader_runtime_length:
486         .word   0                       /* Maximum run-time image length */
487         .word   0x0000                  /* Configuration utility code header */
488         .word   0x0000                  /* DMTF CLP entry point */
489         .equ    mpciheader_len, . - mpciheader
490         .size   mpciheader, . - mpciheader
491
492         .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
493         .ascii  "APPW"
494         .long   mpciheader_image_length
495         .long   512
496         .long   0
497         .ascii  "APPW"
498         .long   mpciheader_runtime_length
499         .long   512
500         .long   0
501         .previous
502
503 /* Fix up additional image source size
504  *
505  */
506         .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
507         .ascii  "ADPW"
508         .long   extra_size
509         .long   512
510         .long   0
511         .previous