/* * vbtracetool, an execution tracing tool for video biosen * * Copyright 2007 Stuart Bennett * * Based on vbetool.c, Copyright Matthew Garrett * * This program is released under the terms of the GNU General Public License, version 2 */ #include #include #include #include #include #include #include #include "lrmi.h" #include "x86emu.h" extern int reload_nv_bios(uintptr_t pcimemaddr); extern int reload_bios_from_file(char *romfile); extern void log_nv_io(); int do_set_mode(unsigned mode) { struct LRMI_regs r; memset(&r, 0, sizeof(r)); r.eax = 0x4f02; r.ebx = (mode & 0xffff) | 0x8000; r.ecx = 0; r.edx = 0; if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Error: something went wrong performing real mode call\n"); return 1; } printf("ax: 0x%04x, bx: 0x%04x\n", r.eax & 0xffff, r.ebx & 0xffff); return 0; } int do_get_mode(void) { struct LRMI_regs r; memset(&r, 0, sizeof(r)); r.eax = 0x4f03; r.ebx = 0; r.ecx = 0; r.edx = 0; if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Error: something went wrong performing real mode call\n"); return 1; } printf("ax: 0x%04x, bx: 0x%04x, mode: 0x%04x (%d)\n", r.eax & 0xffff, r.ebx & 0xffff, r.ebx & 0x3fff, r.ebx & 0x3fff); return 0; } int do_post_int(unsigned pci_device) { struct LRMI_regs r; memset(&r, 0, sizeof(r)); /* Several machines seem to want the device that they're POSTing in here */ r.eax = pci_device; /* 0xc000 is the video option ROM. The init code for each option ROM is at 0x0003 - so jump to c000:0003 and start running */ r.cs = 0xc000; r.ip = 0x0003; /* This is all heavily cargo culted but seems to work */ r.edx = 0x80; r.ds = 0x0040; if (!LRMI_call(&r)) { fprintf(stderr, "Error: something went wrong performing real mode call\n"); return 1; } printf("POST complete\n"); return 0; } int do_writeout_bios(void) { int i; for (i = 0; i < ((*((char *)0xc0002) * 512 < 0x10000) ? *((char *)0xc0002) * 512 : 0x10000); i++) fprintf(stderr, "%c", *((char *)0xc0000 + i)); return 0; } int main(int argc, char *argv[]) { static struct pci_access *pacc; struct pci_dev *p; unsigned int c; unsigned int pci_id = 0, pci_vendor; int opt, debug = 0, mode = 3, op = 'g', opset = 0, nvlog = 0, romoverride = 0, shadow = 0; char *romfile = NULL; while ((opt = getopt(argc, argv, "dglprs:wx:")) != -1) { switch (opt) { case 'd': debug = 1; break; case 'g': opset++; break; case 'l': nvlog = 1; break; case 'r': romoverride++; shadow = 1; break; case 'p': op = 'p'; opset++; break; case 's': op = 's'; opset++; mode = atoi(optarg); break; case 'w': op = 'w'; opset++; break; case 'x': romoverride++; romfile = optarg; break; default: opset = 2; } } if (optind < argc || opset > 1 || romoverride > 1) { printf("eh?\n"); exit(EXIT_FAILURE); } if (!LRMI_init()) { fprintf(stderr, "Failed to initialise LRMI (Linux Real-Mode Interface).\n"); exit(EXIT_FAILURE); } ioperm(0, 1024, 1); iopl(3); if (debug) M.x86.debug = DEBUG_TRACE_F | DEBUG_DECODE_F; /* x86emu debug flags */ else M.x86.debug = 0; if (nvlog) log_nv_io(); pacc = pci_alloc(); pacc->numeric_ids = 1; pci_init(pacc); pci_scan_bus(pacc); if (!pacc->devices) { printf("eh?\n"); exit(EXIT_FAILURE); } for (p = pacc->devices; p; p = p->next) { c = pci_read_word(p, PCI_CLASS_DEVICE); if (c == 0x300) { pci_id = (p->bus << 8) + (p->dev << 3) + (p->func & 0x7); pci_vendor = pci_read_word(p, PCI_VENDOR_ID); break; } } if (!pci_id) { printf("No graphics card found\n"); exit(EXIT_FAILURE); } printf("Using card %04x:%04x on %04x\n", pci_vendor, pci_read_word(p, PCI_DEVICE_ID), pci_id); if (romfile) { if (reload_bios_from_file(romfile)) { printf("Failed to load alternate image, bailing out\n"); exit(EXIT_FAILURE); } } else if (pci_vendor == 0x10de && !shadow) { printf("Nvidia card -- using PROM/PRAMIN BIOS\n"); if (reload_nv_bios(p->base_addr[0])) printf("Failed to load alternate image, proceeding to use PCI ROM\n"); } /* brace yourselves */ sync(); sync(); switch (op) { case 'g': return (do_get_mode()); case 'p': return (do_post_int(pci_id)); case 's': return (do_set_mode(mode)); case 'w': return (do_writeout_bios()); } return 0; }