~ubuntu-branches/ubuntu/trusty/virtualbox-lts-xenial/trusty-proposed

« back to all changes in this revision

Viewing changes to src/VBox/Devices/PC/ipxe/src/arch/i386/prefix/mromprefix.S

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2016-02-23 14:28:26 UTC
  • Revision ID: package-import@ubuntu.com-20160223142826-bdu69el2z6wa2a44
Tags: upstream-4.3.36-dfsg
ImportĀ upstreamĀ versionĀ 4.3.36-dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
 *
 
18
 */
 
19
 
 
20
FILE_LICENCE ( GPL2_OR_LATER )
 
21
 
 
22
#define PCIBIOS_READ_CONFIG_WORD        0xb109
 
23
#define PCIBIOS_READ_CONFIG_DWORD       0xb10a
 
24
#define PCIBIOS_WRITE_CONFIG_WORD       0xb10c
 
25
#define PCIBIOS_WRITE_CONFIG_DWORD      0xb10d
 
26
#define PCI_COMMAND                     0x04
 
27
#define PCI_COMMAND_MEM                         0x02
 
28
#define PCI_BAR_0                       0x10
 
29
#define PCI_BAR_5                       0x24
 
30
#define PCI_BAR_EXPROM                  0x30
 
31
 
 
32
#define ROMPREFIX_EXCLUDE_PAYLOAD 1
 
33
#define _rom_start _mrom_start
 
34
#include "romprefix.S"
 
35
 
 
36
        .text
 
37
        .arch i386
 
38
        .code16
 
39
 
 
40
/* Obtain access to payload by exposing the expansion ROM BAR at the
 
41
 * address currently used by a suitably large memory BAR on the same
 
42
 * device.  The memory BAR is temporarily disabled.  Using a memory
 
43
 * BAR on the same device means that we don't have to worry about the
 
44
 * configuration of any intermediate PCI bridges.
 
45
 *
 
46
 * Parameters:
 
47
 *   %ds:0000 : Prefix
 
48
 *   %esi : Buffer for copy of image source (or zero if no buffer available)
 
49
 * Returns:
 
50
 *   %esi : Valid image source address (buffered or unbuffered)
 
51
 *   CF set on error
 
52
 */
 
53
        .section ".text16.early", "awx", @progbits
 
54
        .globl  open_payload
 
55
open_payload:
 
56
        /* Preserve registers */
 
57
        pushl   %eax
 
58
        pushw   %bx
 
59
        pushl   %ecx
 
60
        pushl   %edx
 
61
        pushl   %edi
 
62
        pushw   %bp
 
63
        pushw   %ds
 
64
 
 
65
        /* Retrieve bus:dev.fn and image source length from .prefix */
 
66
        movw    init_pci_busdevfn, %bx
 
67
        movl    image_source_len_dword, %ecx
 
68
 
 
69
        /* Set up %ds for access to .text16.early */
 
70
        pushw   %cs
 
71
        popw    %ds
 
72
 
 
73
        /* Store bus:dev.fn and image source length to .text16.early */
 
74
        movw    %bx, payload_pci_busdevfn
 
75
        movl    %ecx, rom_bar_copy_len_dword
 
76
 
 
77
        /* Get expansion ROM BAR current value */
 
78
        movw    $PCI_BAR_EXPROM, %di
 
79
        call    pci_read_bar
 
80
        movl    %eax, rom_bar_orig_value
 
81
 
 
82
        /* Get expansion ROM BAR size */
 
83
        call    pci_size_mem_bar_low
 
84
        movl    %ecx, rom_bar_size
 
85
 
 
86
        /* Find a suitable memory BAR to use */
 
87
        movw    $PCI_BAR_0, %di         /* %di is PCI BAR register */
 
88
        xorw    %bp, %bp                /* %bp is increment */
 
89
find_mem_bar:
 
90
        /* Move to next BAR */
 
91
        addw    %bp, %di
 
92
        cmpw    $PCI_BAR_5, %di
 
93
        jle     1f
 
94
        stc
 
95
        jmp     99f
 
96
1:      movw    $4, %bp
 
97
 
 
98
        /* Get BAR current value */
 
99
        call    pci_read_bar
 
100
 
 
101
        /* Skip non-existent BARs */
 
102
        notl    %eax
 
