limine: Set up framebuffer caching as WC
diff --git a/PROTOCOL.md b/PROTOCOL.md
index ee31d678..edf1bcb7 100644
--- a/PROTOCOL.md
+++ b/PROTOCOL.md
@@ -100,9 +100,7 @@ that every usable, bootloader reclaimable, framebuffer, or kernel/modules
memory map region is mapped at HHDM offset + its physical address.
Additionally, the whole 0->4GiB physical memory region will also be mapped
at HHDM offset + physical address, regardless of the contents of the
-memory map.
-These mappings are supervisor, read, write, execute (-rwx), and they use
-WB caching (on x86_64).
+memory map. These mappings are supervisor, read, write, execute (-rwx).
The bootloader page tables are in bootloader-reclaimable memory (see Memory Map
feature below), and their specific layout is undefined as long as they provide
@@ -112,6 +110,18 @@ If the kernel is a position independent executable, the bootloader is free to
relocate it as it sees fit, potentially performing KASLR (as specified by the
config).
+## Caching
+
+### x86_64
+
+All HHDM memory regions are mapped using write-back (WB) caching, except
+framebuffer regions which are mapped using write-combining (WC) caching.
+
+The MTRRs are left as the firmware set them up.
+
+The PAT's (Page Attribute Table) layout is unspecified and the OS should
+not be making assumptions about it.
+
## Entry machine state
### x86_64
diff --git a/common/mm/vmm.c b/common/mm/vmm.c
index b46dba2e..b4db155d 100644
--- a/common/mm/vmm.c
+++ b/common/mm/vmm.c
@@ -119,6 +119,12 @@ level4:
pml1 = get_next_level(pagemap, pml2, virt_addr, pg_size, 1, pml2_entry);
+ // PML1 wants PAT bit at 7 instead of 12
+ if (flags & ((uint64_t)1 << 12)) {
+ flags &= ~((uint64_t)1 << 12);
+ flags |= ((uint64_t)1 << 7);
+ }
+
pml1[pml1_entry] = (pt_entry_t)(phys_addr | flags);
}
diff --git a/common/mm/vmm.h b/common/mm/vmm.h
index eac31001..20bd5765 100644
--- a/common/mm/vmm.h
+++ b/common/mm/vmm.h
@@ -8,7 +8,7 @@
#define VMM_FLAG_WRITE ((uint64_t)1 << 1)
#define VMM_FLAG_NOEXEC ((uint64_t)1 << 63)
-#define VMM_FLAG_FB ((uint64_t)0)
+#define VMM_FLAG_FB (((uint64_t)1 << 3) | ((uint64_t)1 << 12))
#define VMM_MAX_LEVEL 3
diff --git a/common/protos/limine.c b/common/protos/limine.c
index dd8ec18b..28a6ccba 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -1080,6 +1080,12 @@ FEAT_END
rm_int(0x15, &r, &r);
#endif
+ // Enable PAT (write-combining/write-protect)
+ uint64_t pat = rdmsr(0x277);
+ pat &= 0xffffffff;
+ pat |= (uint64_t)0x0105 << 32;
+ wrmsr(0x277, pat);
+
pic_mask_all();
io_apic_mask_all();
