From bdc48bd1e496497116f2bffd2da3643a5c7e39ab Mon Sep 17 00:00:00 2001 From: Jonathan Buzzard Date: Sun, 25 Oct 1998 09:55:29 +0000 Subject: [PATCH] Added a new debugging channel io to allow read/writes on a port to be logged to a file. --- documentation/ioport-trace-hints | 223 +++++++++++++++++++++++++++++++ include/debug.h | 169 +++++++++++------------ include/debugdefs.h | 4 +- miscemu/instr.c | 84 ++++++++++-- 4 files changed, 387 insertions(+), 93 deletions(-) create mode 100644 documentation/ioport-trace-hints diff --git a/documentation/ioport-trace-hints b/documentation/ioport-trace-hints new file mode 100644 index 00000000000..9c6521a9c8d --- /dev/null +++ b/documentation/ioport-trace-hints @@ -0,0 +1,223 @@ +cat > /dev/null < >(sed 's/^[^:]*:io:[^ ]* //' > YYYY) + +You will need large amounts of hard disk space (read hundreds of megabytes if +you do a full page scan), and for reasonable performance a really fast +processor and lots of RAM. + +You might well find the log compression program that David Campbell + wrote helpfull in reducing the size of the log files. +This can be obtained by the following command: + + sh ioport-trace-hints + +This should extract shrink.c (which is located at the end of this file. Compile +the log compression program by: + + cc shrink.c -o shrink + +Use the shrink program to reduce the physical size of the raw log as follows: + + cat log | shrink > log2 + +The trace has the basic form of + + XXXX > YY @ ZZZZ:ZZZZ + +where XXXX is the port in hexidecimal being accessed, YY is the data written +(or read) from the port, and ZZZZ:ZZZZ is the address in memory of the +instruction that accessed the port. The direction of the arrow indicates +whether the data was written or read from the port. + + > data was written to the port + < data was read from the port + + +My basic tip for interperating these logs is to pay close attention to the +addresses of the IO instructions. There grouping and sometimes proximity should +reveal the presence of subroutines in the driver. By studying the different +versions you should be able to work them out. For example consider the +following section of trace from my UMAX Astra 600P + + 0x378 > 55 @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + 0x378 > aa @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + 0x378 > 00 @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + 0x378 > 00 @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + 0x378 > 00 @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + 0x378 > 00 @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + +As you can see their is a repeating structure starting at address 0297:01ec +that consists of four io access on the parallel port. Looking at it the first +io access writes a changing byte to the data port the second always writes the +byte 0x05 to the control port, then a value which always seems to 0x8f is read +from the status port at which point a byte 0x04 is written to the control port. +By studying this and other sections of the trace we can write a C routine that +emulates this, shown below with some macros to make reading/writing on the +parallel port easier to read. + + +#define r_dtr(x) inb(x) +#define r_str(x) inb(x+1) +#define r_ctr(x) inb(x+2) +#define w_dtr(x,y) outb(y, x) +#define w_str(x,y) outb(y, x+1) +#define w_ctr(x,y) outb(y, x+2) + +/* + * Seems to be sending a command byte to the scanner + * + */ +int udpp_put(int udpp_base, unsigned char command) +{ + int loop,value; + + w_dtr(udpp_base, command); + w_ctr(udpp_base, 0x05); + + for (loop=0;loop<10;loop++) + if (((value=r_str(udpp_base)) & 0x80)!=0x00) { + w_ctr(udpp_base, 0x04); + return value & 0xf8; + } + + return (value & 0xf8) | 0x01; +} + + +For the UMAX Astra 600P only seven such routines exist (well 14 really, seven +for SPP and seven for EPP). Whether you choose to disassemble the driver at +this point to verify the routines is your own choice. If you do, the address +from the trace should help in locating them in the disassembly. + +You will probably then find it useful to write a script/perl/C program to +analyse the logfile and decode them futher as this can reveal higher level +grouping of the low level routines. For example from the logs from my UMAX +Astra 600P when decoded futher reveal (this is a small snippet) + + +start: +put: 55 8f +put: aa 8f +put: 00 8f +put: 00 8f +put: 00 8f +put: c2 8f +wait: ff +get: af,87 +wait: ff +get: af,87 +end: cc +start: +put: 55 8f +put: aa 8f +put: 00 8f +put: 03 8f +put: 05 8f +put: 84 8f +wait: ff + +From this it is easy to see that put routine is oftern gouped together in five +sucessive calls sending information to the scanner. Once these are understood +it should be possible to process the logs further to show the higher level +routines in an easy to see format. Once the higest level format that you +can derive from this process is understood, you then need to produce a +series of scans varying only one parameter between them, so you can +discover how to set the various parameters for the scanner. + + +Jonathan Buzzard + + + +-------------------------------------------------------------------- +The following is the shrink.c program. +EOF +cat > shrink.c < +#include + +void +main (void) +{ + char buff[256], lastline[256]; + int count; + + count = 0; + lastline[0] = 0; + + while (!feof (stdin)) + { + fgets (buff, sizeof (buff), stdin); + if (strcmp (buff, lastline) == 0) + { + count++; + } + else + { + if (count > 1) + fprintf (stdout, "# Last line repeated %i times #\n", count); + fprintf (stdout, "%s", buff); + strcpy (lastline, buff); + count = 1; + } + } +} +EOF diff --git a/include/debug.h b/include/debug.h index 8a880c9b5b9..346a07bbef8 100644 --- a/include/debug.h +++ b/include/debug.h @@ -68,90 +68,91 @@ #define dbch_int19 60 #define dbch_int21 61 #define dbch_int31 62 -#define dbch_ipaddress 63 -#define dbch_key 64 -#define dbch_keyboard 65 -#define dbch_ldt 66 -#define dbch_listbox 67 -#define dbch_listview 68 -#define dbch_local 69 -#define dbch_mci 70 -#define dbch_mcianim 71 -#define dbch_mciwave 72 -#define dbch_mdi 73 -#define dbch_menu 74 -#define dbch_message 75 -#define dbch_metafile 76 -#define dbch_midi 77 -#define dbch_mmaux 78 -#define dbch_mmio 79 -#define dbch_mmsys 80 -#define dbch_mmtime 81 -#define dbch_module 82 -#define dbch_mpr 83 -#define dbch_msacm 84 -#define dbch_msg 85 -#define dbch_nativefont 86 -#define dbch_nonclient 87 -#define dbch_ntdll 88 -#define dbch_ole 89 -#define dbch_pager 90 -#define dbch_palette 91 -#define dbch_pidl 92 -#define dbch_print 93 -#define dbch_process 94 -#define dbch_profile 95 -#define dbch_progress 96 -#define dbch_prop 97 -#define dbch_psapi 98 -#define dbch_psdrv 99 -#define dbch_rebar 100 -#define dbch_reg 101 -#define dbch_region 102 -#define dbch_relay 103 -#define dbch_resource 104 -#define dbch_s 105 -#define dbch_scroll 106 -#define dbch_security 107 -#define dbch_segment 108 -#define dbch_selector 109 -#define dbch_sem 110 -#define dbch_sendmsg 111 -#define dbch_shell 112 -#define dbch_shm 113 -#define dbch_snoop 114 -#define dbch_sound 115 -#define dbch_static 116 -#define dbch_statusbar 117 -#define dbch_stress 118 -#define dbch_string 119 -#define dbch_syscolor 120 -#define dbch_system 121 -#define dbch_tab 122 -#define dbch_task 123 -#define dbch_text 124 -#define dbch_thread 125 -#define dbch_thunk 126 -#define dbch_timer 127 -#define dbch_toolbar 128 -#define dbch_toolhelp 129 -#define dbch_tooltips 130 -#define dbch_trackbar 131 -#define dbch_treeview 132 -#define dbch_tweak 133 -#define dbch_uitools 134 -#define dbch_updown 135 -#define dbch_ver 136 -#define dbch_virtual 137 -#define dbch_vxd 138 -#define dbch_win 139 -#define dbch_win16drv 140 -#define dbch_win32 141 -#define dbch_wing 142 -#define dbch_winsock 143 -#define dbch_wnet 144 -#define dbch_x11 145 -#define dbch_x11drv 146 +#define dbch_io 63 +#define dbch_ipaddress 64 +#define dbch_key 65 +#define dbch_keyboard 66 +#define dbch_ldt 67 +#define dbch_listbox 68 +#define dbch_listview 69 +#define dbch_local 70 +#define dbch_mci 71 +#define dbch_mcianim 72 +#define dbch_mciwave 73 +#define dbch_mdi 74 +#define dbch_menu 75 +#define dbch_message 76 +#define dbch_metafile 77 +#define dbch_midi 78 +#define dbch_mmaux 79 +#define dbch_mmio 80 +#define dbch_mmsys 81 +#define dbch_mmtime 82 +#define dbch_module 83 +#define dbch_mpr 84 +#define dbch_msacm 85 +#define dbch_msg 86 +#define dbch_nativefont 87 +#define dbch_nonclient 88 +#define dbch_ntdll 89 +#define dbch_ole 90 +#define dbch_pager 91 +#define dbch_palette 92 +#define dbch_pidl 93 +#define dbch_print 94 +#define dbch_process 95 +#define dbch_profile 96 +#define dbch_progress 97 +#define dbch_prop 98 +#define dbch_psapi 99 +#define dbch_psdrv 100 +#define dbch_rebar 101 +#define dbch_reg 102 +#define dbch_region 103 +#define dbch_relay 104 +#define dbch_resource 105 +#define dbch_s 106 +#define dbch_scroll 107 +#define dbch_security 108 +#define dbch_segment 109 +#define dbch_selector 110 +#define dbch_sem 111 +#define dbch_sendmsg 112 +#define dbch_shell 113 +#define dbch_shm 114 +#define dbch_snoop 115 +#define dbch_sound 116 +#define dbch_static 117 +#define dbch_statusbar 118 +#define dbch_stress 119 +#define dbch_string 120 +#define dbch_syscolor 121 +#define dbch_system 122 +#define dbch_tab 123 +#define dbch_task 124 +#define dbch_text 125 +#define dbch_thread 126 +#define dbch_thunk 127 +#define dbch_timer 128 +#define dbch_toolbar 129 +#define dbch_toolhelp 130 +#define dbch_tooltips 131 +#define dbch_trackbar 132 +#define dbch_treeview 133 +#define dbch_tweak 134 +#define dbch_uitools 135 +#define dbch_updown 136 +#define dbch_ver 137 +#define dbch_virtual 138 +#define dbch_vxd 139 +#define dbch_win 140 +#define dbch_win16drv 141 +#define dbch_win32 142 +#define dbch_wing 143 +#define dbch_winsock 144 +#define dbch_wnet 145 +#define dbch_x11 146 +#define dbch_x11drv 147 /* Definitions for classes identifiers */ #define dbcl_fixme 0 #define dbcl_err 1 diff --git a/include/debugdefs.h b/include/debugdefs.h index 3313d2d6e35..42e6c924a47 100644 --- a/include/debugdefs.h +++ b/include/debugdefs.h @@ -4,7 +4,7 @@ #include "debugtools.h" #endif -#define DEBUG_CHANNEL_COUNT 147 +#define DEBUG_CHANNEL_COUNT 148 #ifdef DEBUG_RUNTIME short debug_msg_enabled[][DEBUG_CLASS_COUNT] = { {1, 1, 0, 0}, @@ -154,6 +154,7 @@ short debug_msg_enabled[][DEBUG_CLASS_COUNT] = { {1, 1, 0, 0}, {1, 1, 0, 0}, {1, 1, 0, 0}, +{1, 1, 0, 0}, }; const char* debug_ch_name[] = { "1", @@ -219,6 +220,7 @@ const char* debug_ch_name[] = { "int19", "int21", "int31", +"io", "ipaddress", "key", "keyboard", diff --git a/miscemu/instr.c b/miscemu/instr.c index 91d42b54e2d..8d57e3722e9 100644 --- a/miscemu/instr.c +++ b/miscemu/instr.c @@ -489,21 +489,41 @@ BOOL32 INSTR_EmulateInstruction( SIGCONTEXT *context ) { case 0x6c: *((BYTE *)data) = IO_inport( DX_sig(context), 1); + TRACE(io, "0x%x < %02x @ %04x:%04x\n", DX_sig(context), + *((BYTE *)data), CS_sig(context), IP_sig(context)); break; case 0x6d: if (long_op) + { *((DWORD *)data) = IO_inport( DX_sig(context), 4); + TRACE(io, "0x%x < %08lx @ %04x:%04x\n", DX_sig(context), + *((DWORD *)data), CS_sig(context), IP_sig(context)); + } else + { *((WORD *)data) = IO_inport( DX_sig(context), 2); + TRACE(io, "0x%x < %04x @ %04x:%04x\n", DX_sig(context), + *((WORD *)data), CS_sig(context), IP_sig(context)); + } break; case 0x6e: IO_outport( DX_sig(context), 1, *((BYTE *)data)); + TRACE(io, "0x%x > %02x @ %04x:%04x\n", DX_sig(context), + *((BYTE *)data), CS_sig(context), IP_sig(context)); break; case 0x6f: if (long_op) + { IO_outport( DX_sig(context), 4, *((DWORD *)data)); + TRACE(io, "0x%x > %08lx @ %04x:%04x\n", DX_sig(context), + *((DWORD *)data), CS_sig(context), IP_sig(context)); + } else + { IO_outport( DX_sig(context), 2, *((WORD *)data)); + TRACE(io, "0x%x > %04x @ %04x:%04x\n", DX_sig(context), + *((WORD *)data), CS_sig(context), IP_sig(context)); + } break; } } @@ -609,45 +629,93 @@ BOOL32 INSTR_EmulateInstruction( SIGCONTEXT *context ) case 0xe4: /* inb al,XX */ AL_sig(context) = IO_inport( instr[1], 1 ); + TRACE(io, "0x%x < %02x @ %04x:%04x\n", instr[1], + AL_sig(context), CS_sig(context), IP_sig(context)); EIP_sig(context) += prefixlen + 2; return TRUE; case 0xe5: /* in (e)ax,XX */ - if (long_op) EAX_sig(context) = IO_inport( instr[1], 4 ); - else AX_sig(context) = IO_inport( instr[1], 2 ); + if (long_op) + { + EAX_sig(context) = IO_inport( instr[1], 4 ); + TRACE(io, "0x%x < %08lx @ %04x:%04x\n", instr[1], + EAX_sig(context), CS_sig(context), IP_sig(context)); + } + else + { + AX_sig(context) = IO_inport( instr[1], 2 ); + TRACE(io, "0x%x < %04x @ %04x:%04x\n", instr[1], + AX_sig(context), CS_sig(context), IP_sig(context)); + } EIP_sig(context) += prefixlen + 2; return TRUE; case 0xe6: /* outb XX,al */ IO_outport( instr[1], 1, AL_sig(context) ); + TRACE(io, "0x%x > %02x @ %04x:%04x\n", instr[1], + AL_sig(context), CS_sig(context), IP_sig(context)); EIP_sig(context) += prefixlen + 2; return TRUE; case 0xe7: /* out XX,(e)ax */ - if (long_op) IO_outport( instr[1], 4, EAX_sig(context) ); - else IO_outport( instr[1], 2, AX_sig(context) ); + if (long_op) + { + IO_outport( instr[1], 4, EAX_sig(context) ); + TRACE(io, "0x%x > %08lx @ %04x:%04x\n", instr[1], + EAX_sig(context), CS_sig(context), IP_sig(context)); + } + else + { + IO_outport( instr[1], 2, AX_sig(context) ); + TRACE(io, "0x%x > %04x @ %04x:%04x\n", instr[1], + AX_sig(context), CS_sig(context), IP_sig(context)); + } EIP_sig(context) += prefixlen + 2; return TRUE; case 0xec: /* inb al,dx */ AL_sig(context) = IO_inport( DX_sig(context), 1 ); + TRACE(io, "0x%x < %02x @ %04x:%04x\n", DX_sig(context), + AL_sig(context), CS_sig(context), IP_sig(context)); EIP_sig(context) += prefixlen + 1; return TRUE; case 0xed: /* in (e)ax,dx */ - if (long_op) EAX_sig(context) = IO_inport( DX_sig(context), 4 ); - else AX_sig(context) = IO_inport( DX_sig(context), 2 ); + if (long_op) + { + EAX_sig(context) = IO_inport( DX_sig(context), 4 ); + TRACE(io, "0x%x < %08lx @ %04x:%04x\n", DX_sig(context), + EAX_sig(context), CS_sig(context), IP_sig(context)); + } + else + { + AX_sig(context) = IO_inport( DX_sig(context), 2 ); + TRACE(io, "0x%x < %04x @ %04x:%04x\n", DX_sig(context), + AX_sig(context), CS_sig(context), IP_sig(context)); + } EIP_sig(context) += prefixlen + 1; return TRUE; case 0xee: /* outb dx,al */ IO_outport( DX_sig(context), 1, AL_sig(context) ); + TRACE(io, "0x%x > %02x @ %04x:%04x\n", DX_sig(context), + AL_sig(context), CS_sig(context), IP_sig(context)); EIP_sig(context) += prefixlen + 1; return TRUE; case 0xef: /* out dx,(e)ax */ - if (long_op) IO_outport( DX_sig(context), 4, EAX_sig(context) ); - else IO_outport( DX_sig(context), 2, AX_sig(context) ); + if (long_op) + { + IO_outport( DX_sig(context), 4, EAX_sig(context) ); + TRACE(io, "0x%x > %08lx @ %04x:%04x\n", DX_sig(context), + EAX_sig(context), CS_sig(context), IP_sig(context)); + } + else + { + IO_outport( DX_sig(context), 2, AX_sig(context) ); + TRACE(io, "0x%x > %04x @ %04x:%04x\n", DX_sig(context), + AX_sig(context), CS_sig(context), IP_sig(context)); + } EIP_sig(context) += prefixlen + 1; return TRUE;