Transcript lesson10

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
Least significant word
31
LEN
3
16
R/W
3
LEN
2
R/W
2
LEN
1
R/W
1
Most significant word
LEN
0
R/W
0
L
0
What kinds of breakpoints?
LEN
LEN
00 = one byte
01 = two bytes
10 = undefined
11 = four bytes
R/W
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
CR4
3
other feature bits
D
E
0
Debug Status Register (DR6)
15
B B
T S
0
B
D
0
1
1
1 1
1
1
1
1
B
3
B
2
B
1
Least significant word
31
16
unused ( all bits here are set to 1 )
Most significant word
B
0
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 processorspecific 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 );