103
        testl   %eax, %eax
 
104
        notl    %eax
 
105
        jz      find_mem_bar
 
106
 
 
107
        /* Skip I/O BARs */
 
108
        testb   $0x01, %al
 
109
        jnz     find_mem_bar
 
110
 
 
111
        /* Set increment to 8 for 64-bit BARs */
 
112
        testb   $0x04, %al
 
113
        jz      1f
 
114
        movw    $8, %bp
 
115
1:
 
116
        /* Skip 64-bit BARs with high dword set; we couldn't use this
 
117
         * address for the (32-bit) expansion ROM BAR anyway
 
118
         */
 
119
        testl   %edx, %edx
 
120
        jnz     find_mem_bar
 
121
 
 
122
        /* Get low dword of BAR size */
 
123
        call    pci_size_mem_bar_low
 
124
 
 
125
        /* Skip BARs smaller than the expansion ROM BAR */
 
126
        cmpl    %ecx, rom_bar_size
 
127
        ja      find_mem_bar
 
128
 
 
129
        /* We have a memory BAR with a 32-bit address that is large
 
130
         * enough to use.  Store BAR number and original value.
 
131
         */
 
132
        movw    %di, stolen_bar_register
 
133
        movl    %eax, stolen_bar_orig_value
 
134
 
 
135
        /* Remove flags from BAR address */
 
136
        xorb    %al, %al
 
137
 
 
138
        /* Write zero to our stolen BAR.  This doesn't technically
 
139
         * disable it, but it's a pretty safe bet that the PCI bridge
 
140
         * won't pass through accesses to this region anyway.  Note
 
141
         * that the high dword (if any) must already be zero.
 
142
         */
 
143
        xorl    %ecx, %ecx
 
144
        call    pci_write_config_dword
 
145
 
 
146
        /* Enable expansion ROM BAR at stolen BAR's address */
 
147
        movl    %eax, %ecx
 
148
        orb     $0x1, %cl
 
149
        movw    $PCI_BAR_EXPROM, %di
 
150
        call    pci_write_config_dword
 
151
 
 
152
        /* Copy payload to buffer, or set buffer address to BAR address */
 
153
        testl   %esi, %esi
 
154
        jz      1f
 
155
        /* We have a buffer; copy payload to it.  Since .mrom is
 
156
         * designed specifically for real hardware, we assume that
 
157
         * flat real mode is working properly.  (In the unlikely event
 
158
         * that this code is run inside a hypervisor that doesn't
 
159
         * properly support flat real mode, it will die horribly.)
 
160
         */
 
161
        pushl   %esi
 
162
        pushw   %es
 
163
        movl    %esi, %edi
 
164
        movl    %eax, %esi
 
165
        movl    rom_bar_copy_len_dword, %ecx
 
166
        xorw    %ax, %ax
 
167
        movw    %ax, %es
 
168
        addr32 es rep movsl
 
169
        popw    %es
 
170
        popl    %esi
 
171
        jmp     2f
 
172
1:      /* We have no buffer; set %esi to the BAR address */
 
173
        movl    %eax, %esi
 
174
2:
 
175
 
 
176
        clc
 
177
        /* Restore registers and return */
 
178
99:     popw    %ds
 
179
        popw    %bp
 
180
        popl    %edi
 
181
        popl    %edx
 
182
        popl    %ecx
 
183
        popw    %bx
 
184
        popl    %eax
 
185
        lret
 
186
        .size   open_payload, . - open_payload
 
187
 
 
188
        .section ".text16.early.data", "aw", @progbits
 
189
payload_pci_busdevfn:
 
190
        .word   0
 
191
        .size   payload_pci_busdevfn, . - payload_pci_busdevfn
 
192
 
 
193
        .section ".text16.early.data", "aw", @progbits
 
194
rom_bar_orig_value:
 
195
        .long   0
 
196
        .size   rom_bar_orig_value, . - rom_bar_orig_value
 
197
 
 
198
        .section ".text16.early.data", "aw", @progbits
 
199
rom_bar_size:
 
200
        .long   0
 
201
        .size   rom_bar_size, . - rom_bar_size
 
202
 
 
203
        .section ".text16.early.data", "aw", @progbits
 
204
rom_bar_copy_len_dword:
 
