2 * Paging lookup functions.
3 * NetWatch system management mode administration console
5 * Copyright 2009, Google Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
18 * * Neither the name of Google Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from
20 * this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <reg-k8-msr.h>
43 #define REG_CS_ATTRIB_L (1<<9)
44 #define PTE_PRESENT (1<<0)
45 #define PTE_LARGE (1<<7)
47 #define PTE_FOR(x) (((unsigned int)(x) >> 12) & 0x3FF)
48 #define PDE_FOR(x) ((unsigned int)(x) >> 22)
49 #define ADDR_12_MASK(x) ((unsigned int)(x) & ~((1 << 12) - 1))
51 /* Keep a memoized copy of the operating mode the CPU was in when we
52 * entered SMM, so we don't have to look it up every time.
55 static enum operating_mode mode;
57 void reset_operating_mode_memo() {
61 /* Check the saved state map to determine what mode we were in. */
63 void probe_operating_mode() {
66 if (state_get_type() == SMM_TYPE_64) {
67 /* This is a 64-bit processor, so we may be in 64-bit
68 * full or compatibility mode. Check if we are. */
70 uint64_t efer = state_get_reg(STATE_REG_EFER);
72 if (efer & EFER_MSR_LMA) {
73 /* We are in long mode. Is this full 64-bit, or
74 * comatibility mode? Check the "L" bit of the
75 * saved CS descriptor to be sure. */
77 if (state_get_reg(STATE_REG_CS_ATTRIB)
86 /* Otherwise, we are in legacy mode, so do the normal
90 /* Either we are on a 32-bit processor, or we are on a 64-bit
91 * processor in legacy mode. */
93 if (state_get_reg(STATE_REG_EFLAGS) & EFLAGS_VM) {
98 cr0 = state_get_reg(STATE_REG_CR0);
102 mode = PROTECTED_PAGING;
104 mode = PROTECTED_NOPAGING;
109 enum operating_mode get_operating_mode() {
111 probe_operating_mode();
116 #define LONG_ADDR_MASK 0x000FFFFFFFFFF000
117 #define PAGE_1G_MASK 0x000FFFFFC0000000
118 #define PAGE_2M_MASK 0x000FFFFFFFE00000
120 #define LONG_ADDR_SECTION(addr, offset) ((((addr) >> (offset)) & 0x1FF) * 8)
122 #define READ_PHYS_QWORD(pa) ({ uint64_t * p = p2v(pa); if (!p) return 0; *p; })
124 /* Given a virtual address from the current CPU context, determine what the
125 * actual corresponding physical address would be, then convert that back
126 * to a virtual address suitable for use within NetWatch.
128 * If the given address is not mapped in to RAM or is mapped to RAM which
129 * cannot be accessed, returns null.
131 * XXX: This currently handles both long and 32-bit modes, but only knows
132 * how to parse standard 4-kbyte pages. It assumes all segments span the full
133 * 32-bit address space. Thus, it will return correct results for most
134 * userspace environments in most sane OS kernels, but not necessarily kernel
135 * space (likely to be mapped with large pages) or anything that plays tricks
136 * with segmentation (like NaCl).
139 uint64_t demap_phys (uint64_t vaddr) {
141 uint64_t pa = state_get_reg(STATE_REG_CR3) & LONG_ADDR_MASK;
145 probe_operating_mode();
147 outputf("demapping %08x %08x m %d", (uint32_t)(vaddr>>32), (uint32_t)vaddr, mode);
152 entry = READ_PHYS_QWORD(pa + LONG_ADDR_SECTION(vaddr, 39));
153 if (!(entry & PTE_PRESENT)) return 0;
154 pa = entry & LONG_ADDR_MASK;
157 entry = READ_PHYS_QWORD(pa + LONG_ADDR_SECTION(vaddr, 30));
158 if (!(entry & PTE_PRESENT)) return 0;
159 pa = entry & LONG_ADDR_MASK;
161 if (entry & PTE_LARGE)
162 return (entry & PAGE_1G_MASK) + (vaddr & 0x3FFFFFFF);
165 entry = READ_PHYS_QWORD(pa + LONG_ADDR_SECTION(vaddr, 21));
166 if (!(entry & PTE_PRESENT)) return 0;
167 pa = entry & LONG_ADDR_MASK;
169 if (entry & PTE_LARGE)
170 return (entry & PAGE_2M_MASK) + (vaddr & 0x1FFFFF);
173 entry = READ_PHYS_QWORD(pa + LONG_ADDR_SECTION(vaddr, 12));
174 if (!(entry & PTE_PRESENT)) return 0;
175 pa = entry & LONG_ADDR_MASK;
177 return pa + (vaddr & 0xFFF);
179 case PROTECTED_NOPAGING:
184 unsigned long pde = ((unsigned long *)p2v(pa))[PDE_FOR(vaddr)];
187 if (!(pde & PTE_PRESENT)) return 0;
188 pte = ((unsigned long *)p2v(ADDR_12_MASK(pde)))[PTE_FOR(vaddr)];
189 if (!(pte & PTE_PRESENT)) return 0;
191 return (pte & ~0xFFF) + (vaddr & 0xFFF);
196 void *demap(uint64_t vaddr) {
197 uint64_t paddr = demap_phys(vaddr);
198 outputf("demap: paddr 0x%08x %08x", (uint32_t)(paddr>>32), (uint32_t)paddr);
199 if (!paddr) return 0;