]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
plat/x86: Add `write-combined` page entry attribute
authorMarco Schlumpp <marco.schlumpp@gmail.com>
Tue, 25 Oct 2022 13:45:14 +0000 (15:45 +0200)
committerUnikraft <monkey@unikraft.io>
Fri, 28 Apr 2023 08:41:35 +0000 (08:41 +0000)
This attribute is useful for memory-mapped devices and can reduce the
amount of transactions necessary when communicating with the device.

Signed-off-by: Marco Schlumpp <marco@unikraft.io>
Reviewed-by: Marc Rittinghaus <marc.rittinghaus@unikraft.io>
Approved-by: Alexander Jung <alex@unikraft.io>
Tested-by: Unikraft CI <monkey@unikraft.io>
GitHub-Closes: #788

arch/x86/x86_64/include/uk/asm/lcpu.h
arch/x86/x86_64/include/uk/asm/paging.h
plat/common/include/x86/paging.h

index 127430490803e4b605f7315e6b5afb06f941b2c2..c8aa635a2f57898f9b467a52992629aa0714ea84 100644 (file)
@@ -138,6 +138,7 @@ static inline void ukarch_spinwait(void)
 #define X86_CPUID1_ECX_AVX      (1 << 28)
 #define X86_CPUID1_ECX_RDRAND  (1 << 30)
 #define X86_CPUID1_EDX_FPU      (1 << 0)
+#define X86_CPUID1_EDX_PAT      (1 << 16)
 #define X86_CPUID1_EDX_FXSR     (1 << 24)
 #define X86_CPUID1_EDX_SSE      (1 << 25)
 /* CPUID feature bits in EBX and ECX when EAX=7, ECX=0 */
index 3c21df0688643bcb3f71b7da48b3afa86be9f652..f3b7e1957d0d85ee8c4fdc8a304fff2127e2c792 100644 (file)
@@ -193,6 +193,7 @@ static inline int ukarch_vaddr_range_isvalid(__vaddr_t start, __vaddr_t end)
 #define PAGE_ATTR_PROT_READ            0x01 /* Page is readable */
 #define PAGE_ATTR_PROT_WRITE           0x02 /* Page is writeable */
 #define PAGE_ATTR_PROT_EXEC            0x04 /* Page is executable */
+#define PAGE_ATTR_WRITECOMBINE         0x08 /* Page allows write-combining */
 
 /* Page fault error code bits */
 #define X86_PF_EC_P                    0x0001UL /* 0=non-present, 1=prot */
index 31c4dba5875144d30fbef09520601df96f54298f..04f6ee4477a1b9f788ca52d9201c36fa1b7b8b48 100644 (file)
@@ -38,6 +38,7 @@
 #include <uk/arch/limits.h>
 #include <uk/essentials.h>
 #include <uk/plat/paging.h>
+#include <uk/plat/common/cpu.h>
 #include <uk/fallocbuddy.h>
 #include <uk/print.h>
 
@@ -101,13 +102,15 @@ pgarch_pte_create(__paddr_t paddr, unsigned long attr, unsigned int level,
        if (!(attr & PAGE_ATTR_PROT_EXEC))
                pte |= X86_PTE_NX;
 
+       if (attr & PAGE_ATTR_WRITECOMBINE) {
+               pte |= X86_PTE_PCD;
+               pte |= X86_PTE_PWT;
+       }
+
        /* Take all other bits from template */
        pte |= template & (X86_PTE_US |
-                          X86_PTE_PWT |
-                          X86_PTE_PCD |
                           X86_PTE_ACCESSED |
                           X86_PTE_DIRTY |
-                          X86_PTE_PAT(level) |
                           X86_PTE_GLOBAL |
                           X86_PTE_USER1_MASK |
                           X86_PTE_USER2_MASK |
@@ -120,7 +123,7 @@ static inline __pte_t
 pgarch_pte_change_attr(__pte_t pte, unsigned long new_attr,
                       unsigned int level __unused)
 {
-       pte &= ~(X86_PTE_RW | X86_PTE_NX);
+       pte &= ~(X86_PTE_RW | X86_PTE_NX | X86_PTE_PCD | X86_PTE_PWT);
 
        if (new_attr & PAGE_ATTR_PROT_WRITE)
                pte |= X86_PTE_RW;
@@ -128,6 +131,11 @@ pgarch_pte_change_attr(__pte_t pte, unsigned long new_attr,
        if (!(new_attr & PAGE_ATTR_PROT_EXEC))
                pte |= X86_PTE_NX;
 
+       if (new_attr & PAGE_ATTR_WRITECOMBINE) {
+               pte |= X86_PTE_PCD;
+               pte |= X86_PTE_PWT;
+       }
+
        return pte;
 }
 
@@ -142,6 +150,9 @@ pgarch_attr_from_pte(__pte_t pte, unsigned int level __unused)
        if (!(pte & X86_PTE_NX))
                attr |= PAGE_ATTR_PROT_EXEC;
 
+       if ((pte & X86_PTE_PWT) && (pte & X86_PTE_PCD))
+               attr |= PAGE_ATTR_WRITECOMBINE;
+
        return attr;
 }
 
@@ -171,13 +182,16 @@ pgarch_pt_pte_create(struct uk_pagetable *pt __unused, __paddr_t pt_paddr,
         */
        pt_pte |= (X86_PTE_PRESENT | X86_PTE_RW);
 
+       /* Do not use the PWT/PCD bits for the PT PTEs. We only use them for
+        * page PTEs
+        */
+       pt_pte &= ~(X86_PTE_PWT | X86_PTE_PCD);
+
        /* Take all other bits from template. We also keep the flags that are
         * ignored by the architecture. The caller might have stored custom
         * data in these fields
         */
        pt_pte |= template & (X86_PTE_US |
-                             X86_PTE_PWT |
-                             X86_PTE_PCD |
                              X86_PTE_ACCESSED |
                              X86_PTE_DIRTY | /* ignored */
                              X86_PTE_GLOBAL | /* ignored */
@@ -275,6 +289,15 @@ pgarch_init(void)
        }
 #endif /* PT_LEVELS == 5 */
 
+       /* Check for PAT support */
+       ukarch_x86_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
+       if (unlikely(!(edx & X86_CPUID1_EDX_PAT))) {
+               uk_pr_crit("Page table attributes are not supported.\n");
+               return -ENOTSUP;
+       }
+       /* Reset PAT to default value */
+       wrmsrl(X86_MSR_PAT, X86_PAT_DEFAULT);
+
        ukarch_x86_cpuid(0x80000008, 0, &eax, &ebx, &ecx, &edx);
 
        max_addr_bit = (eax & X86_PG_VADDR_MASK) >> X86_PG_VADDR_SHIFT;