Subversion Repositories HelenOS-historic

Compare Revisions

Ignore whitespace Rev 1071 → Rev 1072

/kernel/trunk/kernel.config
70,6 → 70,9
# Deadlock detection support for spinlocks
! [CONFIG_DEBUG=y&CONFIG_SMP=y] CONFIG_DEBUG_SPINLOCK (y/n)
 
# Watchpoint on rewriting AS with zero
! [CONFIG_DEBUG=y&ARCH=amd64] CONFIG_DEBUG_AS_WATCHPOINT (y/n)
 
## Run-time configuration directives
 
# Kernel test type
/kernel/trunk/generic/include/ipc/ipc.h
176,6 → 176,7
extern void task_print_list(void);
 
extern answerbox_t *ipc_phone_0;
extern void ipc_cleanup(task_t *task);
 
#endif
 
/kernel/trunk/generic/include/ipc/ipcrsc.h
0,0 → 1,39
/*
* Copyright (C) 2006 Ondrej Palkovsky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
#ifndef __IPCRSC_H__
#define __IPCRSC_H__
 
call_t * get_call(__native callid);
phone_t * get_phone_and_lock(__native phoneid);
int phone_alloc(void);
void phone_dealloc(int phoneid);
void phone_connect(int phoneid, answerbox_t *box);
 
 
#endif
/kernel/trunk/generic/src/console/cmd.c
302,14 → 302,6
.argv = &zone_argv
};
 
static int cmd_hello(cmd_arg_t *argv);
static cmd_info_t hello_info = {
.name = "hello",
.description = "Hello Message",
.func = cmd_hello,
.argc = 0
};
 
/** Data and methods for 'cpus' command. */
static int cmd_cpus(cmd_arg_t *argv);
cmd_info_t cpus_info = {
352,7 → 344,6
&version_info,
&zones_info,
&zone_info,
&hello_info,
NULL
};
 
705,10 → 696,3
version_print();
return 1;
}
 
 
int cmd_hello(cmd_arg_t *argv)
{
printf("\nHello, World !!!\n");
return 1;
}
/kernel/trunk/generic/src/ipc/ipcrsc.c
0,0 → 1,117
/*
* Copyright (C) 2006 Ondrej Palkovsky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/* IPC resources management
*
* The goal of this source code is to properly manage IPC resources
* and allow straight and clean clean-up procedure upon task termination.
*
* The pattern of usage of the resources is:
* - allocate empty phone slot, connect | deallocate slot
* - disconnect connected phone (some messages might be on the fly)
* - find phone in slot and send a message using phone
* - answer message to phone
*
*
*/
 
#include <synch/spinlock.h>
#include <ipc/ipc.h>
#include <arch.h>
#include <proc/task.h>
#include <ipc/ipcrsc.h>
#include <debug.h>
 
/** Find call_t * in call table according to callid
*
* @return NULL on not found, otherwise pointer to call structure
*/
call_t * get_call(__native callid)
{
/* TODO: Traverse list of dispatched calls and find one */
/* TODO: locking of call, ripping it from dispatched calls etc. */
return (call_t *) callid;
}
 
/** Return pointer to phone identified by phoneid or NULL if non-existent */
phone_t * get_phone_and_lock(__native phoneid)
{
phone_t *phone;
 
if (phoneid >= IPC_MAX_PHONES)
return NULL;
 
phone = &TASK->phones[phoneid];
spinlock_lock(&phone->lock);
if (!phone->callee) {
spinlock_unlock(&phone->lock);
return NULL;
}
return phone;
}
 
/** Allocate new phone slot in current TASK structure */
int phone_alloc(void)
{
int i;
 
spinlock_lock(&TASK->lock);
for (i=0; i < IPC_MAX_PHONES; i++) {
if (!TASK->phones[i].busy) {
TASK->phones[i].busy = 1;
break;
}
}
spinlock_unlock(&TASK->lock);
 
if (i >= IPC_MAX_PHONES)
return -1;
return i;
}
 
/** Disconnect phone */
void phone_dealloc(int phoneid)
{
spinlock_lock(&TASK->lock);
 
ASSERT(TASK->phones[phoneid].busy);
 
if (TASK->phones[phoneid].callee)
ipc_phone_destroy(&TASK->phones[phoneid]);
 
TASK->phones[phoneid].busy = 0;
spinlock_unlock(&TASK->lock);
}
 
