bool SheepMem::Init(void) { // Size of a native page page_size = vm_get_page_size(); // Allocate SheepShaver globals proc = base; if (vm_mac_acquire(base, size) < 0) return false; // Allocate page with all bits set to 0, right in the middle // This is also used to catch undesired overlaps between proc and data areas zero_page = proc + (size / 2); Mac_memset(zero_page, 0, page_size); if (vm_protect(Mac2HostAddr(zero_page), page_size, VM_PAGE_READ) < 0) return false; // Allocate alternate stack for PowerPC interrupt routine sig_stack = base + size; if (vm_mac_acquire(sig_stack, SIG_STACK_SIZE) < 0) return false; data = base + size; return true; }
uint8 * basic_jit_cache::copy_data(const uint8 *block, uint32 size) { const int ALIGN = 16; uint8 *ptr; if (data && (data->offs + size) < data->size) ptr = (uint8 *)data + data->offs; else { // No free space left, allocate a new chunk uint32 to_alloc = sizeof(*data) + size + ALIGN; uint32 page_size = vm_get_page_size(); to_alloc = (to_alloc + page_size - 1) & -page_size; D(bug("basic_jit_cache: Allocate data pool (%d KB)\n", to_alloc / 1024)); ptr = (uint8 *)vm_acquire(to_alloc, VM_MAP_PRIVATE | VM_MAP_32BIT); if (ptr == VM_MAP_FAILED) { fprintf(stderr, "FATAL: Could not allocate data pool!\n"); abort(); } data_chunk_t *dcp = (data_chunk_t *)ptr; dcp->size = to_alloc; dcp->offs = (sizeof(*data) + ALIGN - 1) & -ALIGN; dcp->next = data; data = dcp; ptr += dcp->offs; } memcpy(ptr, block, size); data->offs += (size + ALIGN - 1) & -ALIGN; D(bug("basic_jit_cache: DATA %p, %d bytes [data=%p, offs=%u]\n", ptr, size, data, data->offs)); return ptr; }
int main(void) { D(bug("%s\n", __func__)); int i, j; vm_init(); vm_uintptr_t page_size = vm_get_page_size(); char *area; const int n_pages = 7; const int area_size = n_pages * page_size; const int map_options = VM_MAP_DEFAULT | VM_MAP_WRITE_WATCH; if ((area = (char *)vm_acquire(area_size, map_options)) == VM_MAP_FAILED) return 1; unsigned int n_modified_pages_expected = 0; static const int touch_page[n_pages] = { 0, 1, 1, 0, 1, 0, 1 }; for (i = 0; i < n_pages; i++) { if (touch_page[i]) { area[i * page_size] = 1; ++n_modified_pages_expected; } } char *modified_pages[n_pages]; unsigned int n_modified_pages = n_pages; if (vm_get_write_watch(area, area_size, (void **)modified_pages, &n_modified_pages) < 0) return 2; if (n_modified_pages != n_modified_pages_expected) return 3; for (i = 0, j = 0; i < n_pages; i++) { char v = area[i * page_size]; if ((touch_page[i] && !v) || (!touch_page[i] && v)) return 4; if (!touch_page[i]) continue; if (modified_pages[j] != (area + i * page_size)) return 5; ++j; } vm_release(area, area_size); return 0; }
/* Tests covered here: - TEST_VM_PROT_* program slices actually succeeds when a crash occurs - TEST_VM_MAP_ANON* program slices succeeds when it could be compiled */ int main(void) { vm_init(); signal(SIGSEGV, fault_handler); #ifdef SIGBUS signal(SIGBUS, fault_handler); #endif #define page_align(address) ((char *)((vm_uintptr_t)(address) & -page_size)) vm_uintptr_t page_size = vm_get_page_size(); const int area_size = 6 * page_size; volatile char * area = (volatile char *) vm_acquire(area_size); volatile char * fault_address = area + (page_size * 7) / 2; #if defined(TEST_VM_MMAP_ANON) || defined(TEST_VM_MMAP_ANONYMOUS) if (area == VM_MAP_FAILED) return 1; if (vm_release((char *)area, area_size) < 0) return 1; return 0; #endif #if defined(TEST_VM_PROT_NONE_READ) || defined(TEST_VM_PROT_NONE_WRITE) if (area == VM_MAP_FAILED) return 0; if (vm_protect(page_align(fault_address), page_size, VM_PAGE_NOACCESS) < 0) return 0; #endif #if defined(TEST_VM_PROT_RDWR_WRITE) if (area == VM_MAP_FAILED) return 1; if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ) < 0) return 1; if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0) return 1; #endif #if defined(TEST_VM_PROT_READ_WRITE) if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ) < 0) return 0; #endif #if defined(TEST_VM_PROT_NONE_READ) // this should cause a core dump char foo = *fault_address; return 0; #endif #if defined(TEST_VM_PROT_NONE_WRITE) || defined(TEST_VM_PROT_READ_WRITE) // this should cause a core dump *fault_address = 'z'; return 0; #endif #if defined(TEST_VM_PROT_RDWR_WRITE) // this should not cause a core dump *fault_address = 'z'; return 0; #endif }