1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11 /* This file is dual-licensed; see usr/src/contrib/bhyve/LICENSE */
12
13 /*
14 * Copyright 2019 Joyent, Inc.
15 * Copyright 2025 Oxide Computer Company
16 */
17
18 #include <sys/vmm_gpt_impl.h>
19
20 static inline uint64_t
rvi_prot(uint_t prot)21 rvi_prot(uint_t prot)
22 {
23 uint64_t bits;
24
25 bits = 0;
26 if ((prot & PROT_WRITE) != 0)
27 bits |= PT_WRITABLE;
28 if ((prot & PROT_EXEC) == 0)
29 bits |= PT_NX;
30
31 return (bits);
32 }
33
34 /* Make sure that PAT indexes line up as expected */
35 CTASSERT((PAT_DEFAULT_ATTRIBUTE & 0xf) == MTRR_TYPE_WB);
36 CTASSERT(((PAT_DEFAULT_ATTRIBUTE >> 24) & 0xf) == MTRR_TYPE_UC);
37
38 static inline uint64_t
rvi_attr_to_pat(uint8_t attr)39 rvi_attr_to_pat(uint8_t attr)
40 {
41 if (attr == MTRR_TYPE_UC)
42 return (PT_NOCACHE | PT_WRITETHRU);
43 if (attr == MTRR_TYPE_WB)
44 return (0);
45
46 panic("unexpected memattr %x", attr);
47 }
48
49 static uint64_t
rvi_map_table(uint64_t pfn)50 rvi_map_table(uint64_t pfn)
51 {
52 const uint64_t paddr = pfn_to_pa(pfn);
53 const uint64_t flags = PT_USER | PT_REF | PT_VALID;
54 const uint64_t pat = rvi_attr_to_pat(MTRR_TYPE_WB);
55 const uint64_t rprot = PT_WRITABLE;
56 return (paddr | flags | pat | rprot);
57 }
58
59 static uint64_t
rvi_map_page(uint64_t pfn,uint_t prot,uint8_t attr)60 rvi_map_page(uint64_t pfn, uint_t prot, uint8_t attr)
61 {
62 const uint64_t paddr = pfn_to_pa(pfn);
63 const uint64_t flags = PT_USER | PT_REF | PT_VALID;
64 const uint64_t pat = rvi_attr_to_pat(attr);
65 const uint64_t rprot = rvi_prot(prot);
66 return (paddr | flags | pat | rprot);
67 }
68
69 static bool
rvi_pte_parse(uint64_t pte,pfn_t * pfnp,uint_t * protp)70 rvi_pte_parse(uint64_t pte, pfn_t *pfnp, uint_t *protp)
71 {
72 if ((pte & PT_VALID) == 0) {
73 return (false);
74 }
75
76 uint_t prot = PROT_READ;
77 if ((pte & PT_NX) == 0)
78 prot |= PROT_EXEC;
79 if ((pte & PT_WRITABLE) != 0)
80 prot |= PROT_WRITE;
81
82 if (pfnp != NULL) {
83 *pfnp = (pte & PT_PADDR) >> PAGESHIFT;
84 }
85 if (protp != NULL) {
86 *protp = prot;
87 }
88 return (true);
89 }
90
91 static uint64_t
rvi_get_pmtp(pfn_t root_pfn,bool track_dirty)92 rvi_get_pmtp(pfn_t root_pfn, bool track_dirty)
93 {
94 return (root_pfn << PAGESHIFT);
95 }
96
97 static bool
rvi_hw_ad_supported(void)98 rvi_hw_ad_supported(void)
99 {
100 return (true);
101 }
102
103 const struct vmm_pte_impl rvi_pte_impl = {
104 .vpi_map_table = rvi_map_table,
105 .vpi_map_page = rvi_map_page,
106 .vpi_pte_parse = rvi_pte_parse,
107 .vpi_bit_accessed = PT_REF,
108 .vpi_bit_dirty = PT_MOD,
109
110 .vpi_get_pmtp = rvi_get_pmtp,
111 .vpi_hw_ad_supported = rvi_hw_ad_supported,
112 };
113