void phone_connect(int phoneid, answerbox_t *box)
{
phone_t *phone = &TASK->phones[phoneid];
ipc_phone_connect(phone, box);
}
/kernel/trunk/generic/src/ipc/sysipc.c
35,6 → 35,7
#include <debug.h>
#include <ipc/ipc.h>
#include <ipc/sysipc.h>
#include <ipc/ipcrsc.h>
 
 
#include <print.h>
64,72 → 65,6
return 1;
}
 
/** Find call_t * in call table according to callid
*
* @return NULL on not found, otherwise pointer to call structure
*/
static inline call_t * get_call(__native callid)
{
/* TODO: Traverse list of dispatched calls and find one */
/* TODO: locking of call, ripping it from dispatched calls etc. */
return (call_t *) callid;
}
 
/** Return pointer to phone identified by phoneid or NULL if non-existent */
static phone_t * get_phone(__native phoneid)
{
phone_t *phone;
 
if (phoneid >= IPC_MAX_PHONES)
return NULL;
 
phone = &TASK->phones[phoneid];
if (!phone->callee)
return NULL;
return phone;
}
 
/** Allocate new phone slot in current TASK structure */
static int phone_alloc(void)
{
int i;
 
spinlock_lock(&TASK->lock);
for (i=0; i < IPC_MAX_PHONES; i++) {
if (!TASK->phones[i].busy) {
TASK->phones[i].busy = 1;
break;
}
}
spinlock_unlock(&TASK->lock);
 
if (i >= IPC_MAX_PHONES)
return -1;
return i;
}
 
/** Disconnect phone */
static void phone_dealloc(int phoneid)
{
spinlock_lock(&TASK->lock);
 
ASSERT(TASK->phones[phoneid].busy);
 
if (TASK->phones[phoneid].callee)
ipc_phone_destroy(&TASK->phones[phoneid]);
 
TASK->phones[phoneid].busy = 0;
spinlock_unlock(&TASK->lock);
}
 
static void phone_connect(int phoneid, answerbox_t *box)
{
phone_t *phone = &TASK->phones[phoneid];
ipc_phone_connect(phone, box);
}
 
