[contrib] Allow Network Protocol header to display in rom-o-matic
[gpxe.git] / src / arch / i386 / core / gdbmach.c
blob97827ecbc49bc48bd5b92ffc3e4ce91707a798bd
1 /*
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.
19 #include <stddef.h>
20 #include <stdio.h>
21 #include <assert.h>
22 #include <gpxe/uaccess.h>
23 #include <gpxe/gdbstub.h>
24 #include <gdbmach.h>
26 /** @file
28 * GDB architecture-specific bits for i386
32 enum {
33 DR7_CLEAR = 0x00000400, /* disable hardware breakpoints */
34 DR6_CLEAR = 0xffff0ff0, /* clear breakpoint status */
37 /** Hardware breakpoint, fields stored in x86 bit pattern form */
38 struct hwbp {
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) */
42 int enabled;
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;
50 unsigned int i;
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 ) {
53 return &hwbps [ i ];
55 if ( !hwbps [ i ].enabled ) {
56 available = &hwbps [ i ];
59 return available;
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 ] ) );
67 switch ( regnum ) {
68 case 0:
69 __asm__ __volatile__ ( "movl %0, %%dr0\n" : : "r" ( bp->addr ) );
70 break;
71 case 1:
72 __asm__ __volatile__ ( "movl %0, %%dr1\n" : : "r" ( bp->addr ) );
73 break;
74 case 2:
75 __asm__ __volatile__ ( "movl %0, %%dr2\n" : : "r" ( bp->addr ) );
76 break;
77 case 3:
78 __asm__ __volatile__ ( "movl %0, %%dr3\n" : : "r" ( bp->addr ) );
79 break;
82 /* Set type */
83 dr7 &= ~( 0x3 << ( 16 + 4 * regnum ) );
84 dr7 |= bp->type << ( 16 + 4 * regnum );
86 /* Set length */
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 ) {
96 struct hwbp *bp;
98 /* Check and convert breakpoint type to x86 type */
99 switch ( type ) {
100 case GDBMACH_WATCH:
101 type = 0x1;
102 break;
103 case GDBMACH_AWATCH:
104 type = 0x3;
105 break;
106 default:
107 return 0; /* unsupported breakpoint type */
110 /* Only lengths 1, 2, and 4 are supported */
111 if ( len != 2 && len != 4 ) {
112 len = 1;
114 len--; /* convert to x86 breakpoint length bit pattern */
116 /* Calculate linear address by adding segment base */
117 addr += virt_offset;
119 /* Set up the breakpoint */
120 bp = gdbmach_find_hwbp ( type, addr, len );
121 if ( !bp ) {
122 return 0; /* ran out of hardware breakpoints */
124 bp->type = type;
125 bp->addr = addr;
126 bp->len = len;
127 bp->enabled = enable;
128 gdbmach_commit_hwbp ( bp );
129 return 1;
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();