2 * Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <gpxe/uaccess.h>
23 #include <gpxe/gdbstub.h>
28 * GDB architecture-specific bits for i386
33 DR7_CLEAR
= 0x00000400, /* disable hardware breakpoints */
34 DR6_CLEAR
= 0xffff0ff0, /* clear breakpoint status */
37 /** Hardware breakpoint, fields stored in x86 bit pattern form */
39 int type
; /* type (1=write watchpoint, 3=access watchpoint) */
40 unsigned long addr
; /* linear address */
41 size_t len
; /* length (0=1-byte, 1=2-byte, 3=4-byte) */
45 static struct hwbp hwbps
[ 4 ];
46 static gdbreg_t dr7
= DR7_CLEAR
;
48 static struct hwbp
*gdbmach_find_hwbp ( int type
, unsigned long addr
, size_t len
) {
49 struct hwbp
*available
= NULL
;
51 for ( i
= 0; i
< sizeof hwbps
/ sizeof hwbps
[ 0 ]; i
++ ) {
52 if ( hwbps
[ i
].type
== type
&& hwbps
[ i
].addr
== addr
&& hwbps
[ i
].len
== len
) {
55 if ( !hwbps
[ i
].enabled
) {
56 available
= &hwbps
[ i
];
62 static void gdbmach_commit_hwbp ( struct hwbp
*bp
) {
63 unsigned int regnum
= bp
- hwbps
;
65 /* Set breakpoint address */
66 assert ( regnum
< ( sizeof hwbps
/ sizeof hwbps
[ 0 ] ) );
69 __asm__
__volatile__ ( "movl %0, %%dr0\n" : : "r" ( bp
->addr
) );
72 __asm__
__volatile__ ( "movl %0, %%dr1\n" : : "r" ( bp
->addr
) );
75 __asm__
__volatile__ ( "movl %0, %%dr2\n" : : "r" ( bp
->addr
) );
78 __asm__
__volatile__ ( "movl %0, %%dr3\n" : : "r" ( bp
->addr
) );
83 dr7
&= ~( 0x3 << ( 16 + 4 * regnum
) );
84 dr7
|= bp
->type
<< ( 16 + 4 * regnum
);
87 dr7
&= ~( 0x3 << ( 18 + 4 * regnum
) );
88 dr7
|= bp
->len
<< ( 18 + 4 * regnum
);
90 /* Set/clear local enable bit */
91 dr7
&= ~( 0x3 << 2 * regnum
);
92 dr7
|= bp
->enabled
<< 2 * regnum
;
95 int gdbmach_set_breakpoint ( int type
, unsigned long addr
, size_t len
, int enable
) {
98 /* Check and convert breakpoint type to x86 type */
107 return 0; /* unsupported breakpoint type */
110 /* Only lengths 1, 2, and 4 are supported */
111 if ( len
!= 2 && len
!= 4 ) {
114 len
--; /* convert to x86 breakpoint length bit pattern */
116 /* Calculate linear address by adding segment base */
119 /* Set up the breakpoint */
120 bp
= gdbmach_find_hwbp ( type
, addr
, len
);
122 return 0; /* ran out of hardware breakpoints */
127 bp
->enabled
= enable
;
128 gdbmach_commit_hwbp ( bp
);
132 static void gdbmach_disable_hwbps ( void ) {
133 /* Store and clear hardware breakpoints */
134 __asm__
__volatile__ ( "movl %0, %%dr7\n" : : "r" ( DR7_CLEAR
) );
137 static void gdbmach_enable_hwbps ( void ) {
138 /* Clear breakpoint status register */
139 __asm__
__volatile__ ( "movl %0, %%dr6\n" : : "r" ( DR6_CLEAR
) );
141 /* Restore hardware breakpoints */
142 __asm__
__volatile__ ( "movl %0, %%dr7\n" : : "r" ( dr7
) );
145 __asmcall
void gdbmach_handler ( int signo
, gdbreg_t
*regs
) {
146 gdbmach_disable_hwbps();
147 gdbstub_handler ( signo
, regs
);
148 gdbmach_enable_hwbps();