/* * OS-dependent routines. This file (along with os.h) exports an * OS-independent interface to the operating system VM facilities. * Suprisingly, this interface looks a lot like the Mach interface * (but simpler in some places). For some operating systems, a subset * of these functions will have to be emulated. * * This is the Mach version. * */ #include #include #include #include #include "os.h" #include "arch.h" #include "interrupt.h" #define MAX_SEGS 32 static struct segment { vm_address_t start; vm_size_t length; } addr_map[MAX_SEGS]; static int segments = -1; vm_size_t os_vm_page_size; #if defined(i386) || defined(parisc) mach_port_t task_self(void) { return mach_task_self(); } #endif void os_init0(const char *argv[], const char *envp[]) {} void os_init(const char *argv[], const char *envp[]) { os_vm_page_size = vm_page_size; } os_vm_address_t os_validate(vm_address_t addr, vm_size_t len) { kern_return_t res; res = vm_allocate(task_self(), &addr, len, addr == NULL); if (res != KERN_SUCCESS) return 0; segments = -1; vm_protect(task_self(), addr, len, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); return addr; } void os_invalidate(vm_address_t addr, vm_size_t len) { kern_return_t res; res = vm_deallocate(task_self(), addr, len); if (res != KERN_SUCCESS) mach_error("Could not vm_allocate memory: ", res); segments = -1; } vm_address_t os_map(int fd, int offset, vm_address_t addr, vm_size_t len) { kern_return_t res; res = map_fd(fd, offset, &addr, 0, len); if (res != KERN_SUCCESS) { char buf[256]; sprintf(buf, "Could not map_fd(%d, %d, 0x%08x, 0x%08x): ", fd, offset, addr, len); mach_error(buf, res); lseek(fd, offset, L_SET); read(fd, addr, len); } segments = -1; vm_protect(task_self(), addr, len, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); return addr; } void os_flush_icache(vm_address_t address, vm_size_t length) { #ifdef mips vm_machine_attribute_val_t flush; kern_return_t kr; flush = MATTR_VAL_ICACHE_FLUSH; kr = vm_machine_attribute(task_self(), address, length, MATTR_CACHE, &flush); if (kr != KERN_SUCCESS) mach_error("Could not flush the instruction cache", kr); #endif } void os_protect(vm_address_t address, vm_size_t length, vm_prot_t protection) { vm_protect(task_self(), address, length, FALSE, protection); } boolean valid_addr(test) vm_address_t test; { vm_address_t addr; vm_size_t size; int bullshit; int curseg; if (segments == -1) { addr = 0; curseg = 0; while (1) { if (vm_region (task_self(), &addr, &size, &bullshit, &bullshit, &bullshit, &bullshit, &bullshit, &bullshit) != KERN_SUCCESS) break; if (curseg > 0 && addr_map[curseg - 1].start + addr_map[curseg - 1].length == addr) addr_map[curseg - 1].length += size; else { addr_map[curseg].start = addr; addr_map[curseg].length = size; curseg++; } addr += size; } segments = curseg; } for (curseg = 0; curseg < segments; curseg++) if (addr_map[curseg].start <= test && test < addr_map[curseg].start + addr_map[curseg].length) return TRUE; return FALSE; } #ifndef ibmrt static void sigbus_handler(int signal, int code, struct sigcontext *context) { if (!interrupt_maybe_gc(signal, code, context)) interrupt_handle_now(signal, code, context); } #endif void os_install_interrupt_handlers(void) { #ifndef ibmrt interrupt_install_low_level_handler(SIGBUS, sigbus_handler); #endif #ifdef mips interrupt_install_low_level_handler(SIGSEGV, sigbus_handler); #endif }