diff --git a/commands/i386/gas2ack/asm86.c b/commands/i386/gas2ack/asm86.c index 29c5b7ba9..adde7c531 100644 --- a/commands/i386/gas2ack/asm86.c +++ b/commands/i386/gas2ack/asm86.c @@ -75,6 +75,7 @@ int isregister(const char *name) "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp", "cs", "ds", "es", "fs", "gs", "ss", "cr0", "cr1", "cr2", "cr3", "cr4", + "dr0", "dr1", "dr2", "dr3", "dr6", "dr7", "st", }; int reg; diff --git a/commands/i386/gas2ack/gas2ack.c b/commands/i386/gas2ack/gas2ack.c index 2b6088d16..f1dfc2c5f 100644 --- a/commands/i386/gas2ack/gas2ack.c +++ b/commands/i386/gas2ack/gas2ack.c @@ -1,7 +1,7 @@ -/* asmconv 1.11 - convert 80X86 assembly Author: Kees J. Bot +/* asmconv 1.12 - convert 80X86 assembly Author: Kees J. Bot * 24 Dec 1993 */ -static char version[] = "1.11"; +static char version[] = "1.12"; #define nil 0 #include diff --git a/docs/UPDATING b/docs/UPDATING index 872fe1525..31848400f 100644 --- a/docs/UPDATING +++ b/docs/UPDATING @@ -70,4 +70,6 @@ The hello driver (/dev/hello) added to the distribution: # cd /usr/src/commands/scripts && make clean install # cd /dev && MAKEDEV hello +20100318: + Gas2ack updates: Run 'make install' in commands/i386/gas2ack diff --git a/kernel/arch/i386/Makefile b/kernel/arch/i386/Makefile index 69eb76017..d4a10b566 100644 --- a/kernel/arch/i386/Makefile +++ b/kernel/arch/i386/Makefile @@ -9,7 +9,9 @@ ARCHAR=$(ARCH).a # by an upper level Makefile. OBJS= arch_do_vmctl.o \ + breakpoints.o \ clock.o \ + debugreg.o \ do_int86.o \ do_iopenable.o \ do_readbios.o \ @@ -56,6 +58,11 @@ apic_asm.o: apic_asm.S gas2ack -u $@.tmp $@.s $(CC) $(CFLAGS) -c -o $@ $@.s +debugreg.o: debugreg.S + $(CC) $(CFLAGS) -E -D__ASSEMBLY__ -o $@.tmp $< + gas2ack -u $@.tmp $@.s + $(CC) $(CFLAGS) -c -o $@ $@.s + $(HEAD): mpx386.o cp $< $@ diff --git a/kernel/arch/i386/breakpoints.c b/kernel/arch/i386/breakpoints.c new file mode 100644 index 000000000..0e9d40785 --- /dev/null +++ b/kernel/arch/i386/breakpoints.c @@ -0,0 +1,60 @@ +#include "../../kernel.h" +#include "proto.h" + +#include "debugreg.h" + +int breakpoint_set(phys_bytes linaddr, int bp, int flags) +{ + u32_t dr7, dr7flags; + + if (bp >= BREAKPOINT_COUNT) + return EINVAL; + + /* convert flags */ + dr7flags = 0; + switch (flags & BREAKPOINT_FLAG_RW_MASK) { + case BREAKPOINT_FLAG_RW_EXEC: dr7flags |= DR7_RW_EXEC(bp); break; + case BREAKPOINT_FLAG_RW_WRITE: dr7flags |= DR7_RW_WRITE(bp); break; + case BREAKPOINT_FLAG_RW_RW: dr7flags |= DR7_RW_RW(bp); break; + default: return EINVAL; + } + switch (flags & BREAKPOINT_FLAG_LEN_MASK) { + case BREAKPOINT_FLAG_LEN_1: dr7flags |= DR7_LN_1(bp); break; + case BREAKPOINT_FLAG_LEN_2: dr7flags |= DR7_LN_2(bp); break; + case BREAKPOINT_FLAG_LEN_4: dr7flags |= DR7_LN_4(bp); break; + default: return EINVAL; + } + switch (flags & BREAKPOINT_FLAG_MODE_MASK) { + case BREAKPOINT_FLAG_MODE_OFF: break; + case BREAKPOINT_FLAG_MODE_LOCAL: dr7flags |= DR7_L(bp); break; + case BREAKPOINT_FLAG_MODE_GLOBAL: dr7flags |= DR7_G(bp); break; + default: return EINVAL; + } + + /* disable breakpoint before setting address */ + dr7 = st_dr7(); + dr7 &= ~(DR7_L(bp) | DR7_G(bp) | DR7_RW_MASK(bp) | DR7_LN_MASK(bp)); +printf("ld_dr7(0x%x)\n",dr7); + ld_dr7(dr7); + + /* need to set new breakpoint? */ + if ((flags & BREAKPOINT_FLAG_MODE_MASK) == BREAKPOINT_FLAG_MODE_OFF) + return 0; + + /* set breakpoint address */ + switch (bp) { + case 0: ld_dr0(linaddr); break; + case 1: ld_dr1(linaddr); break; + case 2: ld_dr2(linaddr); break; + case 3: ld_dr3(linaddr); break; + default: panic(__FILE__, "invalid breakpoint index", __LINE__); + } +printf("ld_dr%d(0x%x, 0x%x)\n",bp,linaddr); + + /* set new flags */ + dr7 |= dr7flags; + ld_dr7(dr7); +printf("ld_dr7(0x%x)\n",dr7); + return 0; +} + diff --git a/kernel/arch/i386/debugreg.S b/kernel/arch/i386/debugreg.S new file mode 100644 index 000000000..9d60c5bc0 --- /dev/null +++ b/kernel/arch/i386/debugreg.S @@ -0,0 +1,26 @@ +.text + +#define LD_ST_REG(reg) ;\ +.globl ld_##reg ;\ +.globl st_##reg ;\ + ;\ +ld_##reg: ;\ + mov 4(%esp), %eax ;\ + mov %eax, %reg ;\ + ret ;\ + ;\ +st_##reg: ;\ + mov %reg, %eax ;\ + ret + +/* + * void ld_dr0(u32_t value) + * u32_t st_dr0(void) + */ +LD_ST_REG(dr0) +LD_ST_REG(dr1) +LD_ST_REG(dr2) +LD_ST_REG(dr3) +LD_ST_REG(dr6) +LD_ST_REG(dr7) + diff --git a/kernel/arch/i386/debugreg.h b/kernel/arch/i386/debugreg.h new file mode 100644 index 000000000..8590fea5a --- /dev/null +++ b/kernel/arch/i386/debugreg.h @@ -0,0 +1,44 @@ +#ifndef __DEBUGREG_H__ +#define __DEBUGREG_H__ + +/* DR6: status flags */ +#define DR6_B(bp) (1 << (bp)) /* breakpoint was triggered */ +#define DR6_BD (1 << 13) /* debug register access detected */ +#define DR6_BS (1 << 14) /* single step */ +#define DR6_BT (1 << 15) /* task switch */ + +/* DR7: control flags */ +#define DR7_L(bp) (1 << (2*(bp))) /* breakpoint armed locally */ +#define DR7_G(bp) (1 << (1+2*(bp))) /* breakpoint armed globally */ +#define DR7_LE (1 << 8) /* exact local breakpoints */ +#define DR7_GE (1 << 9) /* exact global breakpoints */ +#define DR7_GD (1 << 13) /* detect debug reg movs */ + +#define DR7_RW_MASK(bp) (3 << (16+4*(bp))) +#define DR7_RW_EXEC(bp) (0 << (16+4*(bp))) /* execute */ +#define DR7_RW_WRITE(bp) (1 << (16+4*(bp))) /* write */ +#define DR7_RW_IO(bp) (2 << (16+4*(bp))) /* IO */ +#define DR7_RW_RW(bp) (3 << (16+4*(bp))) /* read or write */ + +#define DR7_LN_MASK(bp) (3 << (18+4*(bp))) +#define DR7_LN_1(bp) (0 << (18+4*(bp))) /* 1 byte */ +#define DR7_LN_2(bp) (1 << (18+4*(bp))) /* 2 bytes */ +#define DR7_LN_8(bp) (2 << (18+4*(bp))) /* 8 bytes */ +#define DR7_LN_4(bp) (3 << (18+4*(bp))) /* 4 bytes */ + +/* debugreg.S */ +void ld_dr0(u32_t value); +void ld_dr1(u32_t value); +void ld_dr2(u32_t value); +void ld_dr3(u32_t value); +void ld_dr6(u32_t value); +void ld_dr7(u32_t value); +u32_t st_dr0(void); +u32_t st_dr1(void); +u32_t st_dr2(void); +u32_t st_dr3(void); +u32_t st_dr6(void); +u32_t st_dr7(void); + +#endif /* __DEBUGREG_H__ */ + diff --git a/kernel/arch/i386/proto.h b/kernel/arch/i386/proto.h index b6f00631c..5e7c55f3d 100644 --- a/kernel/arch/i386/proto.h +++ b/kernel/arch/i386/proto.h @@ -156,6 +156,23 @@ _PROTOTYPE(void __copy_msg_from_user_end, (void)); _PROTOTYPE(void __copy_msg_to_user_end, (void)); _PROTOTYPE(void __user_copy_msg_pointer_failure, (void)); +/* breakpoints.c */ +#define BREAKPOINT_COUNT 4 +#define BREAKPOINT_FLAG_RW_MASK (3 << 0) +#define BREAKPOINT_FLAG_RW_EXEC (0 << 0) +#define BREAKPOINT_FLAG_RW_WRITE (1 << 0) +#define BREAKPOINT_FLAG_RW_RW (2 << 0) +#define BREAKPOINT_FLAG_LEN_MASK (3 << 2) +#define BREAKPOINT_FLAG_LEN_1 (0 << 2) +#define BREAKPOINT_FLAG_LEN_2 (1 << 2) +#define BREAKPOINT_FLAG_LEN_4 (2 << 2) +#define BREAKPOINT_FLAG_MODE_MASK (3 << 4) +#define BREAKPOINT_FLAG_MODE_OFF (0 << 4) +#define BREAKPOINT_FLAG_MODE_LOCAL (1 << 4) +#define BREAKPOINT_FLAG_MODE_GLOBAL (2 << 4) + +_PROTOTYPE(int breakpoint_set, (phys_bytes linaddr, int index, int flags)); + /* functions defined in architecture-independent kernel source. */ #include "../../proto.h"