Adding a V=R mapping for amd64?
Matthew Fleming
mdf356 at gmail.com
Wed Sep 29 20:22:58 UTC 2010
On Wed, Sep 29, 2010 at 1:12 PM, Kostik Belousov <kostikbel at gmail.com> wrote:
> On Wed, Sep 29, 2010 at 12:40:57PM -0700, Matthew Fleming wrote:
>> 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?
>
> Weird formatting of backtrace. Is this some proprietary code ?
Yeah, there's some Isilon local modifications.
> Why do you try to create 1-1 mapping at all ? The MBR code should be
> executing in real mode anyway, and the mapping address at the moment of
> bcopy does not matter at all. I think that the use of PHYS_TO_DMAP()
> should give you direct mapping.
I assumed I need trampoline code. The moment I turn off the xlation
bits, if the instruction pointer I'm running from is the normal kernel
addresses, won't I die horribly trying to access 0xffffffff80000000 or
so in real mode?
> About the #pf that you see. I think that this is due to the fact that
> you are modifying kernel pmap, while the active one is the pmap of
> the user process which context issued reboot().
Isn't the kernel pmap active in the kernel, since I've entered via the
syscall reboot(2) ?
Thanks,
matthew
More information about the freebsd-hackers
mailing list