/****************************************************/
/* Functions that preprocess answer before sending
* it to the recepient
212,13 → 147,13
call_t call;
phone_t *phone;
 
phone = get_phone(phoneid);
if (is_system_method(method))
return EPERM;
 
phone = get_phone_and_lock(phoneid);
if (!phone)
return ENOENT;
 
if (is_system_method(method))
return EPERM;
 
ipc_call_init(&call);
IPC_SET_METHOD(call.data, method);
IPC_SET_ARG1(call.data, arg1);
237,10 → 172,6
call_t call;
phone_t *phone;
 
phone = get_phone(phoneid);
if (!phone)
return ENOENT;
 
ipc_call_init(&call);
copy_from_uspace(&call.data, question, sizeof(call.data));
 
247,6 → 178,10
if (is_system_method(IPC_GET_METHOD(call.data)))
return EPERM;
phone = get_phone_and_lock(phoneid);
if (!phone)
return ENOENT;
 
ipc_call_sync(phone, &call);
 
copy_to_uspace(reply, &call.data, sizeof(call.data));
278,10 → 213,6
call_t *call;
phone_t *phone;
 
phone = get_phone(phoneid);
if (!phone)
return IPC_CALLRET_FATAL;
 
if (is_system_method(method))
return IPC_CALLRET_FATAL;
 
288,6 → 219,10
if (check_call_limit())
return IPC_CALLRET_TEMPORARY;
 
phone = get_phone_and_lock(phoneid);
if (!phone)
return IPC_CALLRET_FATAL;
 
call = ipc_call_alloc();
IPC_SET_METHOD(call->data, method);
IPC_SET_ARG1(call->data, arg1);
307,13 → 242,13
call_t *call;
phone_t *phone;
 
phone = get_phone(phoneid);
if (check_call_limit())
return IPC_CALLRET_TEMPORARY;
 
phone = get_phone_and_lock(phoneid);
if (!phone)
return IPC_CALLRET_FATAL;
 
if (check_call_limit())
return IPC_CALLRET_TEMPORARY;
 
call = ipc_call_alloc();
copy_from_uspace(&call->data, data, sizeof(call->data));
 
344,7 → 279,7
if (!call)
return ENOENT;
 
phone = get_phone(phoneid);
phone = get_phone_and_lock(phoneid);
if (!phone) {
IPC_SET_RETVAL(call->data, EFORWARD);
ipc_answer(&TASK->answerbox, call);
436,15 → 371,15
call_t call;
phone_t *phone;
 
phone = get_phone(phoneid);
if (!phone)
return ENOENT;
 
ipc_call_init(&call);
IPC_SET_METHOD(call.data, IPC_M_CONNECTTOME);
IPC_SET_ARG1(call.data, arg1);
IPC_SET_ARG2(call.data, arg2);
phone = get_phone_and_lock(phoneid);
if (!phone)
return ENOENT;
 
ipc_call_sync(phone, &call);
 
if (!IPC_GET_RETVAL(call.data) && taskid)
466,7 → 401,7
phone_t *phone;
int newphid;
 
phone = get_phone(phoneid);
phone = get_phone_and_lock(phoneid);
if (!phone)
return ENOENT;
 
/kernel/trunk/generic/src/ipc/ipc.c
243,3 → 243,13
0,
NULL, NULL, 0);
}
 
/** Cleans up all IPC communication of the given task
*
*
*/
void ipc_cleanup(task_t *task)
{
/* Cancel all calls in my dispatch queue */
}
/kernel/trunk/Makefile
69,6 → 69,9
ifeq ($(CONFIG_DEBUG_SPINLOCK),y)
DEFS += -DCONFIG_DEBUG_SPINLOCK
endif
ifeq ($(CONFIG_DEBUG_AS_WATCHPOINT),y)
DEFS += -DCONFIG_DEBUG_AS_WATCHPOINT
endif
ifeq ($(CONFIG_FPU_LAZY),y)
DEFS += -DCONFIG_FPU_LAZY
endif
135,7 → 138,8
generic/src/synch/waitq.c \
generic/src/smp/ipi.c \
generic/src/ipc/ipc.c \
generic/src/ipc/sysipc.c
generic/src/ipc/sysipc.c \
generic/src/ipc/ipcrsc.c
 
## Test sources
#
/kernel/trunk/arch/amd64/include/interrupt.h
53,6 → 53,7
#error Wrong definition of VECTOR_APIC_SPUR
#endif
 
#define VECTOR_DEBUG 1
#define VECTOR_PIC_SPUR (IVT_IRQBASE+IRQ_PIC_SPUR)
#define VECTOR_CLK (IVT_IRQBASE+IRQ_CLK)
#define VECTOR_KBD (IVT_IRQBASE+IRQ_KBD)
/kernel/trunk/arch/amd64/include/asm.h
141,56 → 141,6
return v;
}
 
/** Read CR0
*
* Return value in CR0
*
* @return Value read.
*/
static inline __u64 read_cr0(void)
{
__u64 v;
__asm__ volatile ("movq %%cr0,%0\n" : "=r" (v));
return v;
}
 
/** Read CR2
*
* Return value in CR2
*
* @return Value read.
*/
static inline __u64 read_cr2(void)
{
__u64 v;
__asm__ volatile ("movq %%cr2,%0\n" : "=r" (v));
return v;
}
 
/** Write CR3
*
* Write value to CR3.
*
* @param v Value to be written.
*/
static inline void write_cr3(__u64 v)
{
__asm__ volatile ("movq %0,%%cr3\n" : : "r" (v));
}
 
/** Read CR3
*
* Return value in CR3
*
* @return Value read.
*/
static inline __u64 read_cr3(void)
{
__u64 v;
__asm__ volatile ("movq %%cr3,%0" : "=r" (v));
return v;
}
 
/** Write to MSR */
static inline void write_msr(__u32 msr, __u64 value)
{
250,6 → 200,38
__asm__ volatile ("invlpg %0\n" :: "m" (*((__native *)addr)));
}
 