205
        .long   0
 
206
        .size   rom_bar_copy_len_dword, . - rom_bar_copy_len_dword
 
207
 
 
208
        .section ".text16.early.data", "aw", @progbits
 
209
stolen_bar_register:
 
210
        .word   0
 
211
        .size   stolen_bar_register, . - stolen_bar_register
 
212
 
 
213
        .section ".text16.early.data", "aw", @progbits
 
214
stolen_bar_orig_value:
 
215
        .long   0
 
216
        .size   stolen_bar_orig_value, . - stolen_bar_orig_value
 
217
 
 
218
/* Restore original BAR values
 
219
 *
 
220
 * Parameters:
 
221
 *   none
 
222
 * Returns:
 
223
 *   none
 
224
 */
 
225
        .section ".text16.early", "awx", @progbits
 
226
        .globl  close_payload
 
227
close_payload:
 
228
        /* Preserve registers */
 
229
        pushw   %bx
 
230
        pushw   %di
 
231
        pushl   %ecx
 
232
        pushw   %ds
 
233
 
 
234
        /* Set up %ds for access to .text16.early */
 
235
        pushw   %cs
 
236
        popw    %ds
 
237
 
 
238
        /* Retrieve stored bus:dev.fn */
 
239
        movw    payload_pci_busdevfn, %bx
 
240
 
 
241
        /* Restore expansion ROM BAR original value */
 
242
        movw    $PCI_BAR_EXPROM, %di
 
243
        movl    rom_bar_orig_value, %ecx
 
244
        call    pci_write_config_dword
 
245
 
 
246
        /* Restore stolen BAR original value */
 
247
        movw    stolen_bar_register, %di
 
248
        movl    stolen_bar_orig_value, %ecx
 
249
        call    pci_write_config_dword
 
250
 
 
251
        /* Restore registers and return */
 
252
        popw    %ds
 
253
        popl    %ecx
 
254
        popw    %di
 
255
        popw    %bx
 
256
        lret
 
257
        .size   close_payload, . - close_payload
 
258
 
 
259
/* Get PCI BAR value
 
260
 *
 
261
 * Parameters:
 
262
 *   %bx : PCI bus:dev.fn
 
263
 *   %di : PCI BAR register number
 
264
 * Returns:
 
265
 *   %edx:%eax : PCI BAR value
 
266
 */
 
267
        .section ".text16.early", "awx", @progbits
 
268
pci_read_bar:
 
269
        /* Preserve registers */
 
270
        pushl   %ecx
 
271
        pushw   %di
 
272
 
 
273
        /* Read low dword value */
 
274
        call    pci_read_config_dword
 
275
        movl    %ecx, %eax
 
276
 
 
277
        /* Read high dword value, if applicable */
 
278
        xorl    %edx, %edx
 
279
        andb    $0x07, %cl
 
280
        cmpb    $0x04, %cl
 
281
        jne     1f
 
282
        addw    $4, %di
 
283
        call    pci_read_config_dword
 
284
        movl    %ecx, %edx
 
285
1:
 
286
        /* Restore registers and return */
 
287
        popw    %di
 
288
        popl    %ecx
 
289
        ret
 
290
        .size   pci_read_bar, . - pci_read_bar
 
291
 
 
292
/* Get low dword of PCI memory BAR size
 
293
 *
 
294
 * Parameters:
 
295
 *   %bx : PCI bus:dev.fn
 
296
 *   %di : PCI BAR register number
 
297
 *   %eax : Low dword of current PCI BAR value
 
298
 * Returns:
 
299
 *   %ecx : PCI BAR size
 
300
 */
 
301
        .section ".text16.early", "awx", @progbits
 
302
pci_size_mem_bar_low:
 
303
        /* Preserve registers */
 
304
        pushw   %dx
 
305
 
 
306
        /* Disable memory accesses */
 
307
        xorw    %dx, %dx
 
308
        call    pci_set_mem_access
 
309
 
 
310
        /* Write all ones to BAR */
 
311
        xorl    %ecx, %ecx
 
312
        decl    %ecx
 
313
        call    pci_write_config_dword
 
314
 
 
315
        /* Read back BAR */
 
316
        call    pci_read_config_dword
 
317
 
 
318
        /* Calculate size */
 
319
        notl    %ecx
 
