|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2010 Michael Brown <[email protected]>. ! 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.