#define GEN_READ_REG(reg) static inline __native read_ ##reg (void) \
{ \
__native res; \
__asm__ volatile ("movq %%" #reg ", %0" : "=r" (res) ); \
return res; \
}
 
#define GEN_WRITE_REG(reg) static inline void write_ ##reg (__native regn) \
{ \
__asm__ volatile ("movq %0, %%" #reg : : "r" (regn)); \
}
 
GEN_READ_REG(cr0);
GEN_READ_REG(cr2);
GEN_READ_REG(cr3);
GEN_WRITE_REG(cr3);
 
GEN_READ_REG(dr0);
GEN_READ_REG(dr1);
GEN_READ_REG(dr2);
GEN_READ_REG(dr3);
GEN_READ_REG(dr6);
GEN_READ_REG(dr7);
 
GEN_WRITE_REG(dr0);
GEN_WRITE_REG(dr1);
GEN_WRITE_REG(dr2);
GEN_WRITE_REG(dr3);
GEN_WRITE_REG(dr6);
GEN_WRITE_REG(dr7);
 
 
extern size_t interrupt_handler_size;
extern void interrupt_handlers(void);
 
/kernel/trunk/arch/amd64/include/debugger.h
0,0 → 1,48
/*
* Copyright (C) 2006 Ondrej Palkovsky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
#ifndef __amd64_DEBUGGER_H__
#define __amd64_DEBUGGER_H__
 
#include <arch/types.h>
 
#define BKPOINTS_MAX 4
 
/* Flags that are passed to breakpoint_add function */
#define BKPOINT_INSTR 0x1
#define BKPOINT_WRITE 0x2
#define BKPOINT_READ_WRITE 0x4
 
#define BKPOINT_CHECK_ZERO 0x8
 
 
extern void debugger_init(void);
extern int breakpoint_add(void * where, int flags);
extern void breakpoint_del(int slot);
 
#endif
/kernel/trunk/arch/amd64/include/cpu.h
29,6 → 29,7
#ifndef __amd64_CPU_H__
#define __amd64_CPU_H__
 
#define RFLAGS_RF (1 << 16)
 
#define EFER_MSR_NUM 0xc0000080
#define AMD_SCE_FLAG 0
/kernel/trunk/arch/amd64/Makefile.inc
103,7 → 103,8
arch/$(ARCH)/src/cpu/cpu.c \
arch/$(ARCH)/src/proc/scheduler.c \
arch/$(ARCH)/src/userspace.c \
arch/$(ARCH)/src/syscall.c
arch/$(ARCH)/src/syscall.c \
arch/$(ARCH)/src/debugger.c
 
ifeq ($(CONFIG_SMP),y)
ARCH_SOURCES += \
/kernel/trunk/arch/amd64/src/amd64.c
46,6 → 46,7
#include <panic.h>
#include <interrupt.h>
#include <arch/syscall.h>
#include <arch/debugger.h>
 
/** Disable I/O on non-privileged levels
*
129,10 → 130,12
{
if (config.cpu_active == 1) {
ega_init(); /* video */
/* Enable debugger */
debugger_init();
}
/* Setup fast SYSCALL/SYSRET */
syscall_setup_cpu();
 
}
 
void arch_pre_smp_init(void)
/kernel/trunk/arch/amd64/src/proc/scheduler.c
32,6 → 32,7
#include <arch.h>
#include <arch/context.h> /* SP_DELTA */
#include <arch/asm.h>
#include <arch/debugger.h>
 
void before_thread_runs_arch(void)
{
42,6 → 43,16
write_msr(AMD_MSR_GS,
(__u64)&THREAD->kstack);
swapgs();
 
 
#ifdef CONFIG_DEBUG_AS_WATCHPOINT
/* Set watchpoint on AS to ensure that nobody sets it to zero */
static int old_slot = -1;
if (old_slot >=0)
breakpoint_del(old_slot);
old_slot = breakpoint_add(&((the_t *) THREAD->kstack)->as,
BKPOINT_WRITE | BKPOINT_CHECK_ZERO);
#endif
}
 
void after_thread_ran_arch(void)
/kernel/trunk/arch/amd64/src/debugger.c
0,0 → 1,318
/*
* Copyright (C) 2006 Ondrej Palkovsky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
#include <arch/debugger.h>
#include <console/kconsole.h>
#include <console/cmd.h>
#include <symtab.h>
#include <print.h>
#include <panic.h>
#include <interrupt.h>
#include <arch/asm.h>
#include <arch/cpu.h>
#include <debug.h>
#include <func.h>
 
typedef struct {
__address address; /**< Breakpoint address */
int flags; /**< Flags regarding breakpoint */
int counter; /**< How many times the exception occured */
} bpinfo_t;
 
static bpinfo_t breakpoints[BKPOINTS_MAX];
SPINLOCK_INITIALIZE(bkpoint_lock);
 
static int cmd_print_breakpoints(cmd_arg_t *argv);
static cmd_info_t bkpts_info = {
.name = "bkpts",
.description = "Print breakpoint table.",
.func = cmd_print_breakpoints,
.argc = 0,
};
 
static int cmd_del_breakpoint(cmd_arg_t *argv);
static cmd_arg_t del_argv = {
.type = ARG_TYPE_INT
};
static cmd_info_t delbkpt_info = {
.name = "delbkpt",
.description = "delbkpt <number> - Delete breakpoint.",
.func = cmd_del_breakpoint,
.argc = 1,
.argv = &del_argv
};
 
static int cmd_add_breakpoint(cmd_arg_t *argv);
static cmd_arg_t add_argv = {
.type = ARG_TYPE_INT
};
static cmd_info_t addbkpt_info = {
.name = "addbkpt",
.description = "addbkpt <&symbol> - new breakpoint.",
.func = cmd_add_breakpoint,
.argc = 1,
.argv = &add_argv
};
 
static cmd_arg_t addw_argv = {
.type = ARG_TYPE_INT
};
static cmd_info_t addwatchp_info = {
.name = "addwatchp",
.description = "addbwatchp <&symbol> - new write watchpoint.",
.func = cmd_add_breakpoint,
.argc = 1,
.argv = &addw_argv
};
 
 
/** Print table of active breakpoints */
int cmd_print_breakpoints(cmd_arg_t *argv)
{
int i;
char *symbol;
 
printf("Breakpoint table.\n");
for (i=0; i < BKPOINTS_MAX; i++)
if (breakpoints[i].address) {
symbol = get_symtab_entry(breakpoints[i].address);
printf("%d. 0x%p in %s\n",i,
breakpoints[i].address, symbol);
printf(" Count(%d) ", breakpoints[i].counter);
printf("\n");
}
return 1;
}
 
/** Enable hardware breakpoint
*
*
* @param where Address of HW breakpoint
* @param flags Type of breakpoint (EXECUTE, WRITE)
* @return Debug slot on success, -1 - no available HW breakpoint
*/
int breakpoint_add(void * where, int flags)
{
bpinfo_t *cur = NULL;
int curidx;
ipl_t ipl;
int i;
__native dr7;
 
ASSERT( flags & (BKPOINT_INSTR | BKPOINT_WRITE | BKPOINT_READ_WRITE));
 
ipl = interrupts_disable();
spinlock_lock(&bkpoint_lock);
/* Find free space in slots */
for (i=0; i<BKPOINTS_MAX; i++)
if (!breakpoints[i].address) {
cur = &breakpoints[i];
curidx = i;
break;
}
if (!cur) {
/* Too many breakpoints */
spinlock_unlock(&bkpoint_lock);
interrupts_restore(ipl);
return -1;
}
cur->address = (__address) where;
cur->flags = flags;
cur->counter = 0;
 
/* Set breakpoint to debug registers */
switch (curidx) {
case 0:
write_dr0(cur->address);
break;
case 1:
write_dr1(cur->address);
break;
case 2:
write_dr2(cur->address);
break;
case 3:
write_dr3(cur->address);
break;
}
dr7 = read_dr7();
/* Set type to requested breakpoint & length*/
dr7 &= ~ (0x3 << (16 + 4*curidx));
dr7 &= ~ (0x3 << (18 + 4*curidx));
if ((flags & BKPOINT_INSTR)) {
printf("Instr breakpoint\n");
;
} else {
if (sizeof(int) == 4)
dr7 |= 0x3 << (18 + 4*curidx);
else /* 8 */
dr7 |= 0x2 << (18 + 4*curidx);
if ((flags & BKPOINT_WRITE))
dr7 |= 0x1 << (16 + 4*curidx);
else if ((flags & BKPOINT_READ_WRITE))
dr7 |= 0x3 << (16 + 4*curidx);
}
 
/* Enable global breakpoint */
dr7 |= 0x2 << (curidx*2);
 
write_dr7(dr7);
 
spinlock_unlock(&bkpoint_lock);
interrupts_restore(ipl);
 
return curidx;
}
 
