[42030] | 1 | /* $Id: pcibios.c 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * PCI BIOS support.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2004-2023 Oracle and/or its affiliates.
|
---|
[42030] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[42030] | 26 | */
|
---|
| 27 |
|
---|
| 28 | #include <stdint.h>
|
---|
| 29 | #include <string.h>
|
---|
| 30 | #include "biosint.h"
|
---|
| 31 | #include "inlines.h"
|
---|
| 32 |
|
---|
| 33 | #if DEBUG_PCI
|
---|
| 34 | # define BX_DEBUG_PCI(...) BX_DEBUG(__VA_ARGS__)
|
---|
| 35 | #else
|
---|
| 36 | # define BX_DEBUG_PCI(...)
|
---|
| 37 | #endif
|
---|
| 38 |
|
---|
| 39 | /* PCI function codes. */
|
---|
| 40 | enum pci_func {
|
---|
| 41 | PCI_BIOS_PRESENT = 0x01, /* PCI BIOS presence check. */
|
---|
| 42 | FIND_PCI_DEVICE = 0x02, /* Find PCI device by ID. */
|
---|
| 43 | FIND_PCI_CLASS_CODE = 0x03, /* Find PCI device by class. */
|
---|
| 44 | GEN_SPECIAL_CYCLE = 0x06, /* Generate special cycle. */
|
---|
| 45 | READ_CONFIG_BYTE = 0x08, /* Read a byte from PCI config space. */
|
---|
| 46 | READ_CONFIG_WORD = 0x09, /* Read a word from PCI config space. */
|
---|
| 47 | READ_CONFIG_DWORD = 0x0A, /* Read a dword from PCI config space. */
|
---|
| 48 | WRITE_CONFIG_BYTE = 0x0B, /* Write a byte to PCI config space. */
|
---|
| 49 | WRITE_CONFIG_WORD = 0x0C, /* Write a word to PCI config space. */
|
---|
| 50 | WRITE_CONFIG_DWORD = 0x0D, /* Write a dword to PCI config space. */
|
---|
| 51 | GET_IRQ_ROUTING = 0x0E, /* Get IRQ routing table. */
|
---|
| 52 | SET_PCI_HW_INT = 0x0F, /* Set PCI hardware interrupt. */
|
---|
| 53 | };
|
---|
| 54 |
|
---|
| 55 | enum pci_error {
|
---|
| 56 | SUCCESSFUL = 0x00, /* Success. */
|
---|
| 57 | FUNC_NOT_SUPPORTED = 0x81, /* Unsupported function. */
|
---|
| 58 | BAD_VENDOR_ID = 0x83, /* Bad vendor ID (all bits set) passed. */
|
---|
| 59 | DEVICE_NOT_FOUND = 0x86, /* No matching device found. */
|
---|
| 60 | BAD_REGISTER_NUMBER = 0x87, /* Register number out of range. */
|
---|
| 61 | SET_FAILED = 0x88, /* Failed to set PCI interrupt. */
|
---|
| 62 | BUFFER_TOO_SMALL = 0x89 /* Routing table buffer insufficient. */
|
---|
| 63 | };
|
---|
| 64 |
|
---|
[63562] | 65 | /// @todo merge with system.c
|
---|
[42030] | 66 | #define AX r.gr.u.r16.ax
|
---|
| 67 | #define BX r.gr.u.r16.bx
|
---|
| 68 | #define CX r.gr.u.r16.cx
|
---|
| 69 | #define DX r.gr.u.r16.dx
|
---|
| 70 | #define SI r.gr.u.r16.si
|
---|
| 71 | #define DI r.gr.u.r16.di
|
---|
| 72 | #define BP r.gr.u.r16.bp
|
---|
| 73 | #define SP r.gr.u.r16.sp
|
---|
| 74 | #define EAX r.gr.u.r32.eax
|
---|
| 75 | #define EBX r.gr.u.r32.ebx
|
---|
| 76 | #define ECX r.gr.u.r32.ecx
|
---|
| 77 | #define EDX r.gr.u.r32.edx
|
---|
| 78 | #define ES r.es
|
---|
| 79 |
|
---|
| 80 | /* The 16-bit PCI BIOS service must be callable from both real and protected
|
---|
| 81 | * mode. In protected mode, the caller must set the CS selector base to F0000h
|
---|
| 82 | * (but the CS selector value is not specified!). The caller does not always
|
---|
| 83 | * provide a DS which covers the BIOS segment.
|
---|
| 84 | *
|
---|
| 85 | * Unlike APM, there are no provisions for the 32-bit PCI BIOS interface
|
---|
| 86 | * calling the 16-bit implementation.
|
---|
| 87 | *
|
---|
| 88 | * The PCI Firmware Specification requires that the PCI BIOS service is called
|
---|
| 89 | * with at least 1,024 bytes of stack space available, that interrupts are not
|
---|
| 90 | * enabled during execution, and that the routines are re-entrant.
|
---|
| 91 | *
|
---|
[48947] | 92 | * Implementation notes:
|
---|
[42030] | 93 | * - The PCI BIOS interface already uses certain 32-bit registers even in
|
---|
| 94 | * 16-bit mode. To simplify matters, all 32-bit GPRs are saved/restored and
|
---|
| 95 | * may be used by helper routines (notably for 32-bit port I/O).
|
---|
| 96 | */
|
---|
| 97 |
|
---|
| 98 | #define PCI_CFG_ADDR 0xCF8
|
---|
| 99 | #define PCI_CFG_DATA 0xCFC
|
---|
| 100 |
|
---|
[42127] | 101 | #ifdef __386__
|
---|
| 102 |
|
---|
| 103 | #define PCIxx(x) pci32_##x
|
---|
| 104 |
|
---|
| 105 | /* The stack layout is different in 32-bit mode. */
|
---|
| 106 | typedef struct {
|
---|
| 107 | pushad_regs_t gr;
|
---|
[42332] | 108 | uint32_t es;
|
---|
[42127] | 109 | uint32_t flags;
|
---|
| 110 | } pci_regs_t;
|
---|
| 111 |
|
---|
| 112 | #define FLAGS r.flags
|
---|
| 113 |
|
---|
| 114 | /* In 32-bit mode, don't do any output; not technically impossible but needs
|
---|
| 115 | * a lot of extra code.
|
---|
| 116 | */
|
---|
| 117 | #undef BX_INFO
|
---|
| 118 | #define BX_INFO(...)
|
---|
| 119 | #undef BX_DEBUG_PCI
|
---|
| 120 | #define BX_DEBUG_PCI(...)
|
---|
| 121 |
|
---|
| 122 | #else
|
---|
| 123 |
|
---|
| 124 | #define PCIxx(x) pci16_##x
|
---|
| 125 |
|
---|
| 126 | typedef struct {
|
---|
| 127 | pushad_regs_t gr;
|
---|
[45710] | 128 | uint16_t ds;
|
---|
[42127] | 129 | uint16_t es;
|
---|
| 130 | iret_addr_t ra;
|
---|
| 131 | } pci_regs_t;
|
---|
| 132 |
|
---|
| 133 | #define FLAGS r.ra.flags.u.r16.flags
|
---|
| 134 |
|
---|
| 135 | #endif
|
---|
| 136 |
|
---|
| 137 | #ifdef __386__
|
---|
| 138 |
|
---|
| 139 | /* 32-bit code can just use the compiler intrinsics. */
|
---|
| 140 | extern unsigned inpd(unsigned port);
|
---|
| 141 | extern unsigned outpd(unsigned port, unsigned value);
|
---|
| 142 | #pragma intrinsic(inpd,outpd)
|
---|
| 143 |
|
---|
| 144 | #else
|
---|
| 145 |
|
---|
[63562] | 146 | /// @todo merge with AHCI code
|
---|
[42030] | 147 |
|
---|
| 148 | /* Warning: Destroys high bits of EAX. */
|
---|
| 149 | uint32_t inpd(uint16_t port);
|
---|
| 150 | #pragma aux inpd = \
|
---|
| 151 | ".386" \
|
---|
| 152 | "in eax, dx" \
|
---|
| 153 | "mov dx, ax" \
|
---|
| 154 | "shr eax, 16" \
|
---|
| 155 | "xchg ax, dx" \
|
---|
| 156 | parm [dx] value [dx ax] modify nomemory;
|
---|
| 157 |
|
---|
| 158 | /* Warning: Destroys high bits of EAX. */
|
---|
| 159 | void outpd(uint16_t port, uint32_t val);
|
---|
| 160 | #pragma aux outpd = \
|
---|
| 161 | ".386" \
|
---|
| 162 | "xchg ax, cx" \
|
---|
| 163 | "shl eax, 16" \
|
---|
| 164 | "mov ax, cx" \
|
---|
| 165 | "out dx, eax" \
|
---|
| 166 | parm [dx] [cx ax] modify nomemory;
|
---|
| 167 |
|
---|
[42127] | 168 | #endif
|
---|
| 169 |
|
---|
[42332] | 170 | /* PCI IRQ routing expansion buffer descriptor. */
|
---|
| 171 | typedef struct {
|
---|
| 172 | uint16_t buf_size;
|
---|
| 173 | uint8_t __far *buf_ptr;
|
---|
| 174 | } pci_route_buf;
|
---|
| 175 |
|
---|
| 176 | /* Defined in assembler module .*/
|
---|
| 177 | extern char pci_routing_table[];
|
---|
| 178 | extern uint16_t pci_routing_table_size;
|
---|
| 179 |
|
---|
[42030] | 180 | /* Write the CONFIG_ADDRESS register to prepare for data access. Requires
|
---|
| 181 | * the register offset to be DWORD aligned (low two bits clear). Warning:
|
---|
| 182 | * destroys high bits of EAX.
|
---|
| 183 | */
|
---|
| 184 | void pci16_w_addr(uint16_t bus_dev_fn, uint16_t ofs, uint16_t cfg_addr);
|
---|
| 185 | #pragma aux pci16_w_addr = \
|
---|
| 186 | ".386" \
|
---|
| 187 | "movzx eax, ax" \
|
---|
| 188 | "shl eax, 8" \
|
---|
| 189 | "or eax, 80000000h" \
|
---|
| 190 | "mov al, bl" \
|
---|
| 191 | "out dx, eax" \
|
---|
| 192 | parm [ax] [bx] [dx] modify exact [ax] nomemory;
|
---|
| 193 |
|
---|
| 194 |
|
---|
| 195 | /* Select a PCI configuration register given its offset and bus/dev/fn.
|
---|
| 196 | * This is largely a wrapper to avoid excessive inlining.
|
---|
| 197 | */
|
---|
[42127] | 198 | void PCIxx(select_reg)(uint16_t bus_dev_fn, uint16_t ofs)
|
---|
[42030] | 199 | {
|
---|
| 200 | pci16_w_addr(bus_dev_fn, ofs & ~3, PCI_CFG_ADDR);
|
---|
| 201 | }
|
---|
| 202 |
|
---|
[42127] | 203 | /* Selected configuration space offsets. */
|
---|
[42030] | 204 | #define PCI_VEN_ID 0x00
|
---|
| 205 | #define PCI_DEV_ID 0x02
|
---|
| 206 | #define PCI_REV_ID 0x08
|
---|
| 207 | #define PCI_CLASS_CODE 0x09
|
---|
| 208 | #define PCI_HEADER_TYPE 0x0E
|
---|
[42127] | 209 | #define PCI_BRIDGE_SUBORD 0x1A
|
---|
[42030] | 210 |
|
---|
[42127] | 211 | /* To avoid problems with 16-bit code, we reserve the last possible
|
---|
| 212 | * bus/dev/fn combination (65,535). Upon reaching this location, the
|
---|
| 213 | * probing will end.
|
---|
| 214 | */
|
---|
[42793] | 215 | #define BUSDEVFN_NOT_FOUND 0xFFFF
|
---|
[42030] | 216 |
|
---|
[42793] | 217 | /* In the search algorithm, we decrement the device index every time
|
---|
| 218 | * a matching device is found. If the requested device is indeed found,
|
---|
| 219 | * the index will have decremented down to -1/0xFFFF.
|
---|
| 220 | */
|
---|
| 221 | #define INDEX_DEV_FOUND 0xFFFF
|
---|
| 222 |
|
---|
[42030] | 223 | /* Find a specified PCI device, either by vendor+device ID or class.
|
---|
[78052] | 224 | * If index is non-zero, the n-th device will be located. When searching
|
---|
| 225 | * by class, the ignore_if flag only compares the base and sub-class code,
|
---|
| 226 | * ignoring the programming interface code.
|
---|
[42030] | 227 | *
|
---|
| 228 | * Note: This function is somewhat performance critical; since it may
|
---|
| 229 | * generate a high number of port I/O accesses, it can take a significant
|
---|
| 230 | * amount of time in cases where the caller is looking for a number of
|
---|
| 231 | * non-present devices.
|
---|
| 232 | */
|
---|
[78052] | 233 | uint16_t PCIxx(find_device)(uint32_t search_item, uint16_t index, int search_class, int ignore_if)
|
---|
[42030] | 234 | {
|
---|
| 235 | uint32_t data;
|
---|
| 236 | uint16_t bus_dev_fn;
|
---|
| 237 | uint8_t max_bus;
|
---|
| 238 | uint8_t hdr_type;
|
---|
[42127] | 239 | uint8_t subordinate;
|
---|
[42030] | 240 | int step;
|
---|
| 241 | int found;
|
---|
| 242 |
|
---|
| 243 | if (search_class) {
|
---|
| 244 | BX_DEBUG_PCI("PCI: Find class %08lX index %u\n",
|
---|
| 245 | search_item, index);
|
---|
[48947] | 246 | } else
|
---|
| 247 | BX_DEBUG_PCI("PCI: Find device %04X:%04X index %u\n",
|
---|
[42030] | 248 | (uint16_t)search_item, (uint16_t)(search_item >> 16), index);
|
---|
| 249 |
|
---|
| 250 | bus_dev_fn = 0; /* Start at the beginning. */
|
---|
| 251 | max_bus = 0; /* Initially assume primary bus only. */
|
---|
| 252 |
|
---|
| 253 | do {
|
---|
| 254 | /* For the first function of a device, read the device's header type.
|
---|
| 255 | * If the header type has all bits set, there's no device. A PCI
|
---|
| 256 | * multi-function device must implement function 0 and the header type
|
---|
| 257 | * will be something other than 0xFF. If the header type has the high
|
---|
| 258 | * bit clear, there is a device but it's not multi-function, so we can
|
---|
| 259 | * skip probing the next 7 sub-functions.
|
---|
| 260 | */
|
---|
| 261 | if ((bus_dev_fn & 7) == 0) {
|
---|
[42127] | 262 | PCIxx(select_reg)(bus_dev_fn, PCI_HEADER_TYPE);
|
---|
[42030] | 263 | hdr_type = inp(PCI_CFG_DATA + (PCI_HEADER_TYPE & 3));
|
---|
| 264 | if (hdr_type == 0xFF) {
|
---|
| 265 | bus_dev_fn += 8; /* Skip to next device. */
|
---|
| 266 | continue;
|
---|
| 267 | }
|
---|
| 268 | if (hdr_type & 0x80)
|
---|
| 269 | step = 1; /* MFD - try every sub-function. */
|
---|
| 270 | else
|
---|
| 271 | step = 8; /* No MFD, go to next device after probing. */
|
---|
| 272 | }
|
---|
| 273 |
|
---|
| 274 | /* If the header type indicates a bus, we're interested. The secondary
|
---|
[48947] | 275 | * and subordinate bus numbers will indicate which buses are present;
|
---|
| 276 | * thus we can determine the highest bus number. In the common case,
|
---|
[42030] | 277 | * there will be only the primary bus (i.e. bus 0) and we can avoid
|
---|
| 278 | * looking at the remaining 255 theoretically present buses. This check
|
---|
[42127] | 279 | * only needs to be done on the primary bus, since bridges must report
|
---|
| 280 | * all bridges potentially behind them.
|
---|
[42030] | 281 | */
|
---|
| 282 | if ((hdr_type & 7) == 1 && (bus_dev_fn >> 8) == 0) {
|
---|
[42127] | 283 | /* Read the subordinate (last) bridge number. */
|
---|
| 284 | PCIxx(select_reg)(bus_dev_fn, PCI_BRIDGE_SUBORD);
|
---|
| 285 | subordinate = inp(PCI_CFG_DATA + (PCI_BRIDGE_SUBORD & 3));
|
---|
| 286 | if (subordinate > max_bus)
|
---|
| 287 | max_bus = subordinate;
|
---|
[42030] | 288 | }
|
---|
| 289 |
|
---|
| 290 | /* Select the appropriate register. */
|
---|
[42127] | 291 | PCIxx(select_reg)(bus_dev_fn, search_class ? PCI_REV_ID : PCI_VEN_ID);
|
---|
[42030] | 292 | data = inpd(PCI_CFG_DATA);
|
---|
| 293 | found = 0;
|
---|
| 294 |
|
---|
[78052] | 295 | /* Only 3 or even just 2 bytes are compared for class searches. */
|
---|
[42030] | 296 | if (search_class)
|
---|
[78052] | 297 | if (ignore_if)
|
---|
| 298 | data >>= 16;
|
---|
| 299 | else
|
---|
| 300 | data >>= 8;
|
---|
[42030] | 301 |
|
---|
[42392] | 302 | #if 0
|
---|
[42030] | 303 | BX_DEBUG_PCI("PCI: Data is %08lX @ %02X:%%02X:%01X\n", data,
|
---|
| 304 | bus_dev_fn >> 8, bus_dev_fn >> 3 & 31, bus_dev_fn & 7);
|
---|
[42392] | 305 | #endif
|
---|
[42030] | 306 |
|
---|
| 307 | if (data == search_item)
|
---|
| 308 | found = 1;
|
---|
| 309 |
|
---|
| 310 | /* If device was found but index is non-zero, decrement index and
|
---|
| 311 | * continue looking. If requested device was found, index will be -1!
|
---|
| 312 | */
|
---|
| 313 | if (found && !index--)
|
---|
| 314 | break;
|
---|
| 315 |
|
---|
| 316 | bus_dev_fn += step;
|
---|
| 317 | } while ((bus_dev_fn >> 8) <= max_bus);
|
---|
| 318 |
|
---|
[42793] | 319 | if (index == INDEX_DEV_FOUND)
|
---|
[42030] | 320 | BX_DEBUG_PCI("PCI: Device found (%02X:%%02X:%01X)\n", bus_dev_fn >> 8,
|
---|
| 321 | bus_dev_fn >> 3 & 31, bus_dev_fn & 7);
|
---|
| 322 |
|
---|
[42793] | 323 | return index == INDEX_DEV_FOUND ? bus_dev_fn : BUSDEVFN_NOT_FOUND;
|
---|
[42030] | 324 | }
|
---|
| 325 |
|
---|
[42127] | 326 | void BIOSCALL PCIxx(function)(volatile pci_regs_t r)
|
---|
[42030] | 327 | {
|
---|
[42332] | 328 | pci_route_buf __far *route_buf;
|
---|
| 329 | uint16_t device;
|
---|
[42030] | 330 |
|
---|
[42532] | 331 | BX_DEBUG_PCI("PCI: AX=%04X BX=%04X CX=%04X DI=%04X\n", AX, BX, CX, DI);
|
---|
[42030] | 332 |
|
---|
| 333 | SET_AH(SUCCESSFUL); /* Assume success. */
|
---|
[48947] | 334 | CLEAR_CF();
|
---|
[42030] | 335 |
|
---|
| 336 | switch (GET_AL()) {
|
---|
| 337 | case PCI_BIOS_PRESENT:
|
---|
| 338 | AX = 0x0001; /* Configuration mechanism #1 supported. */
|
---|
| 339 | BX = 0x0210; /* Version 2.1. */
|
---|
[63562] | 340 | /// @todo return true max bus # in CL
|
---|
[42030] | 341 | CX = 0; /* Maximum bus number. */
|
---|
| 342 | EDX = 'P' | ('C' << 8) | ((uint32_t)'I' << 16) | ((uint32_t)' ' << 24);
|
---|
| 343 | break;
|
---|
| 344 | case FIND_PCI_DEVICE:
|
---|
| 345 | /* Vendor ID FFFFh is reserved so that non-present devices can
|
---|
| 346 | * be easily detected.
|
---|
| 347 | */
|
---|
[42127] | 348 | if (DX == 0xFFFF) {
|
---|
[42030] | 349 | SET_AH(BAD_VENDOR_ID);
|
---|
| 350 | SET_CF();
|
---|
| 351 | } else {
|
---|
[78052] | 352 | device = PCIxx(find_device)(DX | (uint32_t)CX << 16, SI, 0, 0);
|
---|
[42793] | 353 | if (device == BUSDEVFN_NOT_FOUND) {
|
---|
[42030] | 354 | SET_AH(DEVICE_NOT_FOUND);
|
---|
| 355 | SET_CF();
|
---|
| 356 | } else {
|
---|
| 357 | BX = device;
|
---|
| 358 | }
|
---|
| 359 | }
|
---|
| 360 | break;
|
---|
| 361 | case FIND_PCI_CLASS_CODE:
|
---|
[78052] | 362 | device = PCIxx(find_device)(ECX, SI, 1, 0);
|
---|
[42793] | 363 | if (device == BUSDEVFN_NOT_FOUND) {
|
---|
[42030] | 364 | SET_AH(DEVICE_NOT_FOUND);
|
---|
| 365 | SET_CF();
|
---|
| 366 | } else {
|
---|
| 367 | BX = device;
|
---|
| 368 | }
|
---|
| 369 | break;
|
---|
| 370 | case READ_CONFIG_BYTE:
|
---|
| 371 | case READ_CONFIG_WORD:
|
---|
| 372 | case READ_CONFIG_DWORD:
|
---|
| 373 | case WRITE_CONFIG_BYTE:
|
---|
| 374 | case WRITE_CONFIG_WORD:
|
---|
| 375 | case WRITE_CONFIG_DWORD:
|
---|
| 376 | if (DI >= 256) {
|
---|
| 377 | SET_AH(BAD_REGISTER_NUMBER);
|
---|
| 378 | SET_CF();
|
---|
| 379 | } else {
|
---|
[42127] | 380 | PCIxx(select_reg)(BX, DI);
|
---|
[42030] | 381 | switch (GET_AL()) {
|
---|
| 382 | case READ_CONFIG_BYTE:
|
---|
| 383 | SET_CL(inp(PCI_CFG_DATA + (DI & 3)));
|
---|
| 384 | break;
|
---|
| 385 | case READ_CONFIG_WORD:
|
---|
| 386 | CX = inpw(PCI_CFG_DATA + (DI & 2));
|
---|
| 387 | break;
|
---|
| 388 | case READ_CONFIG_DWORD:
|
---|
| 389 | ECX = inpd(PCI_CFG_DATA);
|
---|
| 390 | break;
|
---|
| 391 | case WRITE_CONFIG_BYTE:
|
---|
| 392 | outp(PCI_CFG_DATA + (DI & 3), GET_CL());
|
---|
| 393 | break;
|
---|
| 394 | case WRITE_CONFIG_WORD:
|
---|
| 395 | outpw(PCI_CFG_DATA + (DI & 2), CX);
|
---|
| 396 | break;
|
---|
| 397 | case WRITE_CONFIG_DWORD:
|
---|
| 398 | outpd(PCI_CFG_DATA, ECX);
|
---|
| 399 | break;
|
---|
| 400 | }
|
---|
| 401 | }
|
---|
| 402 | break;
|
---|
[42332] | 403 | case GET_IRQ_ROUTING:
|
---|
| 404 | route_buf = ES :> (void *)DI;
|
---|
[49067] | 405 | BX_DEBUG_PCI("PCI: Route Buf %04X:%04X size %04X, need %04X (at %04X:%04X)\n",
|
---|
[45710] | 406 | FP_SEG(route_buf->buf_ptr), FP_OFF(route_buf->buf_ptr),
|
---|
[49067] | 407 | route_buf->buf_size, pci_routing_table_size, ES, DI);
|
---|
[42332] | 408 | if (pci_routing_table_size > route_buf->buf_size) {
|
---|
| 409 | SET_AH(BUFFER_TOO_SMALL);
|
---|
| 410 | SET_CF();
|
---|
| 411 | } else {
|
---|
| 412 | rep_movsb(route_buf->buf_ptr, pci_routing_table, pci_routing_table_size);
|
---|
[42392] | 413 | /* IRQs 9 and 11 are PCI only. */
|
---|
| 414 | BX = (1 << 9) | (1 << 11);
|
---|
[42332] | 415 | }
|
---|
[45710] | 416 | route_buf->buf_size = pci_routing_table_size;
|
---|
[42332] | 417 | break;
|
---|
[42030] | 418 | default:
|
---|
| 419 | BX_INFO("PCI: Unsupported function AX=%04X BX=%04X called\n", AX, BX);
|
---|
| 420 | SET_AH(FUNC_NOT_SUPPORTED);
|
---|
| 421 | SET_CF();
|
---|
| 422 | }
|
---|
| 423 | }
|
---|