📄 i386_stub.c
字号:
/* i386_stub.c - helper functions for stub, generic to all i386 processors
*
* Copyright (c) 1998,1999, 2001 Cygnus Solutions
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice is included verbatim in any distributions. No written agreement,
* license, or royalty fee is required for any of the authorized uses.
* Modifications to this software may be copyrighted by their authors
* and need not follow the licensing terms described here, provided that
* the new terms are clearly indicated on the first page of each file where
* they apply.
*/
/*
- pjo, 29 sep 1999
- Copied from the ARM configuration and merged with an older GDB i386-stub.c.
*/
#include <stddef.h>
#include <pkgconf/hal.h>
#ifdef CYGPKG_REDBOOT
#include <pkgconf/redboot.h>
#endif
#ifdef CYGPKG_HAL_I386_SIM
#error "GDB Stub support not implemented for i386 SIM"
#endif
#include <cyg/hal/hal_stub.h>
#include <cyg/hal/hal_arch.h>
#include <cyg/hal/hal_intr.h>
#include <cyg/hal/i386_stub.h>
#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif
#ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
#include <cyg/hal/dbg-threads-api.h> // dbg_currthread_id
#endif
// We need a local memcpy so we don't rely on libc.
static inline void*
local_memcpy(void* dest, void* src, size_t size)
{
unsigned char* __d = (unsigned char*) dest;
unsigned char* __s = (unsigned char*) src;
while(size--)
*__d++ = *__s++;
return dest;
}
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
/* Given a trap value TRAP, return the corresponding signal. */
int __computeSignal (unsigned int trap_number)
{
switch (trap_number)
{
case CYGNUM_HAL_VECTOR_DIV0:
/* This isn't quite accurrate: this is integer division only. */
return SIGFPE ;
case CYGNUM_HAL_VECTOR_DEBUG:
return SIGTRAP ;
case CYGNUM_HAL_VECTOR_NMI:
return SIGINT ;
case CYGNUM_HAL_VECTOR_BREAKPOINT:
return SIGTRAP ;
case CYGNUM_HAL_VECTOR_OVERFLOW:
case CYGNUM_HAL_VECTOR_BOUND:
return SIGSEGV ;
case CYGNUM_HAL_VECTOR_OPCODE:
return SIGILL ;
case CYGNUM_HAL_VECTOR_NO_DEVICE:
case CYGNUM_HAL_VECTOR_FPE:
return SIGFPE ;
case CYGNUM_HAL_VECTOR_DOUBLE_FAULT:
return SIGTRAP ;
case CYGNUM_HAL_VECTOR_INVALID_TSS:
case CYGNUM_HAL_VECTOR_SEGV:
case CYGNUM_HAL_VECTOR_STACK_FAULT:
case CYGNUM_HAL_VECTOR_PROTECTION:
case CYGNUM_HAL_VECTOR_PAGE:
case CYGNUM_HAL_VECTOR_ALIGNMENT:
return SIGSEGV ;
default:
return SIGTRAP;
}
}
/* Return the trap number corresponding to the last-taken trap. */
int __get_trap_number (void)
{
#if 1
// The vector is not not part of the GDB register set so get it
// directly from the HAL saved context.
return _hal_registers->vector;
#else
extern int hal_pc_trap_number ;
// The vector is not not part of the GDB register set so get it
// directly from the save context.
return hal_pc_trap_number ;
#endif
}
#if defined(CYGSEM_REDBOOT_BSP_SYSCALLS)
int __is_bsp_syscall(void)
{
return __get_trap_number() == 0x80;
}
#endif
/* Set the currently-saved pc register value to PC. */
void set_pc (target_register_t pc)
{
put_register (PC, pc);
}
static target_register_t
reg_offset(regnames_t reg)
{
switch(reg) {
case EAX ... GS:
return reg * 4;
#ifdef CYGHWR_HAL_I386_FPU
case REG_FST0 ... REG_FST7:
return (target_register_t)&((GDB_SavedRegisters *)0)->st0[0]
+ ((reg - REG_FST0) * 10);
case REG_FCTRL:
return (target_register_t)&((GDB_SavedRegisters *)0)->fcw;
case REG_FSTAT:
return (target_register_t)&((GDB_SavedRegisters *)0)->fsw;
case REG_FTAG:
return (target_register_t)&((GDB_SavedRegisters *)0)->ftw;
case REG_FISEG:
case REG_FOP:
// REG_FISEG is lsw, REG_FOP is msw
return (target_register_t)&((GDB_SavedRegisters *)0)->cssel;
case REG_FIOFF:
return (target_register_t)&((GDB_SavedRegisters *)0)->ipoff;
case REG_FOSEG:
return (target_register_t)&((GDB_SavedRegisters *)0)->opsel;
case REG_FOOFF:
return (target_register_t)&((GDB_SavedRegisters *)0)->dataoff;
#endif
#if 0 // GDB never asks for MMX regs directly, but it did...
case REG_MMX0 ... REG_MMX7:
{
target_register_t tos = (get_register (REG_FSTAT) >> 11) & 7;
return reg_offset((((8 - tos) + reg - REG_MMX0) & 7) + REG_FST0);
}
#endif
#ifdef CYGHWR_HAL_I386_PENTIUM_SSE
case REG_XMM0 ... REG_XMM7:
return (target_register_t)&((GDB_SavedRegisters *)0)->xmm0[0]
+ ((reg - REG_XMM0) * 16);
case REG_MXCSR:
return (target_register_t)&((GDB_SavedRegisters *)0)->mxcsr;
#endif
#ifdef CYGHWR_HAL_I386_PENTIUM_GDB_REGS
case REG_CR0 ... REG_CR4:
return (target_register_t)&((GDB_SavedRegisters *)0)->cr0
+ ((reg - REG_CR0) * 4);
case REG_GDT:
return (target_register_t)&((GDB_SavedRegisters *)0)->gdtr[0];
case REG_IDT:
return (target_register_t)&((GDB_SavedRegisters *)0)->idtr[0];
#endif
default:
return -1;
}
return -1;
}
// Return the currently-saved value corresponding to register REG of
// the exception context.
target_register_t
get_register (regnames_t reg)
{
target_register_t val;
target_register_t offset = reg_offset(reg);
if (REGSIZE(reg) > sizeof(target_register_t) || offset == -1)
return -1;
val = _registers[offset/sizeof(target_register_t)];
#ifdef CYGHWR_HAL_I386_FPU
if (reg == REG_FISEG)
val &= 0xffff;
else if (reg == REG_FOP)
val = (val >> 16) & 0xffff;
#endif
return val;
}
// Store VALUE in the register corresponding to WHICH in the exception
// context.
void
put_register (regnames_t which, target_register_t value)
{
target_register_t index;
target_register_t offset = reg_offset(which);
if (REGSIZE(which) > sizeof(target_register_t) || offset == -1)
return;
index = offset / sizeof(target_register_t);
switch (which) {
#ifdef CYGHWR_HAL_I386_FPU
case REG_FISEG:
value = (_registers[index] & 0xffff0000) | (value & 0xffff);
break;
case REG_FOP:
value = (_registers[index] & 0x0000ffff) | (value << 16);
break;
#endif
#ifdef CYGHWR_HAL_I386_PENTIUM_GDB_REGS
case REG_CR0:
value &= REG_CR0_MASK;
break;
case REG_CR2:
value &= REG_CR2_MASK;
break;
case REG_CR3:
value &= REG_CR3_MASK;
break;
case REG_CR4:
value &= REG_CR4_MASK;
break;
#endif
default:
break;
}
_registers[index] = value;
}
#ifdef CYGHWR_HAL_I386_PENTIUM_GDB_REGS
// Handle the Model Specific Registers
static target_register_t _msrval[2];
static int _which_msr = 0;
static int _dummy_flag = 0;
extern void * volatile __mem_fault_handler;
static void
__do_read_msr (void)
{
// _dummy_flag is always false but the goto is necessary to keep
// some compilers from reordering stuff across the 'err' label.
if (_dummy_flag)
goto err;
__mem_fault = 1; // Defaults to 'fail'. Is cleared
// when the wrmsr completes.
__mem_fault_handler = &&err;
asm volatile ("movl %2,%%ecx\n"
"rdmsr\n"
"movl %%edx,%1\n"
"movl %%eax,%0\n"
: "=m" (_msrval[0]), "=m" (_msrval[1])
: "m" (_which_msr)
: "ecx", "ebx", "edx", "eax", "memory");
__mem_fault = 0;
err:
__mem_fault_handler = (void *)0;
}
static void
__do_write_msr (void)
{
// _dummy_flag is always false but the goto is necessary to keep
// some compilers from reordering stuff across the 'err' label.
if (_dummy_flag)
goto err;
__mem_fault = 1; // Defaults to 'fail'. Is cleared
// when the wrmsr completes.
__mem_fault_handler = &&err;
asm volatile ("movl %1,%%edx\n"
"movl %0,%%eax\n"
"movl %2,%%ecx\n"
"wrmsr\n"
: /* no outputs */
: "m" (_msrval[0]), "m" (_msrval[1]), "m" (_which_msr)
: "ecx", "ebx", "edx", "eax", "memory");
__mem_fault = 0;
err:
__mem_fault_handler = (void *)0;
}
static int
rdmsr (int msrnum, target_register_t *msrval)
{
_which_msr = msrnum;
__set_mem_fault_trap (__do_read_msr);
if (__mem_fault)
return 0;
msrval[0] = _msrval[0];
msrval[1] = _msrval[1];
return 1;
}
static int
wrmsr (int msrnum, target_register_t *msrval)
{
_which_msr = msrnum;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -