mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
320 lines
7.4 KiB
320 lines
7.4 KiB
/*[
|
|
|
|
ccpupig.c
|
|
|
|
LOCAL CHAR SccsID[]="@(#)ccpupig.c 1.22 04/11/95"
|
|
|
|
C CPU <-> Pigger Interface
|
|
--------------------------
|
|
|
|
]*/
|
|
|
|
#include <insignia.h>
|
|
#include <host_def.h>
|
|
|
|
#ifdef PIG
|
|
|
|
#include <xt.h>
|
|
#define CPU_PRIVATE
|
|
#include CpuH
|
|
#include <ccpupig.h>
|
|
#include <sas.h> /* need memory(M) */
|
|
#include <ccpusas4.h> /* the cpu internal sas bits */
|
|
#include <Cpu_c.h> /* Intel memory access macros */
|
|
|
|
#include <c_reg.h>
|
|
#include <c_xcptn.h>
|
|
#include <c_page.h>
|
|
|
|
#define DASM_PRIVATE
|
|
#include <dasm.h>
|
|
#include <decode.h>
|
|
|
|
#include <assert.h>
|
|
/*
|
|
* Interface between this cpu and other one being pigged
|
|
*/
|
|
GLOBAL enum pig_actions pig_cpu_action;
|
|
GLOBAL IBOOL ccpu_pig_enabled = FALSE;
|
|
|
|
/*
|
|
* Last Instruction memorizing...
|
|
*/
|
|
|
|
GLOBAL IU32 ccpu_synch_count = 1;
|
|
|
|
LOCAL struct ccpu_last_inst *inst_buffer;
|
|
LOCAL struct ccpu_last_inst *inst_ptr;
|
|
LOCAL struct ccpu_last_inst *inst_ptr_wrap;
|
|
LOCAL struct ccpu_last_inst *next_inst_ptr;
|
|
LOCAL struct ccpu_last_inst *inst_bytes_ptr;
|
|
LOCAL char prefetch_inst_buffer[200];
|
|
|
|
/*(
|
|
* Keep these last inst vars up to date...
|
|
)*/
|
|
|
|
GLOBAL VOID save_last_inst_details IFN1(char *, text)
|
|
{
|
|
inst_ptr->cs = GET_CS_SELECTOR();
|
|
inst_ptr->big_cs = GET_CS_AR_X() != 0;
|
|
inst_ptr->text = text;
|
|
/*
|
|
* getEIP() should be getInstructionPointer() but they
|
|
* are equivalent for the current CCPU.
|
|
*/
|
|
inst_ptr->eip = GET_EIP();
|
|
inst_bytes_ptr = inst_ptr;
|
|
inst_bytes_ptr->inst_len = 0;
|
|
|
|
inst_ptr->synch_count = ccpu_synch_count;
|
|
|
|
if (++inst_ptr >= inst_ptr_wrap)
|
|
inst_ptr = inst_buffer;
|
|
|
|
/* Invalidate the previous prefetch disassembly buffer */
|
|
prefetch_inst_buffer[0] = '\0';
|
|
}
|
|
|
|
/* This is called by the CCPU as it processes each instruction byte.
|
|
* The CCPU has already checked that the Intel instruction is not just
|
|
* an infinite sequence of prefixes, so we know it will fit.
|
|
*/
|
|
GLOBAL IU8 save_instruction_byte IFN1(IU8, byte)
|
|
{
|
|
int len = inst_bytes_ptr->inst_len++;
|
|
|
|
inst_bytes_ptr->bytes[len] = byte;
|
|
return (byte);
|
|
}
|
|
|
|
/* When an exception occurs, the CCPU will save the details in the last instruction
|
|
* history buffer. This requires a sprintf, and we use the code-bytes data area
|
|
* to keep this information.
|
|
* Up to 3 parameters can be in the format.
|
|
*/
|
|
GLOBAL VOID save_last_xcptn_details IFN6(char *, fmt, IUH, a1, IUH, a2, IUH, a3, IUH, a4, IUH, a5 )
|
|
{
|
|
char buffer[128];
|
|
|
|
inst_ptr->cs = getCS_SELECTOR();
|
|
inst_ptr->eip = getEIP();
|
|
inst_ptr->big_cs = 0;
|
|
inst_ptr->synch_count = ccpu_synch_count;
|
|
|
|
/* The default message is too long sometimes.
|
|
* We replace any leading "Exception:-" with "XCPT"
|
|
*/
|
|
|
|
if (strncmp(fmt, "Exception:-", 11) == 0)
|
|
{
|
|
strcpy(buffer, "XCPT");
|
|
sprintf(buffer + 4, fmt + 11, a1, a2, a3, a4, a5);
|
|
}
|
|
else
|
|
{
|
|
sprintf(buffer, fmt, a1, a2, a3, a4, a5);
|
|
}
|
|
|
|
if (strlen(buffer) >= sizeof(inst_ptr->bytes))
|
|
printf("warning: CCPU XCPTN text message below longer than buffer; truncating:\n -- %s\n", buffer);
|
|
|
|
strncpy(&inst_ptr->bytes[0], buffer, sizeof(inst_ptr->bytes) - 2);
|
|
|
|
inst_ptr->bytes[sizeof(inst_ptr->bytes) - 2] = '\n';
|
|
inst_ptr->bytes[sizeof(inst_ptr->bytes) - 1] = '\0';
|
|
|
|
inst_ptr->text = (char *)&inst_ptr->bytes[0];
|
|
|
|
if (++inst_ptr >= inst_ptr_wrap)
|
|
inst_ptr = inst_buffer;
|
|
|
|
/* Invalidate the previous prefetch disassembly buffer */
|
|
prefetch_inst_buffer[0] = '\0';
|
|
}
|
|
|
|
GLOBAL struct ccpu_last_inst *get_synch_inst_details IFN1(IU32, synch_point)
|
|
{
|
|
/* scan backwards through the buffer until the start of the relevant
|
|
* synch point block is found.
|
|
*/
|
|
IS32 n_entries = inst_ptr_wrap - inst_buffer;
|
|
|
|
next_inst_ptr = inst_ptr - 1;
|
|
|
|
if (next_inst_ptr < inst_buffer)
|
|
next_inst_ptr = inst_ptr_wrap - 1;
|
|
|
|
while (synch_point <= next_inst_ptr->synch_count)
|
|
{
|
|
if (--n_entries <= 0)
|
|
return (next_inst_ptr);
|
|
|
|
if (--next_inst_ptr < inst_buffer)
|
|
next_inst_ptr = inst_ptr_wrap - 1;
|
|
}
|
|
|
|
if (++next_inst_ptr >= inst_ptr_wrap)
|
|
next_inst_ptr = inst_buffer;
|
|
|
|
return (next_inst_ptr);
|
|
}
|
|
|
|
|
|
/* After a previous call to get_synch_inst_details(), get the next
|
|
* inst details. This call should be repeated until NULL is returned.
|
|
*/
|
|
GLOBAL struct ccpu_last_inst *get_next_inst_details IFN1(IU32, finish_synch_point)
|
|
{
|
|
if (next_inst_ptr)
|
|
{
|
|
if (++next_inst_ptr >= inst_ptr_wrap)
|
|
next_inst_ptr = inst_buffer;
|
|
|
|
if ((next_inst_ptr->synch_count == 0)
|
|
|| (next_inst_ptr == inst_ptr)
|
|
|| (next_inst_ptr->synch_count > finish_synch_point)
|
|
)
|
|
{
|
|
next_inst_ptr = (struct ccpu_last_inst *)0;
|
|
}
|
|
}
|
|
return next_inst_ptr;
|
|
}
|
|
|
|
|
|
GLOBAL VOID init_last_inst_details IFN0()
|
|
{
|
|
SAVED IBOOL first = TRUE;
|
|
|
|
if (first)
|
|
{
|
|
struct ccpu_last_inst *ptr;
|
|
ISM32 size = ISM32getenv("CCPU_HISTORY_SIZE", 256);
|
|
|
|
if (size < 100)
|
|
{
|
|
sprintf(prefetch_inst_buffer,
|
|
"CCPU_HISTORY_SIZE of %d is too small",
|
|
size);
|
|
FatalError(prefetch_inst_buffer);
|
|
}
|
|
ptr = (struct ccpu_last_inst *)host_malloc(size * sizeof(*ptr));
|
|
if (ptr == (struct ccpu_last_inst *)0)
|
|
{
|
|
sprintf(prefetch_inst_buffer,
|
|
"Unable to malloc memory for CCPU_HISTORY_SIZE of %d",
|
|
size);
|
|
FatalError(prefetch_inst_buffer);
|
|
}
|
|
inst_buffer = ptr;
|
|
inst_ptr_wrap = &inst_buffer[size];
|
|
first = FALSE;
|
|
}
|
|
|
|
memset(inst_buffer, 0, ((IHPE)inst_ptr_wrap - (IHPE)inst_buffer));
|
|
next_inst_ptr = (struct ccpu_last_inst *)0;
|
|
inst_ptr = inst_buffer;
|
|
}
|
|
|
|
|
|
/* When about to pig an interrupt we may need to mark the last
|
|
* basic block as "invalid" even though it has been executed by
|
|
* the CCPU.
|
|
*/
|
|
GLOBAL VOID save_last_interrupt_details IFN2(IU8, number, IBOOL, invalidateLastBlock)
|
|
{
|
|
if (invalidateLastBlock)
|
|
{
|
|
struct ccpu_last_inst *ptr;
|
|
IU32 synch_count = ccpu_synch_count - 1;
|
|
|
|
ptr = get_synch_inst_details(synch_count);
|
|
|
|
while (ptr != (struct ccpu_last_inst *)0)
|
|
{
|
|
ptr->text = "Intr: invalidated";
|
|
ptr = get_next_inst_details(synch_count);
|
|
}
|
|
}
|
|
save_last_xcptn_details("Intr: vector %02x", number, 0, 0, 0, 0);
|
|
}
|
|
|
|
|
|
LOCAL IBOOL reset_prefetch;
|
|
|
|
LOCAL IS32 prefetch_byte IFN1(LIN_ADDR, eip)
|
|
{
|
|
SAVED IU8 *ip_ptr;
|
|
SAVED IU8 *ip_ceiling;
|
|
SAVED LIN_ADDR last_eip;
|
|
IU8 b;
|
|
|
|
if (reset_prefetch
|
|
|| (eip != ++last_eip)
|
|
|| !BelowOrEqualCpuPtrsLS8(ip_ptr, ip_ceiling))
|
|
{
|
|
IU32 ip_phys_addr;
|
|
|
|
/* Ensure this we fault first on the first
|
|
* byte within a new page -- dasm386 sometimes
|
|
* looks ahead a couple of bytes.
|
|
*/
|
|
if (GET_EIP() != eip)
|
|
{
|
|
(void)usr_chk_byte((GET_CS_BASE() + eip) & 0xFFFFF000, PG_R);
|
|
}
|
|
ip_phys_addr = usr_chk_byte(GET_CS_BASE() + eip, PG_R);
|
|
ip_ptr = Sas.SasPtrToPhysAddrByte(ip_phys_addr);
|
|
ip_ceiling = CeilingIntelPageLS8(ip_ptr);
|
|
reset_prefetch = FALSE;
|
|
}
|
|
b = *IncCpuPtrLS8(ip_ptr);
|
|
last_eip = eip;
|
|
return ((IS32) b);
|
|
}
|
|
|
|
/* Use the decoder from dasm386 to read the bytes in a single instruction */
|
|
GLOBAL void prefetch_1_instruction IFN0()
|
|
{
|
|
IBOOL bigCode = GET_CS_AR_X() != 0;
|
|
IU32 eip = GET_EIP();
|
|
char *fmt, *newline;
|
|
|
|
reset_prefetch = TRUE;
|
|
|
|
/* If we take a fault, the EIP pushed will be the
|
|
* value at the start of the "instruction"
|
|
* We must update this incase we fault.
|
|
*/
|
|
CCPU_save_EIP = eip;
|
|
|
|
if ( bigCode )
|
|
{
|
|
fmt = " %04x:%08x ";
|
|
newline = "\n ";
|
|
}
|
|
else
|
|
{
|
|
fmt = " %04x:%04x ";
|
|
newline = "\n ";
|
|
}
|
|
(void)dasm_internal(prefetch_inst_buffer,
|
|
GET_CS_SELECTOR(),
|
|
eip,
|
|
bigCode ? THIRTY_TWO_BIT: SIXTEEN_BIT,
|
|
eip,
|
|
prefetch_byte,
|
|
fmt,
|
|
newline);
|
|
assert(strlen(prefetch_inst_buffer) < sizeof(prefetch_inst_buffer));
|
|
}
|
|
|
|
/* Return to the show_code() routine in the pigger the instruction
|
|
* we prefetched.
|
|
*/
|
|
GLOBAL char *get_prefetched_instruction IFN0()
|
|
{
|
|
return (prefetch_inst_buffer);
|
|
}
|
|
#endif /* PIG */
|