I recently added PAT support into my kernel, and all is well and now framebuffer scrolling is nice and fast.
Except, as the title says, when running on real hardware (with an Intel i5-3210m CPU, also happens on an i5-3320m, does not happen on my Athlon 64 X2 PC), I receive a machine check exception.
When reading the MCE status MSRs, MCE_STATUS says an MCE is in progress, and that restart IP is valid, bank 1 MCi_STATUS says that it's valid and that MCi_ADDR is valid, and bank 1 MCi_ADDR points to the LAPIC (although it points to a register I never access, either directly or indirectly).
I can't see why it fails now, or if it's a problem unrelated to PAT, why it didn't fail before.
Thanks in advance for any help!
Relevant code:
Code that maps the LAPIC:
Code: Select all
arch_mm_map_kernel((void *)lapic_base, (void *)lapic_base, 4, // 4 pages
ARCH_MM_FLAG_R | ARCH_MM_FLAG_W, ARCH_MM_CACHE_UC);
Code: Select all
#define ARCH_MM_FLAG_R 0x01 /* page is readable */
#define ARCH_MM_FLAG_W 0x02 /* page is writable */
#define ARCH_MM_FLAG_E 0x04 /* page is executable */
#define ARCH_MM_FLAG_U 0x08 /* page is accessible in user mode */
#define ARCH_MM_CACHE_WB 0 /* write-back */
#define ARCH_MM_CACHE_WT 1 /* write-through */
#define ARCH_MM_CACHE_WC 2 /* write-combining */
#define ARCH_MM_CACHE_WP 3 /* write-protect */
#define ARCH_MM_CACHE_UC 4 /* uncacheable */
#define ARCH_MM_CACHE_DEFAULT ARCH_MM_CACHE_WB
Code: Select all
// PAT setup
cpu_set_msr(0x277, 0x0000000005010406);
// flags
#define VMM_FLAG_WRITE (1<<1)
#define VMM_FLAG_USER (1<<2)
#define VMM_FLAG_PAT0 (1<<3)
#define VMM_FLAG_PAT1 (1<<4)
#define VMM_FLAG_PAT2 (1<<4)
#define VMM_FLAG_NX (1ull<<63)
// these flags only apply to the lowest-level table entries
// higher tables (PML4, PDP, PD) only get (arch_flags & (WRITE | USER))
// the present bit is set automatically for each entry
int vmm_arch_to_vmm_flags(int flags, int cache) {
int arch_flags = 0;
if (flags & ARCH_MM_FLAG_W) arch_flags |= VMM_FLAG_WRITE;
if (flags & ARCH_MM_FLAG_U) arch_flags |= VMM_FLAG_USER;
if (!(flags & ARCH_MM_FLAG_E)) arch_flags |= VMM_FLAG_NX;
if (cache & (1 << 0)) arch_flags |= VMM_FLAG_PAT0;
if (cache & (1 << 1)) arch_flags |= VMM_FLAG_PAT1;
if (cache & (1 << 2)) arch_flags |= VMM_FLAG_PAT2;
return arch_flags;
}