/* * 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 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 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, op = 'g', opset = 0, nvreload = 0, nvlog = 0; while ((opt = getopt(argc, argv, "dglnps:")) != -1) { switch (opt) { case 'd': debug = 1; break; case 'g': opset++; break; case 'l': nvlog = 1; break; case 'n': nvreload = 1; break; case 'p': op = 'p'; opset++; break; case 's': op = 's'; opset++; mode = atoi(optarg); break; default: opset = 2; } } if (optind < argc || opset > 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 (nvreload) { if (pci_vendor != 0x10de) printf("Not an Nvidia card -- -n ignored\n"); else if (reload_nv_bios(p->base_addr[0])) exit(EXIT_FAILURE); } /* 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)); } return 0; }