/* mm-init.h - Memory management initialization. Copyright (C) 2004, 2005, 2008 Free Software Foundation, Inc. Written by Neal H. Walfield . This file is part of the GNU Hurd. The GNU Hurd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. The GNU Hurd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the GNU Hurd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #if HAVE_CONFIG_H #include #endif #include #include #if defined(i386) || defined(__x86_64) # include #endif #include #include "storage.h" #include "as.h" extern struct hurd_startup_data *__hurd_startup_data; vg_addr_t meta_data_activity; int mm_init_done; void mm_init (vg_addr_t activity) { assert (! mm_init_done); extern int output_debug; output_debug = 1; if (VG_ADDR_IS_VOID (activity)) meta_data_activity = __hurd_startup_data->activity; else meta_data_activity = activity; hurd_activation_handler_init_early (); storage_init (); as_init (); hurd_activation_handler_init (); mm_init_done = 1; #ifndef NDEBUG /* The following test checks the activation trampoline. In particular, it checks that the register file before a fault matches the register file after a fault. This is interesting because such an activation is handled in normal mode. That means, when the fault occurs, we enter the activation handler, return an activation frame, enter normal mode, execute the normal mode activation handler, call the call back functions, and then return to the interrupted code. */ #if defined(i386) || defined(__x86_64) int d = 5; void test (int nesting) { vg_addr_t addr = as_alloc (PAGESIZE_LOG2, 1, true); void *a = VG_ADDR_TO_PTR (vg_addr_extend (addr, 0, PAGESIZE_LOG2)); int recursed = false; /* We allocate the storage in the fault handler. */ struct storage storage; memset (&storage, 0, sizeof (storage)); int faulted = false; bool fault (struct pager *pager, uintptr_t offset, int count, bool ro, uintptr_t fault_addr, uintptr_t ip, struct vg_activation_fault_info info) { assert (a == (void *) (fault_addr & ~(PAGESIZE - 1))); assert (count == 1); struct hurd_utcb *utcb = hurd_utcb (); struct activation_frame *activation_frame = utcb->activation_stack; debug (d, "Fault at %p " AF_REGS_FMT, fault, AF_REGS_PRINTF (activation_frame)); #ifdef i386 assert (activation_frame->eax == 0xa); assert (activation_frame->ebx == 0xb); assert (activation_frame->ecx == 0xc); assert (activation_frame->edx == 0xd); assert (activation_frame->edi == 0xd1); assert (activation_frame->esi == 0x21); assert (activation_frame->ebp == (uintptr_t) a); /* We cannot easily check esp and eip here. */ #endif as_ensure (addr); storage = storage_alloc (VG_ADDR_VOID, vg_cap_page, STORAGE_UNKNOWN, VG_OBJECT_POLICY_DEFAULT, addr); if (nesting > 1 && ! recursed) { recursed = true; int i; for (i = 0; i < 3; i ++) { debug (d, "Depth: %d; iter: %d", nesting - 1, i); test (nesting - 1); debug (d, "Depth: %d; iter: %d done", nesting - 1, i); } } faulted = true; return true; } struct pager pager = PAGER_VOID; pager.length = PAGESIZE; pager.fault = fault; pager_init (&pager); struct region region = { (uintptr_t) a, PAGESIZE }; struct map *map = map_create (region, MAP_ACCESS_ALL, &pager, 0, NULL); #ifdef i386 # define R(reg) "%%e" #reg # define WS "4" #else # define R(reg) "%%r" #reg # define WS "8" #endif uintptr_t pre_flags, pre_sp; uintptr_t ax, bx, cx, dx, di, si, bp, sp, flags; uintptr_t canary; /* Check that the trampoline works. */ __asm__ __volatile__ ( "mov "R(sp)", %[pre_sp]\n\t" "pushf\n\t" "pop "R(ax)"\n\t" "mov "R(ax)", %[pre_flags]\n\t" /* Canary. */ "mov $0xcab00d1e, "R(ax)"\n\t" "push "R(ax)"\n\t" "push "R(bp)"\n\t" "mov $0xa, "R(ax)"\n\t" "mov $0xb, "R(bx)"\n\t" "mov $0xc, "R(cx)"\n\t" "mov $0xd, "R(dx)"\n\t" "mov $0xd1, "R(di)"\n\t" "mov $0x21, "R(si)"\n\t" "mov %[addr], "R(bp)"\n\t" /* Fault! */ "mov "R(ax)", 0("R(bp)")\n\t" /* Save the current bp. */ "push "R(bp)"\n\t" /* Restore the old bp. */ "mov "WS"("R(sp)"), "R(bp)"\n\t" /* Save the rest of the GP registers. */ "mov "R(ax)", %[ax]\n\t" "mov "R(bx)", %[bx]\n\t" "mov "R(cx)", %[cx]\n\t" "mov "R(dx)", %[dx]\n\t" "mov "R(di)", %[di]\n\t" "mov "R(si)", %[si]\n\t" /* Save the new flags. */ "pushf\n\t" "pop "R(ax)"\n\t" "mov "R(ax)", %[flags]\n\t" /* Save the new bp. */ "mov 0("R(sp)"), "R(ax)"\n\t" "mov "R(ax)", %[bp]\n\t" /* Fix up the stack. */ "add $(2*"WS"), "R(sp)"\n\t" /* Grab the canary. */ "pop "R(ax)"\n\t" "mov "R(ax)", %[canary]\n\t" /* And don't forget to save the new sp. */ "mov "R(sp)", %[sp]\n\t" : [ax] "=m" (ax), [bx] "=m" (bx), [cx] "=m" (cx), [dx] "=m" (dx), [di] "=m" (di), [si] "=m" (si), [bp] "=m" (bp), [pre_sp] "=m" (pre_sp), [sp] "=m" (sp), [pre_flags] "=m" (pre_flags), [flags] "=m" (flags), [canary] "=m" (canary) : [addr] "m" (a) #ifdef i386 : "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" #else : "%rax", "%rbx", "%rcx", "%rdx", "%rdi", "%rsi" #endif ); debug (d, "Regsiter file: " "ax: %p, bx: %p, cx: %p, dx: %p, " "di: %p, si: %p, bp: %p -> %p, sp: %p -> %p, flags: %p -> %p", (void *) ax, (void *) bx, (void *) cx, (void *) dx, (void *) di, (void *) si, (void *) a, (void *) bp, (void *) pre_sp, (void *) sp, (void *) pre_flags, (void *) flags); assert (ax == 0xa); assert (bx == 0xb); assert (cx == 0xc); assert (dx == 0xd); assert (di == 0xd1); assert (si == 0x21); assert (bp == (uintptr_t) a); assert (sp == pre_sp); assert (flags == pre_flags); assert (canary == 0xcab00d1e); assert (faulted); maps_lock_lock (); map_disconnect (map); maps_lock_unlock (); map_destroy (map); assert (! VG_ADDR_IS_VOID (storage.addr)); storage_free (storage.addr, true); as_free (addr, 1); } int i; for (i = 0; i < 3; i ++) { debug (d, "Depth: %d; iter: %d", 3, i + 1); test (3); debug (d, "Depth: %d; iter: %d done", 3, i + 1); } #endif #endif }