예제 #1
0
void
acpi_install_wakeup_handler(struct acpi_softc *sc)
{
	static void	*wakeaddr;
	void		*wakepages[ACPI_WAKEPAGES];
#ifdef __amd64__
	uint64_t	*pt4, *pt3, *pt2;
	vm_paddr_t	pt4pa, pt3pa, pt2pa;
	int		i;
#endif

	if (wakeaddr != NULL)
		return;

	if (acpi_alloc_wakeup_handler(wakepages) == NULL)
		return;

	wakeaddr = wakepages[0];
	sc->acpi_wakeaddr = (vm_offset_t)wakeaddr;
	sc->acpi_wakephys = vtophys(wakeaddr);

#ifdef __amd64__
	pt4 = wakepages[1];
	pt3 = wakepages[2];
	pt2 = wakepages[3];
	pt4pa = vtophys(pt4);
	pt3pa = vtophys(pt3);
	pt2pa = vtophys(pt2);
#endif

	bcopy(wakecode, (void *)sc->acpi_wakeaddr, sizeof(wakecode));

	/* Patch GDT base address, ljmp targets. */
	WAKECODE_FIXUP((bootgdtdesc + 2), uint32_t,
	    sc->acpi_wakephys + bootgdt);
	WAKECODE_FIXUP((wakeup_sw32 + 2), uint32_t,
	    sc->acpi_wakephys + wakeup_32);
#ifdef __amd64__
	WAKECODE_FIXUP((wakeup_sw64 + 1), uint32_t,
	    sc->acpi_wakephys + wakeup_64);
	WAKECODE_FIXUP(wakeup_pagetables, uint32_t, pt4pa);
#endif

	/* Save pointers to some global data. */
	WAKECODE_FIXUP(wakeup_ret, void *, resumectx);
#ifndef __amd64__
#if defined(PAE) || defined(PAE_TABLES)
	WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdpt));
#else
	WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdir));
#endif

#else /* __amd64__ */
	/* Create the initial 1GB replicated page tables */
	for (i = 0; i < 512; i++) {
		/*
		 * Each slot of the level 4 pages points
		 * to the same level 3 page
		 */
		pt4[i] = (uint64_t)pt3pa;
		pt4[i] |= PG_V | PG_RW | PG_U;

		/*
		 * Each slot of the level 3 pages points
		 * to the same level 2 page
		 */
		pt3[i] = (uint64_t)pt2pa;
		pt3[i] |= PG_V | PG_RW | PG_U;

		/* The level 2 page slots are mapped with 2MB pages for 1GB. */
		pt2[i] = i * (2 * 1024 * 1024);
		pt2[i] |= PG_V | PG_RW | PG_PS | PG_U;
	}
#endif /* !__amd64__ */

	if (bootverbose)
		device_printf(sc->acpi_dev, "wakeup code va %#jx pa %#jx\n",
		    (uintmax_t)sc->acpi_wakeaddr, (uintmax_t)sc->acpi_wakephys);
}
예제 #2
0
void
acpi_install_wakeup_handler(struct acpi_softc *sc)
{
	static void	*wakeaddr = NULL;
#ifdef __amd64__
	uint64_t	*pt4, *pt3, *pt2;
	int		i;
#endif

	if (wakeaddr != NULL)
		return;

	wakeaddr = acpi_alloc_wakeup_handler();
	if (wakeaddr == NULL)
		return;

	sc->acpi_wakeaddr = (vm_offset_t)wakeaddr;
	sc->acpi_wakephys = vtophys(wakeaddr);

	bcopy(wakecode, (void *)WAKECODE_VADDR(sc), sizeof(wakecode));

	/* Patch GDT base address, ljmp targets. */
	WAKECODE_FIXUP((bootgdtdesc + 2), uint32_t,
	    WAKECODE_PADDR(sc) + bootgdt);
	WAKECODE_FIXUP((wakeup_sw32 + 2), uint32_t,
	    WAKECODE_PADDR(sc) + wakeup_32);
#ifdef __amd64__
	WAKECODE_FIXUP((wakeup_sw64 + 1), uint32_t,
	    WAKECODE_PADDR(sc) + wakeup_64);
	WAKECODE_FIXUP(wakeup_pagetables, uint32_t, sc->acpi_wakephys);
#endif

	/* Save pointers to some global data. */
	WAKECODE_FIXUP(wakeup_ret, void *, resumectx);
#ifndef __amd64__
#ifdef PAE
	WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdpt));
#else
	WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdir));
#endif

