Adding a V=R mapping for amd64?

Matthew Fleming mdf356 at gmail.com
Wed Sep 29 19:40:59 UTC 2010


I'm hacking around with making a "fast reboot" that puts a copy of the
MBR from disk into address 0x7c00 and, after disabling various
translation bits and stopping other CPUs, branches to it, to skip the
hardware self test that normally happens on boot.

I haven't gotten to the point of attempting to run the code at 0x7c00
because I'm first hitting a different error.  Despite my attempts to
enter a translation into the hardware page table, I get a panic trying
to write to address 0x7000, where I intended to put the trampoline
code that turns off translation.

Rebooting...
Attempt to reset to MBR...
XXX attempting pmap_kenter()...
XXX copying bootstrap code...
panic @ time 1285760103.939, thread 0xffffff000775d960: Fatal trap 12:
page fault while in kernel mode

cpuid = 0
Panic occurred in module kernel loaded at 0xffffffff80100000:

Stack: --------------------------------------------------
kernel:trap_fatal+0xac
kernel:trap_pfault+0x24c
kernel:trap+0x42e
kernel:bcopy+0x16
kernel:shutdown_reset+0x48
kernel:boot+0x317
kernel:reboot+0x60
kernel:ia32_syscall+0x1cd
--------------------------------------------------
cpuid = 0; apic id = 00
fault virtual address   = 0x7000
fault code              = supervisor write data, page not present
stack pointer           = 0x10:0xffffff8059e07670
frame pointer           = 0x10:0xffffff8059e07780

Here's what I think is the relevant snippets of code.  Note that I
reserved the vm_page_t for physical page 7 as mbr_page early in boot,
so I know the memory is free.

void
pmap_kenter_VR(vm_paddr_t pa)
{
	pmap_t pmap = kernel_pmap;
	vm_page_t mpte;
	pd_entry_t *pde;
	pt_entry_t *pte;

	vm_page_lock_queues();
	PMAP_LOCK(pmap);
	mpte = pmap_allocpte(pmap, pa, M_WAITOK);

	pde = pmap_pde(pmap, pa);
	if (pde == NULL || (*pde & PG_V) == 0)
		panic("%s: invalid page directory va=%#lx", __func__, pa);
	if ((*pde & PG_PS) != 0)
		panic("%s: attempted pmap_enter on 2MB page", __func__);
	pte = pmap_pde_to_pte(pde, pa);
	if (pte == NULL)
		panic("%s: no pte va=%#lx", __func__, pa);

	if (*pte != 0) {
		/* Remove extra pte reference. */
		mpte->wire_count--;
	}
        pte_store(pte, pa | PG_RW | PG_V | PG_G | pg_nx);
	
	vm_page_unlock_queues();
	PMAP_UNLOCK(pmap);
}

Then in cpu_reset():

	/*
	 * Establish a V=R mapping for the MBR page, and copy a
	 * reasonable guess at the size of the bootstrap code into the
	 * beginning of the page.
	 */
	printf("XXX attempting pmap_kenter()...\n");
	pmap_kenter_VR(trunc_page(mbaddr));
	printf("XXX copying bootstrap code...\n");
	to_copy = (uintptr_t)xxx_reset_end - (uintptr_t)xxx_reset_real;
	if (to_copy > mbaddr - trunc_page(mbaddr))
		to_copy = mbaddr - trunc_page(mbaddr);
	bcopy(xxx_reset_real, (void *)trunc_page(mbaddr), to_copy);  /* die here */
	printf("XXX attempting to turn off xlation and re-run MBR...\n");
	xxx_reset_real(mbaddr);


My first attempt was a call to
	pmap_kenter(trunc_page(0x7c00), trunc_page(0x7c00));
which failed trying to dereference the non-existent PDE.

My second attempt called
	pmap_enter(kernel_pmap, trunc_page(0x7c00), VM_PROT_WRITE, mbr_page,
	    VM_PROT_ALL, 0);
That failed with the same crash as the attempt using pmap_kenter_VR().

So... any thoughts as to why, after an apparently successful
installation of an xlation, I still get a panic as though there were
no xlation?

Thanks,
matthew


More information about the freebsd-hackers mailing list