static void handle_exception(int slot, istate_t *istate)
{
ASSERT(breakpoints[slot].address);
 
/* Handle zero checker */
if (! (breakpoints[slot].flags & BKPOINT_INSTR)) {
if ((breakpoints[slot].flags & BKPOINT_CHECK_ZERO)) {
if (*((__native *) breakpoints[slot].address) != 0)
return;
printf("**** Found ZERO on address %P ****\n",
slot, breakpoints[slot].address);
} else {
printf("Data watchpoint - new data: %P\n",
*((__native *) breakpoints[slot].address));
}
}
printf("Reached breakpoint %d:%P(%s)\n", slot, istate->rip,
get_symtab_entry(istate->rip));
printf("***Type 'exit' to exit kconsole.\n");
atomic_set(&haltstate,1);
kconsole("debug");
atomic_set(&haltstate,0);
}
 
static void debug_exception(int n, istate_t *istate)
{
__native dr6;
int i;
/* Set RF to restart the instruction */
istate->rflags |= RFLAGS_RF;
 
dr6 = read_dr6();
for (i=0; i < BKPOINTS_MAX; i++) {
if (dr6 & (1 << i)) {
dr6 &= ~ (1 << i);
write_dr6(dr6);
handle_exception(i, istate);
}
}
}
 
void breakpoint_del(int slot)
{
bpinfo_t *cur;
ipl_t ipl;
__native dr7;
 
ipl = interrupts_disable();
spinlock_lock(&bkpoint_lock);
 
cur = &breakpoints[slot];
if (!cur->address) {
spinlock_unlock(&bkpoint_lock);
interrupts_restore(ipl);
return;
}
 
cur->address = NULL;
 
/* Disable breakpoint in DR7 */
dr7 = read_dr7();
dr7 &= ~(0x2 << (slot*2));
write_dr7(dr7);
 
spinlock_unlock(&bkpoint_lock);
interrupts_restore(ipl);
}
 
/** Remove breakpoint from table */
int cmd_del_breakpoint(cmd_arg_t *argv)
{
if (argv->intval < 0 || argv->intval > BKPOINTS_MAX) {
printf("Invalid breakpoint number.\n");
return 0;
}
breakpoint_del(argv->intval);
return 1;
}
 
/** Add new breakpoint to table */
static int cmd_add_breakpoint(cmd_arg_t *argv)
{
int flags;
 
if (argv == &add_argv) {
flags = BKPOINT_INSTR;
} else { /* addwatchp */
flags = BKPOINT_WRITE;
}
printf("Adding breakpoint on address: %p\n", argv->intval);
if (breakpoint_add((void *)argv->intval, flags))
printf("Add breakpoint failed.\n");
return 1;
}
 
/** Initialize debugger */
void debugger_init()
{
int i;
 
for (i=0; i<BKPOINTS_MAX; i++)
breakpoints[i].address = NULL;
cmd_initialize(&bkpts_info);
if (!cmd_register(&bkpts_info))
panic("could not register command %s\n", bkpts_info.name);
 
cmd_initialize(&delbkpt_info);
if (!cmd_register(&delbkpt_info))
panic("could not register command %s\n", delbkpt_info.name);
 
cmd_initialize(&addbkpt_info);
if (!cmd_register(&addbkpt_info))
panic("could not register command %s\n", addbkpt_info.name);
 
cmd_initialize(&addwatchp_info);
if (!cmd_register(&addwatchp_info))
panic("could not register command %s\n", addwatchp_info.name);
exc_register(VECTOR_DEBUG, "debugger",
debug_exception);
}