#else
	/* Build temporary page tables below realmode code. */
	pt4 = wakeaddr;
	pt3 = pt4 + (PAGE_SIZE) / sizeof(uint64_t);
	pt2 = pt3 + (PAGE_SIZE) / sizeof(uint64_t);

	/* Create the initial 1GB replicated page tables */
	for (i = 0; i < 512; i++) {
		/*
		 * Each slot of the level 4 pages points
		 * to the same level 3 page
		 */
		pt4[i] = (uint64_t)(sc->acpi_wakephys + PAGE_SIZE);
		pt4[i] |= PG_V | PG_RW | PG_U;

		/*
		 * Each slot of the level 3 pages points
		 * to the same level 2 page
		 */
		pt3[i] = (uint64_t)(sc->acpi_wakephys + (2 * PAGE_SIZE));
		pt3[i] |= PG_V | PG_RW | PG_U;

		/* The level 2 page slots are mapped with 2MB pages for 1GB. */
		pt2[i] = i * (2 * 1024 * 1024);
		pt2[i] |= PG_V | PG_RW | PG_PS | PG_U;
	}
#endif

	if (bootverbose)
		device_printf(sc->acpi_dev, "wakeup code va %#jx pa %#jx\n",
		    (uintmax_t)sc->acpi_wakeaddr, (uintmax_t)sc->acpi_wakephys);
}
예제 #3
0
void
acpi_install_wakeup_handler(struct acpi_softc *sc)
{
	static void	*wakeaddr = NULL;
	uint64_t	*pt4, *pt3, *pt2;
	int		i;

	if (wakeaddr != NULL)
		return;

	wakeaddr = acpi_alloc_wakeup_handler();
	if (wakeaddr == NULL)
		return;

	sc->acpi_wakeaddr = (vm_offset_t)wakeaddr;
	sc->acpi_wakephys = vtophys(wakeaddr);

	bcopy(wakecode, (void *)WAKECODE_VADDR(sc), sizeof(wakecode));

	/* Patch GDT base address, ljmp targets and page table base address. */
	WAKECODE_FIXUP((bootgdtdesc + 2), uint32_t,
	    WAKECODE_PADDR(sc) + bootgdt);
	WAKECODE_FIXUP((wakeup_sw32 + 2), uint32_t,
	    WAKECODE_PADDR(sc) + wakeup_32);
	WAKECODE_FIXUP((wakeup_sw64 + 1), uint32_t,
	    WAKECODE_PADDR(sc) + wakeup_64);
	WAKECODE_FIXUP(wakeup_pagetables, uint32_t, sc->acpi_wakephys);

	/* Save pointers to some global data. */
	WAKECODE_FIXUP(wakeup_retaddr, void *, acpi_restorecpu);
	WAKECODE_FIXUP(wakeup_kpml4, uint64_t, KPML4phys);
	WAKECODE_FIXUP(wakeup_ctx, vm_offset_t,
	    WAKECODE_VADDR(sc) + wakeup_ctx);
	WAKECODE_FIXUP(wakeup_efer, uint64_t, rdmsr(MSR_EFER));
	WAKECODE_FIXUP(wakeup_star, uint64_t, rdmsr(MSR_STAR));
	WAKECODE_FIXUP(wakeup_lstar, uint64_t, rdmsr(MSR_LSTAR));
	WAKECODE_FIXUP(wakeup_cstar, uint64_t, rdmsr(MSR_CSTAR));
	WAKECODE_FIXUP(wakeup_sfmask, uint64_t, rdmsr(MSR_SF_MASK));
	WAKECODE_FIXUP(wakeup_xsmask, uint64_t, xsave_mask);

	/* Build temporary page tables below realmode code. */
	pt4 = wakeaddr;
	pt3 = pt4 + (PAGE_SIZE) / sizeof(uint64_t);
	pt2 = pt3 + (PAGE_SIZE) / sizeof(uint64_t);

	/* Create the initial 1GB replicated page tables */
	for (i = 0; i < 512; i++) {
		/*
		 * Each slot of the level 4 pages points
		 * to the same level 3 page
		 */
		pt4[i] = (uint64_t)(sc->acpi_wakephys + PAGE_SIZE);
		pt4[i] |= PG_V | PG_RW | PG_U;

		/*
		 * Each slot of the level 3 pages points
		 * to the same level 2 page
		 */
		pt3[i] = (uint64_t)(sc->acpi_wakephys + (2 * PAGE_SIZE));
		pt3[i] |= PG_V | PG_RW | PG_U;

		/* The level 2 page slots are mapped with 2MB pages for 1GB. */
		pt2[i] = i * (2 * 1024 * 1024);
		pt2[i] |= PG_V | PG_RW | PG_PS | PG_U;
	}

	if (bootverbose)
		device_printf(sc->acpi_dev, "wakeup code va %p pa %p\n",
		    (void *)sc->acpi_wakeaddr, (void *)sc->acpi_wakephys);
}