diff options
author | Stuart Bennett <sb476@cam.ac.uk> | 2007-11-16 00:13:50 +0000 |
---|---|---|
committer | Stuart Bennett <sb476@cam.ac.uk> | 2007-11-16 01:45:58 +0000 |
commit | 5154c73df7017a6a04a497b00c29c7edb5d12c96 (patch) | |
tree | c13108b3f32de9a8f6f34ce39eba2679356e6a48 /vbtracetool.c | |
parent | 0cbb7dd01ad08b150e7cd0d4e7dfadd0c7375598 (diff) |
inttool is dead, long live vbtracetool
Diffstat (limited to 'vbtracetool.c')
-rw-r--r-- | vbtracetool.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/vbtracetool.c b/vbtracetool.c new file mode 100644 index 0000000..94d9248 --- /dev/null +++ b/vbtracetool.c @@ -0,0 +1,156 @@ +/* + * vbtracetool, an execution tracing tool for video biosen + * + * Copyright 2007 Stuart Bennett <sb476@cam.ac.uk> + * + * Based on vbetool.c, Copyright Matthew Garrett <mjg59@srcf.ucam.org> + * + * This program is released under the terms of the GNU General Public License, + * version 2 + */ + +#include <pci/pci.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/io.h> + +#include "lrmi.h" +#include "x86emu.h" + +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; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + static struct pci_access *pacc; + struct pci_dev *p; + unsigned int c; + unsigned int pci_id; + int opt, debug = 0, mode, op = 0, opset = 0; + + while ((opt = getopt(argc, argv, "dgps:")) != -1) { + switch (opt) { + case 'd': + debug = 1; + break; + case 'g': + opset++; + break; + case 'p': + op = 2; + opset++; + break; + case 's': + op = 1; + 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; + + switch (op) { + case 0: + return (do_get_mode()); + case 1: + return (do_set_mode(mode)); + case 2: + pacc = pci_alloc(); + pacc->numeric_ids = 1; + pci_init(pacc); + + pci_scan_bus(pacc); + + 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); + return (do_post_int(pci_id)); + } + } + } + + return 0; +} |