320
        orb     $0x0f, %cl
 
321
        incl    %ecx
 
322
 
 
323
        /* Restore original value */
 
324
        pushl   %ecx
 
325
        movl    %eax, %ecx
 
326
        call    pci_write_config_dword
 
327
        popl    %ecx
 
328
 
 
329
        /* Enable memory accesses */
 
330
        movw    $PCI_COMMAND_MEM, %dx
 
331
        call    pci_set_mem_access
 
332
 
 
333
        /* Restore registers and return */
 
334
        popw    %dx
 
335
        ret
 
336
        .size   pci_size_mem_bar_low, . - pci_size_mem_bar_low
 
337
 
 
338
/* Read PCI config dword
 
339
 *
 
340
 * Parameters:
 
341
 *   %bx : PCI bus:dev.fn
 
342
 *   %di : PCI register number
 
343
 * Returns:
 
344
 *   %ecx : Dword value
 
345
 */
 
346
        .section ".text16.early", "awx", @progbits
 
347
pci_read_config_dword:
 
348
        /* Preserve registers */
 
349
        pushl   %eax
 
350
        pushl   %ebx
 
351
        pushl   %edx
 
352
 
 
353
        /* Issue INT 0x1a,b10a */
 
354
        movw    $PCIBIOS_READ_CONFIG_DWORD, %ax
 
355
        int     $0x1a
 
356
 
 
357
        /* Restore registers and return */
 
358
        popl    %edx
 
359
        popl    %ebx
 
360
        popl    %eax
 
361
        ret
 
362
        .size   pci_read_config_dword, . - pci_read_config_dword
 
363
 
 
364
/* Write PCI config dword
 
365
 *
 
366
 * Parameters:
 
367
 *   %bx : PCI bus:dev.fn
 
368
 *   %di : PCI register number
 
369
 *   %ecx : PCI BAR value
 
370
 * Returns:
 
371
 *   none
 
372
 */
 
373
        .section ".text16.early", "awx", @progbits
 
374
pci_write_config_dword:
 
375
        /* Preserve registers */
 
376
        pushal
 
377
 
 
378
        /* Issue INT 0x1a,b10d */
 
379
        movw    $PCIBIOS_WRITE_CONFIG_DWORD, %ax
 
380
        int     $0x1a
 
381
 
 
382
        /* Restore registers and return */
 
383
        popal
 
384
        ret
 
385
        .size   pci_write_config_dword, . - pci_write_config_dword
 
386
 
 
387
/* Enable/disable memory access response in PCI command word
 
388
 *
 
389
 * Parameters:
 
390
 *   %bx : PCI bus:dev.fn
 
391
 *   %dx : PCI_COMMAND_MEM, or zero
 
392
 * Returns:
 
393
 *   none
 
394
 */
 
395
        .section ".text16.early", "awx", @progbits
 
396
pci_set_mem_access:
 
397
        /* Preserve registers */
 
398
        pushal
 
399
 
 
400
        /* Read current value of command register */
 
401
        pushw   %bx
 
402
        pushw   %dx
 
403
        movw    $PCI_COMMAND, %di
 
404
        movw    $PCIBIOS_READ_CONFIG_WORD, %ax
 
405
        int     $0x1a
 
406
        popw    %dx
 
407
        popw    %bx
 
408
 
 
409
        /* Set memory access enable as appropriate */
 
410
        andw    $~PCI_COMMAND_MEM, %cx
 
411
        orw     %dx, %cx
 
412
 
 
413
        /* Write new value of command register */
 
414
        movw    $PCIBIOS_WRITE_CONFIG_WORD, %ax
 
415
        int     $0x1a
 
416
 
 
417
        /* Restore registers and return */
 
418
        popal
 
419
        ret
 
420
        .size   pci_set_mem_access, . - pci_set_mem_access
 
421
 
 
422
/* Image source area length (in dwords)
 
423
 *
 
424
 */
 
425
        .section ".prefix", "ax", @progbits
 
426
image_source_len_dword:
 
427
        .long   0
 
428
        .size   image_source_len_dword, . - image_source_len_dword
 
429
        .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
 
430
        .ascii  "ADDL"
 
431
        .long   image_source_len_dword
 
432
        .long   4
 
433
        .long   0
 
434
        .previous