160 likes | 185 Views
What Linux does with IDE?. Introduction to Pentium features for trapping reads/writes to memory-locations and i/o-ports. Breakpoint Address Registers. DR0. DR1. DR2. DR3. Special ‘MOV’ instructions. Use ‘mov DRn, genreg’ to write into DRn Use ‘mov genreg, DRn’ to read from DRn
E N D
What Linux does with IDE? Introduction to Pentium features for trapping reads/writes to memory-locations and i/o-ports
Breakpoint Address Registers DR0 DR1 DR2 DR3
Special ‘MOV’ instructions • Use ‘mov DRn, genreg’ to write into DRn • Use ‘mov genreg, DRn’ to read from DRn • These instructions are ‘privileged’ (i.e., can only be executed by code running in ring0)
Debug Control Register (DR7) 15 0 0 0 G D 0 0 1 G E L E G 3 L 3 G 2 L 2 G 1 L 1 G 0 L 0 Least significant word 31 16 LEN 3 R/W 3 LEN 2 R/W 2 LEN 1 R/W 1 LEN 0 R/W 0 Most significant word
What kinds of breakpoints? LEN R/W LEN 00 = one byte 01 = two bytes 10 = undefined 11 = four bytes R/W 00 = break on instruction fetch only 01 = break on data writes only 10 = break on in/out to port-address ** 11 = break on data reads or writes (but not on instruction fetches) ** Provided the DE-bit (bit 3) is set to 1 in Control Register CR4
Control Register 4 • The Pentium uses Control Register 4 to activate certain extended features of the processor, while still allowing for backward compatibility with systems software that was written for earlier x86 processors • An example: Debug Extensions (DE-bit) 31 3 0 other feature bits D E CR4
Debug Status Register (DR6) 15 0 B T B S B D 0 1 1 1 1 1 1 1 1 B 3 B 2 B 1 B 0 Least significant word 31 16 unused ( all bits here are set to 1 ) Most significant word
Where to set a breakpoint • Suppose you want to trigger a ‘debug’ fault whenever Linux tries to write/read the IDE Command/Status Register (ioport 0x1F7) • Your debug exception-handler can use the saved CS:EIP values on its stack to check whether an ‘out’ or ‘in’ was just executed • Machine-code: 0xEC for “ in %dx, %al ”, or 0xEE for “ out %al, %dx ” • Could set a ‘breakpoint’ at address EIP-1
Detecting a ‘breakpoint’ • Your debug exception-handler reads DR6 to check for occurrences of breakpoints mov eax, DR6 ; get debug status bt eax, #0 ; breakpoint #0? jnc notBP0 ; no, another cause ; test for other causes… notBP0:
The ‘asm’ construct An introduction to the GNU C/C++ compiler’s obscure syntax for doing inline assembly language
The ‘asm’ construct • When using C/C++ for systems programs, we sometimes need to employ processor-specific instructions (e.g., to access CPU registers or the current stack area) • Because our high-level languages strive for ‘portability’ across different hardware platforms, these languages don’t provide direct access to CPU registers or stack
gcc/g++ extensions • The GNU compilers support an extension to the language which allows us to insert assembler code into our instruction-stream • Operands in registers or global variables can directly appear in assembly language, like this (as can immediate operands): int count = 4; // global variable asm(“ movl count , %eax “); asm(“ imull $5, %eax, %ecx “);
Local variables • Variables defined as local to a function are more awkward to reference by name with the ‘asm’ construct, because they reside on the stack and require the generation of offsets from the %ebp register-contents • A special syntax is available for handling such situations in a manner that gcc/g++ can decipher
Template • The general construct-format is as follows: asm( instruction-template : output-operand : input-operand : clobber-list );
Example from ‘hdtraps.c’ void trap_handler( unsigned long *tos ) { unsigned long db_status; // … other instructions can go here … asm(“ movl %dr6, %eax “); asm(“ movl %%eax, %0 “ : “=m” (db_status) ); // … other instructions can go here … }
In-class exercise • Modify the ‘hdtraps.c’ module so that the output from ‘/proc/hdtraps’ is improved (i.e., more understandable to humans) • Instead of: eax=00530150 opn=EC show: 0x50 = inb( 0x01F7 ); • Instead of: eax=007402EA opn=EE show: outb( 0xEA, 0x01F7 );