📄 registry.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * *//***************************************************************** * $File$ * * The registry should hold three types of "special" addresses: * Backdoor functions * Backdoor variables * I/O device ranges * * $Author: bosch $ * $Date: 1998/02/10 00:28:32 $ *****************************************************************/#include <stdlib.h>#include "cpu_interface.h"#include "simtypes.h"#include "simutil.h"#include "list.h"#include "sim_error.h"#include "simutil.h"#include "registry.h"#include "sim.h"#include "syslimits.h"#define MAX_FUNCS 1023 /* max. func. entries */#define MAX_ENTRIES_CPU 32 /* max. range entries per CPU */#define MAX_ENTRIES SIM_MAXCPUS*MAX_ENTRIES_CPU/* Just for registering backdoor functions */typedef struct FuncEntry FuncEntry;struct FuncEntry { bool present; uint64 tag; void (*func)(void);};static FuncEntry funcRegistry[MAX_FUNCS];/* For registering backdoor and I/O data ranges */typedef struct entry Entry;struct entry { VA start; VA end; uint flag; void *data; /* This is either a function or a data pointer */ char *name; /* Name, only used for debugging */};static Entry registry[MAX_ENTRIES]; /* range registry */static int numEntries = 0; /* number of entries */static int complete = 0; /* still adding entries if == 0 */static Entry* lastEntry; /* pointer to last entry accessed */static VA minAddress;static VA maxAddress;static uint simFuncCount;/***************************************************************** * Registry initialization *****************************************************************/void RegistryInit(void){ int i; minAddress = (VA)-1LL; maxAddress = 0; for (i=0; i < MAX_FUNCS; i++) { funcRegistry[i].func = NULL; funcRegistry[i].present = FALSE; } lastEntry = registry; numEntries = 0;}/***************************************************************** * This procedure just allows you to register functions with the * registry with no regard as to what address they are placed at. * They will end up being dereferenced in the kernel, caught by * the simulators, and then the corresponding function will be * executed in the backdoor. All functions will be called with * normal parameter lists, so I kept the arg type as void. *****************************************************************/void RegistryAddSimFunction(void *ptr, void *func){ uint hash; simFuncCount++; ASSERT(simFuncCount < MAX_FUNCS); hash = PTR_TO_UINT64(ptr) % MAX_FUNCS; while (funcRegistry[hash].present) { if (funcRegistry[hash].tag == PTR_TO_UINT64(ptr)) { CPUPrint("REGISTRY: OVERRIDE %#x as %#x entry %d\n", funcRegistry[hash].func, funcRegistry[hash].tag, hash); break; } hash = (hash + 1) % MAX_FUNCS; } funcRegistry[hash].func = (void (*) (void))func; funcRegistry[hash].tag = PTR_TO_UINT64(ptr); funcRegistry[hash].present = TRUE; SIM_DEBUG(('b', "REGISTRY: ADDED %#x as %#x entry %d\n", func, ptr, hash));}void *RegistryGetSimFunction(VA address){ uint hash; hash = (uint)address % MAX_FUNCS; while (funcRegistry[hash].tag != (uint)address) { if (funcRegistry[hash].present != TRUE) { /* fell off the end of the list. CPU model should * give a bus error to the processor since this * is unmapped memory. */ return NULL; } hash = (hash + 1) % MAX_FUNCS; } SIM_DEBUG(('b', "BDOOR %lld getfunc: 0x%llx\n", (Reg64)CPUVec.CycleCount(0), (Reg64)address)); return (void *)funcRegistry[hash].func;}/***************************************************************** * Add a chunk of the virtual address space to the registry along * with flags and an optional function that can be executed when this * range is addressed. The flag indicates whether this reference * should be treated as a function or just read uncached as data. ****************************************************************/intRegistryAddRange(VA start, VA size, uint flag, void *data, char *name){ VA end = start + size; register Entry *ptr; register Entry *endPtr = registry + numEntries; ASSERT(size > 0); ASSERT(!complete); /* Check for overlap. */ for (ptr = registry; ptr < endPtr; ptr++) { if ((end <= ptr->start) || (start >= ptr->end)) continue; CPUError("Overlap in call to RegistryAddRange\n"); } ASSERT(numEntries < MAX_ENTRIES); ptr = endPtr; numEntries++; ptr->start = start; ptr->end = start + size; ptr->flag = flag; ptr->data = data; ptr->name = SaveString(name); if (start < minAddress) minAddress = start; if (start > maxAddress) maxAddress = start+size; /* Report the registery update (PZ) */ CPUPrint("Registering region [%#08lx, %#08lx) for %s.\n", (long)start, (long)(start + size), name); return 0;}/***************************************************************** * Function for comparing registry entries. Assumes the * entries don't overlap. ****************************************************************/static intentry_compare(const void* ep1, const void* ep2){ Entry *e1 = (Entry*) ep1; Entry *e2 = (Entry*) ep2; if (e1->start == e2->start && e1->end == e2->end) return 0; if (e1->end <= e2->start) return -1; if (e2->end <= e1->start) return 1; ASSERT(0); return 0; /* keep compiler happy */}static intelem_compare(const void* xp, const void* ep){ VA x = *(VA *)xp; Entry* e = (Entry*)ep; if (e->start <= x && x < e->end) return 0; if (e->end <= x) return 1; else return -1;}/***************************************************************** * Signals that all ranges have been added to the registry. * The registry will be sorted, so that we can use fast binary * search in RegistryIsInRange. ****************************************************************/voidRegistryComplete(void){ ASSERT(!complete); /* sort registry */ qsort(registry, numEntries, sizeof(Entry), entry_compare); complete = 1;}/***************************************************************** * Given a virtual address, this procedure determines if it is * in the special range of addresses. These addresses can be * set to be DATA or FUNCTIONS and the returned flag determines * which is intended. *****************************************************************/boolRegistryIsInRange(VA addr, void **data, uint *flag){ register Entry *ptr; VA vAddr; ASSERT(complete && numEntries > 0); /* Check cache of last entry */ if ((addr >= lastEntry->start) && (addr < lastEntry->end)) { /* Found a registered address! */ *flag = lastEntry->flag; if (*flag == REG_FUNC) *data = (char *)lastEntry->data; else *data = ((char*)lastEntry->data) + (addr - lastEntry->start); SIM_DEBUG(('b', "BDOOR %lld inRange: 0x%llx (%s) to 0x%x\n", (Reg64)CPUVec.CycleCount(0), (Reg64)addr, lastEntry->name, *data)); return TRUE; } if ((addr < minAddress) || (addr > maxAddress)) { return FALSE; } /* use binary search on registry -- it's sorted */ vAddr = addr; ptr = bsearch((void*)&vAddr, registry, numEntries, sizeof(Entry), elem_compare); if (!ptr) return FALSE; /* not found */ ASSERT(addr >= ptr->start && addr < ptr->end); /* Found a registered address! */ *flag = ptr->flag; if (*flag == REG_FUNC) *data = (char *)ptr->data; else *data = ((char*)ptr->data) + (addr - ptr->start); lastEntry = ptr; SIM_DEBUG(('b', "BDOOR %lld inRange: 0x%llx (%s) to 0x%x\n", (Reg64)CPUVec.CycleCount(0), (Reg64)addr, lastEntry->name, *data)); return TRUE;}/***************************************************************** * Given a virtual address, this procedure determines the address * that the kernel should use to access it. *****************************************************************/VARegistryReverseMap(void *data){ register Entry *ptr; register Entry *endPtr = registry + numEntries;#if !(defined(sgi) && defined(_ABIN32)) for (ptr = registry; ptr < endPtr; ptr++) { int size = ptr->end - ptr->start; if ((data >= ptr->data) && ((char *)data < (char *)ptr->data+size)) { return ptr->start + ((char *)data - (char *)ptr->data); } }#else /* Workaround for an SGI compiler bug - The "real" version of this code * crashes the compiler. */ for (ptr = registry; ; ptr++) { int size = ptr->end - ptr->start; if ((data >= ptr->data) && ((char *)data < (char *)ptr->data+size)) { return ptr->start + ((char *)data - (char *)ptr->data); } if ( ptr < endPtr) break; }#endif return (VA)0;}voidRegistryDumpEntries(void){ Entry *ptr; Entry *endPtr = registry + numEntries; for (ptr = registry; ptr < endPtr; ptr++) { SIM_DEBUG(('b', "REGISTRY: %#llx - %#llx : (%#llx) : %s (%s)\n", (Reg64)ptr->start, (Reg64)ptr->end, (Reg64)ptr->data, ptr->name, (ptr->flag == REG_DATA)? "data":"func")); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -