| 1 |
/*
|
| 2 |
* Copyright (c) 2007, 2008 University of Tsukuba
|
| 3 |
* All rights reserved.
|
| 4 |
*
|
| 5 |
* Redistribution and use in source and binary forms, with or without
|
| 6 |
* modification, are permitted provided that the following conditions are met:
|
| 7 |
*
|
| 8 |
* 1. Redistributions of source code must retain the above copyright notice,
|
| 9 |
* this list of conditions and the following disclaimer.
|
| 10 |
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
* this list of conditions and the following disclaimer in the documentation
|
| 12 |
* and/or other materials provided with the distribution.
|
| 13 |
* 3. Neither the name of the University of Tsukuba nor the names of its
|
| 14 |
* contributors may be used to endorse or promote products derived from
|
| 15 |
* this software without specific prior written permission.
|
| 16 |
*
|
| 17 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
* POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
*/
|
| 29 |
/*
|
| 30 |
* Copyright (c) 2010-2012 Yuichi Watanabe
|
| 31 |
*/
|
| 32 |
|
| 33 |
#include <core/assert.h>
|
| 34 |
#include <core/string.h>
|
| 35 |
#include <core/mm.h>
|
| 36 |
#include <core/printf.h>
|
| 37 |
#include "constants.h"
|
| 38 |
#include "cpu_mmu.h"
|
| 39 |
#include "current.h"
|
| 40 |
#include "mm.h"
|
| 41 |
#include "msr_pass.h"
|
| 42 |
#include "panic.h"
|
| 43 |
|
| 44 |
#define USER_MODE()\
|
| 45 |
seg_user_mode();
|
| 46 |
|
| 47 |
struct get_pte_data {
|
| 48 |
unsigned int pg : 1; /* PG (Paging): CR0 bit 31 */
|
| 49 |
unsigned int wp : 1; /* WP (Write Protect): CR0 bit 16 */
|
| 50 |
unsigned int pse : 1; /* PSE (Page Size Extensions): CR4 bit 4 */
|
| 51 |
unsigned int pae : 1; /* PAE (Physical Address Extensions):CR4bit5 */
|
| 52 |
unsigned int lme : 1; /* LME (Long Mode Enable): MSR(EFER) bit 8 */
|
| 53 |
unsigned int nxe : 1; /* NXE (No-Execute Enable):MSR(EFER) bit 10 */
|
| 54 |
unsigned int write : 1; /* Write access. Set D bit if 1 */
|
| 55 |
unsigned int user : 1; /* User access */
|
| 56 |
unsigned int exec : 1; /* Execution */
|
| 57 |
};
|
| 58 |
|
| 59 |
static u64 reserved_bit_table[2][3][5] = {
|
| 60 |
/* NXE = 0 */
|
| 61 |
{
|
| 62 |
/* levels = 2 (32-bit, PAE = 0, PSE = 1) */
|
| 63 |
{
|
| 64 |
0x0000000000200000ULL, /* PDE, 4-MByte page */
|
| 65 |
0x0000000000000000ULL, /* PTE */
|
| 66 |
0x0000000000000000ULL, /* PDE, 4-KByte page */
|
| 67 |
0xFFFFFFFFFFFFFFFFULL, /* PDPTE */
|
| 68 |
0xFFFFFFFFFFFFFFFFULL, /* PML4E */
|
| 69 |
},
|
| 70 |
/* levels = 3 (32-bit, PAE = 1) */
|
| 71 |
{
|
| 72 |
0xFFFFFF00001FE000ULL, /* PDE, 2-MByte page */
|
| 73 |
0xFFFFFF0000000000ULL, /* PTE */
|
| 74 |
0xFFFFFF0000000000ULL, /* PDE, 4-KByte page */
|
| 75 |
0xFFFFFF00000001E6ULL, /* PDPTE */
|
| 76 |
0xFFFFFFFFFFFFFFFFULL, /* PML4E */
|
| 77 |
},
|
| 78 |
/* levels = 4 (64-bit) */
|
| 79 |
{
|
| 80 |
0x800FFF00001FE000ULL, /* PDE, 2-MByte page */
|
| 81 |
0x800FFF0000000000ULL, /* PTE */
|
| 82 |
0x800FFF0000000000ULL, /* PDE, 4-KByte page */
|
| 83 |
0x800FFF0000000000ULL, /* PDPTE */
|
| 84 |
0x800FFF0000000000ULL, /* PML4E */
|
| 85 |
},
|
| 86 |
},
|
| 87 |
/* NXE = 1 */
|
| 88 |
{
|
| 89 |
/* levels = 2 (32-bit, PAE = 0, PSE = 1) */
|
| 90 |
{
|
| 91 |
0x0000000000200000ULL, /* PDE, 4-MByte page */
|
| 92 |
0x0000000000000000ULL, /* PTE */
|
| 93 |
0x0000000000000000ULL, /* PDE, 4-KByte page */
|
| 94 |
0xFFFFFFFFFFFFFFFFULL, /* PDPTE */
|
| 95 |
0xFFFFFFFFFFFFFFFFULL, /* PML4E */
|
| 96 |
},
|
| 97 |
/* levels = 3 (32-bit, PAE = 1) */
|
| 98 |
{
|
| 99 |
0x7FFFFF00001FE000ULL, /* PDE, 2-MByte page */
|
| 100 |
0x7FFFFF0000000000ULL, /* PTE */
|
| 101 |
0x7FFFFF0000000000ULL, /* PDE, 4-KByte page */
|
| 102 |
0xFFFFFF00000001E6ULL, /* PDPTE */
|
| 103 |
0xFFFFFFFFFFFFFFFFULL, /* PML4E */
|
| 104 |
},
|
| 105 |
/* levels = 4 (64-bit) */
|
| 106 |
{
|
| 107 |
0x000FFF00001FE000ULL, /* PDE, 2-MByte page */
|
| 108 |
0x000FFF0000000000ULL, /* PTE */
|
| 109 |
0x000FFF0000000000ULL, /* PDE, 4-KByte page */
|
| 110 |
0x000FFF0000000000ULL, /* PDPTE */
|
| 111 |
0x000FFF0000000000ULL, /* PML4E */
|
| 112 |
},
|
| 113 |
},
|
| 114 |
};
|
| 115 |
|
| 116 |
static bool
|
| 117 |
test_pmap_entry_reserved_bit (u64 entry, int level, int levels,
|
| 118 |
struct get_pte_data d)
|
| 119 |
{
|
| 120 |
u64 mask;
|
| 121 |
|
| 122 |
if (!d.pae && !d.pse) /* PAE = 0, PSE = 0 */
|
| 123 |
return false; /* No reserved bits checked */
|
| 124 |
if (level == 2 && (entry & PDE_PS_BIT))
|
| 125 |
level = 0;
|
| 126 |
mask = reserved_bit_table[d.nxe][levels - 2][level];
|
| 127 |
ASSERT (mask != 0xFFFFFFFFFFFFFFFFULL);
|
| 128 |
if (entry & mask)
|
| 129 |
return true;
|
| 130 |
return false;
|
| 131 |
}
|
| 132 |
|
| 133 |
static bool
|
| 134 |
set_ad_bit (pmap_t *m, u64 entry, bool seta, bool setd)
|
| 135 |
{
|
| 136 |
if (entry & PDE_A_BIT)
|
| 137 |
seta = false;
|
| 138 |
if (entry & PDE_D_BIT)
|
| 139 |
setd = false;
|
| 140 |
if (seta || setd) {
|
| 141 |
if (seta)
|
| 142 |
entry |= PDE_A_BIT;
|
| 143 |
if (setd)
|
| 144 |
entry |= PDE_D_BIT;
|
| 145 |
return pmap_write (m, entry, 0xFFF);
|
| 146 |
} else {
|
| 147 |
return false;
|
| 148 |
}
|
| 149 |
}
|
| 150 |
|
| 151 |
/* simplify1: entries[0] & entries[1] are generated when paging is disabled */
|
| 152 |
/* simplify2: entries[2] (PDPTE) |= RW|US|A when 32-bit PAE */
|
| 153 |
/* simplify3: entries[1] (PDE) &= ~PS when PSE is disabled */
|
| 154 |
/* simplify : entries[] are 64-bit when PAE is disabled */
|
| 155 |
/* simplify : entries[0] (PTE) will be generated when it is in a large page */
|
| 156 |
static vmmerr_t
|
| 157 |
get_pte_sub (ulong virt, ulong cr3, struct get_pte_data d, u64 entries[5],
|
| 158 |
int *plevels)
|
| 159 |
{
|
| 160 |
pmap_t m;
|
| 161 |
int levels;
|
| 162 |
int i;
|
| 163 |
u64 entry;
|
| 164 |
vmmerr_t r;
|
| 165 |
|
| 166 |
if (!d.pg) {
|
| 167 |
/* Paging disabled */
|
| 168 |
/* simplify1 */
|
| 169 |
entries[0] = (virt & PTE_ADDR_MASK64) | PTE_P_BIT | PTE_RW_BIT
|
| 170 |
| PTE_US_BIT | PTE_A_BIT | PTE_D_BIT;
|
| 171 |
entries[1] = PDE_P_BIT | PDE_RW_BIT | PDE_US_BIT | PDE_A_BIT
|
| 172 |
| PDE_D_BIT | PDE_PS_BIT;
|
| 173 |
*plevels = 1;
|
| 174 |
return VMMERR_SUCCESS;
|
| 175 |
}
|
| 176 |
/* Paging enabled */
|
| 177 |
if (d.lme) {
|
| 178 |
d.pae = 1;
|
| 179 |
d.pse = 1;
|
| 180 |
levels = 4;
|
| 181 |
} else if (d.pae) {
|
| 182 |
d.pse = 1;
|
| 183 |
levels = 3;
|
| 184 |
} else {
|
| 185 |
levels = 2;
|
| 186 |
}
|
| 187 |
*plevels = levels;
|
| 188 |
pmap_open_guest (&m, cr3, levels, true);
|
| 189 |
pmap_setvirt (&m, virt, levels + 1);
|
| 190 |
entry = pmap_read (&m);
|
| 191 |
entry |= PDE_RW_BIT | PDE_US_BIT | PDE_A_BIT;
|
| 192 |
entries[levels] = entry;
|
| 193 |
for (i = levels; i >= 1; i--) {
|
| 194 |
pmap_setlevel (&m, i);
|
| 195 |
retry:
|
| 196 |
entry = pmap_read (&m);
|
| 197 |
if (!(entry & PDE_P_BIT))
|
| 198 |
goto ret_nopage;
|
| 199 |
if (test_pmap_entry_reserved_bit (entry, i, levels, d))
|
| 200 |
goto ret_reserved;
|
| 201 |
if (levels == 3 && i == 3) /* simplify2 */
|
| 202 |
entry |= PDE_RW_BIT | PDE_US_BIT | PDE_A_BIT;
|
| 203 |
if (!(entry & PDE_US_BIT) && d.user)
|
| 204 |
goto ret_noaccess;
|
| 205 |
if (!(entry & PDE_RW_BIT) && d.write && (d.wp || d.user))
|
| 206 |
goto ret_noaccess;
|
| 207 |
if ((entry & PDE_NX_BIT) && d.exec && d.nxe)
|
| 208 |
goto ret_noexec;
|
| 209 |
if (i == 2 && !d.pse) /* simplify3 */
|
| 210 |
entry &= ~(u64)PDE_PS_BIT;
|
| 211 |
if ((i == 2 && (entry & PDE_PS_BIT)) || i == 1) {
|
| 212 |
if (set_ad_bit (&m, entry, true, d.write))
|
| 213 |
goto retry;
|
| 214 |
} else {
|
| 215 |
if (set_ad_bit (&m, entry, true, false))
|
| 216 |
goto retry;
|
| 217 |
}
|
| 218 |
entries[i - 1] = entry;
|
| 219 |
}
|
| 220 |
r = VMMERR_SUCCESS;
|
| 221 |
ret:
|
| 222 |
pmap_close (&m);
|
| 223 |
return r;
|
| 224 |
ret_nopage:
|
| 225 |
r = VMMERR_PAGE_NOT_PRESENT;
|
| 226 |
goto ret;
|
| 227 |
ret_reserved:
|
| 228 |
r = VMMERR_PAGE_BAD_RESERVED_BIT;
|
| 229 |
goto ret;
|
| 230 |
ret_noaccess:
|
| 231 |
r = VMMERR_PAGE_NOT_ACCESSIBLE;
|
| 232 |
goto ret;
|
| 233 |
ret_noexec:
|
| 234 |
r = VMMERR_PAGE_NOT_EXECUTABLE;
|
| 235 |
goto ret;
|
| 236 |
}
|
| 237 |
|
| 238 |
vmmerr_t
|
| 239 |
mmu_get_pte (ulong virt, ulong cr0, ulong cr3, ulong cr4, u64 efer,
|
| 240 |
bool write, bool user, bool exec, u64 entries[5],
|
| 241 |
int *plevels)
|
| 242 |
{
|
| 243 |
struct get_pte_data d;
|
| 244 |
|
| 245 |
d.pg = !!(cr0 & CR0_PG_BIT);
|
| 246 |
d.wp = !!(cr0 & CR0_WP_BIT);
|
| 247 |
d.pse = !!(cr4 & CR4_PSE_BIT);
|
| 248 |
d.pae = !!(cr4 & CR4_PAE_BIT);
|
| 249 |
d.lme = !!(efer & MSR_IA32_EFER_LME_BIT);
|
| 250 |
d.nxe = !!(efer & MSR_IA32_EFER_NXE_BIT);
|
| 251 |
d.write = write;
|
| 252 |
d.user = user;
|
| 253 |
d.exec = exec;
|
| 254 |
return get_pte_sub (virt, cr3, d, entries, plevels);
|
| 255 |
}
|
| 256 |
|
| 257 |
static vmmerr_t
|
| 258 |
get_pte (ulong virt, bool wr, bool us, bool ex, u64 *pte)
|
| 259 |
{
|
| 260 |
int levels;
|
| 261 |
vmmerr_t r;
|
| 262 |
u64 entries[5];
|
| 263 |
u64 efer;
|
| 264 |
ulong cr0, cr3, cr4;
|
| 265 |
|
| 266 |
current->vmctl.read_control_reg (CONTROL_REG_CR0, &cr0);
|
| 267 |
current->vmctl.read_control_reg (CONTROL_REG_CR3, &cr3);
|
| 268 |
current->vmctl.read_control_reg (CONTROL_REG_CR4, &cr4);
|
| 269 |
current->vmctl.read_msr (MSR_IA32_EFER, &efer);
|
| 270 |
r = mmu_get_pte (virt, cr0, cr3, cr4, efer, wr, us, ex, entries,
|
| 271 |
&levels);
|
| 272 |
if (r == VMMERR_SUCCESS)
|
| 273 |
*pte = entries[0];
|
| 274 |
return r;
|
| 275 |
}
|
| 276 |
|
| 277 |
vmmerr_t
|
| 278 |
write_linearaddr_b (ulong linear, u8 data)
|
| 279 |
{
|
| 280 |
u64 pte;
|
| 281 |
bool us;
|
| 282 |
vmmerr_t err;
|
| 283 |
|
| 284 |
us = USER_MODE();
|
| 285 |
err = get_pte(linear, true, us, false, &pte);
|
| 286 |
if (err) {
|
| 287 |
mmu_generate_pagefault(err, true, us, linear);
|
| 288 |
return err;
|
| 289 |
}
|
| 290 |
write_gphys_b((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
|
| 291 |
msr_pte_to_cache_flag(pte));
|
| 292 |
return VMMERR_SUCCESS;
|
| 293 |
}
|
| 294 |
|
| 295 |
vmmerr_t
|
| 296 |
write_linearaddr_w (ulong linear, u16 data)
|
| 297 |
{
|
| 298 |
u64 pte;
|
| 299 |
bool us;
|
| 300 |
vmmerr_t err;
|
| 301 |
|
| 302 |
if ((linear & 0xFFF) == 0xFFF) {
|
| 303 |
RIE (write_linearaddr_b (linear, data));
|
| 304 |
RIE (write_linearaddr_b (linear + 1, data >> 8));
|
| 305 |
return VMMERR_SUCCESS;
|
| 306 |
}
|
| 307 |
|
| 308 |
us = USER_MODE();
|
| 309 |
err = get_pte(linear, true, us, false, &pte);
|
| 310 |
if (err) {
|
| 311 |
mmu_generate_pagefault(err, true, us, linear);
|
| 312 |
return err;
|
| 313 |
}
|
| 314 |
write_gphys_w ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
|
| 315 |
msr_pte_to_cache_flag(pte));
|
| 316 |
return VMMERR_SUCCESS;
|
| 317 |
}
|
| 318 |
|
| 319 |
vmmerr_t
|
| 320 |
write_linearaddr_l (ulong linear, u32 data)
|
| 321 |
{
|
| 322 |
u64 pte;
|
| 323 |
bool us;
|
| 324 |
vmmerr_t err;
|
| 325 |
|
| 326 |
if ((linear & 0xFFF) >= 0xFFD) {
|
| 327 |
RIE (write_linearaddr_w (linear, data));
|
| 328 |
RIE (write_linearaddr_w (linear + 2, data >> 16));
|
| 329 |
return VMMERR_SUCCESS;
|
| 330 |
}
|
| 331 |
us = USER_MODE();
|
| 332 |
err = get_pte(linear, true, us, false, &pte);
|
| 333 |
if (err) {
|
| 334 |
mmu_generate_pagefault(err, true, us, linear);
|
| 335 |
return err;
|
| 336 |
}
|
| 337 |
write_gphys_l ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
|
| 338 |
msr_pte_to_cache_flag(pte));
|
| 339 |
return VMMERR_SUCCESS;
|
| 340 |
}
|
| 341 |
|
| 342 |
vmmerr_t
|
| 343 |
write_linearaddr_q (ulong linear, u64 data)
|
| 344 |
{
|
| 345 |
u64 pte;
|
| 346 |
bool us;
|
| 347 |
vmmerr_t err;
|
| 348 |
|
| 349 |
if ((linear & 0xFFF) >= 0xFF9) {
|
| 350 |
RIE (write_linearaddr_l (linear, data));
|
| 351 |
RIE (write_linearaddr_l (linear + 4, data >> 32));
|
| 352 |
return VMMERR_SUCCESS;
|
| 353 |
}
|
| 354 |
us = USER_MODE();
|
| 355 |
err = get_pte(linear, true, us, false, &pte);
|
| 356 |
if (err) {
|
| 357 |
mmu_generate_pagefault(err, true, us, linear);
|
| 358 |
return err;
|
| 359 |
}
|
| 360 |
write_gphys_q ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
|
| 361 |
msr_pte_to_cache_flag(pte));
|
| 362 |
return VMMERR_SUCCESS;
|
| 363 |
}
|
| 364 |
|
| 365 |
vmmerr_t
|
| 366 |
read_linearaddr_b (ulong linear, void *data)
|
| 367 |
{
|
| 368 |
u64 pte;
|
| 369 |
bool us;
|
| 370 |
vmmerr_t err;
|
| 371 |
|
| 372 |
us = USER_MODE();
|
| 373 |
err = get_pte(linear, false, us, false /* FIXME */, &pte);
|
| 374 |
if (err) {
|
| 375 |
mmu_generate_pagefault(err, false, us, linear);
|
| 376 |
return err;
|
| 377 |
}
|
| 378 |
read_gphys_b ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
|
| 379 |
msr_pte_to_cache_flag(pte));
|
| 380 |
return VMMERR_SUCCESS;
|
| 381 |
}
|
| 382 |
|
| 383 |
vmmerr_t
|
| 384 |
read_linearaddr_w (ulong linear, void *data)
|
| 385 |
{
|
| 386 |
u64 pte;
|
| 387 |
bool us;
|
| 388 |
vmmerr_t err;
|
| 389 |
|
| 390 |
if ((linear & 0xFFF) == 0xFFF) {
|
| 391 |
RIE (read_linearaddr_b (linear, ((u8 *)data)));
|
| 392 |
RIE (read_linearaddr_b (linear + 1, ((u8 *)data + 1)));
|
| 393 |
return VMMERR_SUCCESS;
|
| 394 |
}
|
| 395 |
us = USER_MODE();
|
| 396 |
err = get_pte(linear, false, us, false /* FIXME */, &pte);
|
| 397 |
if (err) {
|
| 398 |
mmu_generate_pagefault(err, false, us, linear);
|
| 399 |
return err;
|
| 400 |
}
|
| 401 |
read_gphys_w ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
|
| 402 |
msr_pte_to_cache_flag(pte));
|
| 403 |
return VMMERR_SUCCESS;
|
| 404 |
}
|
| 405 |
|
| 406 |
vmmerr_t
|
| 407 |
read_linearaddr_l (ulong linear, void *data)
|
| 408 |
{
|
| 409 |
u64 pte;
|
| 410 |
bool us;
|
| 411 |
vmmerr_t err;
|
| 412 |
|
| 413 |
if ((linear & 0xFFF) >= 0xFFD) {
|
| 414 |
RIE (read_linearaddr_w (linear, ((u8 *)data)));
|
| 415 |
RIE (read_linearaddr_w (linear + 2, ((u8 *)data + 2)));
|
| 416 |
return VMMERR_SUCCESS;
|
| 417 |
}
|
| 418 |
us = USER_MODE();
|
| 419 |
err = get_pte(linear, false, us, false /* FIXME */, &pte);
|
| 420 |
if (err) {
|
| 421 |
mmu_generate_pagefault(err, false, us, linear);
|
| 422 |
return err;
|
| 423 |
}
|
| 424 |
read_gphys_l ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
|
| 425 |
msr_pte_to_cache_flag(pte));
|
| 426 |
return VMMERR_SUCCESS;
|
| 427 |
}
|
| 428 |
|
| 429 |
vmmerr_t
|
| 430 |
read_linearaddr_q (ulong linear, void *data)
|
| 431 |
{
|
| 432 |
u64 pte;
|
| 433 |
bool us;
|
| 434 |
vmmerr_t err;
|
| 435 |
|
| 436 |
if ((linear & 0xFFF) >= 0xFF9) {
|
| 437 |
RIE (read_linearaddr_l (linear, ((u8 *)data)));
|
| 438 |
RIE (read_linearaddr_l (linear + 4, ((u8 *)data + 4)));
|
| 439 |
return VMMERR_SUCCESS;
|
| 440 |
}
|
| 441 |
us = USER_MODE();
|
| 442 |
err = get_pte(linear, false, us, false /* FIXME */, &pte);
|
| 443 |
if (err) {
|
| 444 |
mmu_generate_pagefault(err, false, us, linear);
|
| 445 |
return err;
|
| 446 |
}
|
| 447 |
read_gphys_q ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
|
| 448 |
msr_pte_to_cache_flag(pte));
|
| 449 |
return VMMERR_SUCCESS;
|
| 450 |
}
|
| 451 |
|
| 452 |
/* access a TSS during a task switch */
|
| 453 |
/* According to the manual, a processor uses contiguous physical addresses */
|
| 454 |
/* to access a TSS during a task switch */
|
| 455 |
vmmerr_t
|
| 456 |
read_linearaddr_tss (ulong linear, void *tss, uint len)
|
| 457 |
{
|
| 458 |
u64 pte;
|
| 459 |
void *p;
|
| 460 |
|
| 461 |
RIE (get_pte (linear, false, false, false, &pte));
|
| 462 |
p = mapmem_gphys ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), len, 0);
|
| 463 |
if (!p)
|
| 464 |
return VMMERR_NOMEM;
|
| 465 |
memcpy (tss, p, len);
|
| 466 |
unmapmem (p, len);
|
| 467 |
return VMMERR_SUCCESS;
|
| 468 |
}
|
| 469 |
|
| 470 |
vmmerr_t
|
| 471 |
write_linearaddr_tss (ulong linear, void *tss, uint len)
|
| 472 |
{
|
| 473 |
u64 pte;
|
| 474 |
void *p;
|
| 475 |
|
| 476 |
RIE (get_pte (linear, true, false, false, &pte));
|
| 477 |
p = mapmem_gphys ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), len,
|
| 478 |
MAPMEM_WRITE);
|
| 479 |
if (!p)
|
| 480 |
return VMMERR_NOMEM;
|
| 481 |
memcpy (p, tss, len);
|
| 482 |
unmapmem (p, len);
|
| 483 |
return VMMERR_SUCCESS;
|
| 484 |
}
|
| 485 |
|
| 486 |
void
|
| 487 |
mmu_generate_pagefault(vmmerr_t vmmerr, bool wr, bool us, ulong cr2)
|
| 488 |
{
|
| 489 |
u32 err = 0;
|
| 490 |
|
| 491 |
switch (vmmerr) {
|
| 492 |
case VMMERR_PAGE_NOT_PRESENT:
|
| 493 |
break;
|
| 494 |
case VMMERR_PAGE_NOT_ACCESSIBLE:
|
| 495 |
err = PAGEFAULT_ERR_P_BIT;
|
| 496 |
break;
|
| 497 |
case VMMERR_PAGE_BAD_RESERVED_BIT:
|
| 498 |
err = PAGEFAULT_ERR_P_BIT | PAGEFAULT_ERR_RSVD_BIT;
|
| 499 |
break;
|
| 500 |
case VMMERR_PAGE_NOT_EXECUTABLE:
|
| 501 |
err = PAGEFAULT_ERR_P_BIT | PAGEFAULT_ERR_ID_BIT;
|
| 502 |
break;
|
| 503 |
default:
|
| 504 |
panic("mmu_generate_pagefault: Unknown vmmerr. 0x%x", vmmerr);
|
| 505 |
}
|
| 506 |
if (wr) {
|
| 507 |
err |= PAGEFAULT_ERR_WR_BIT;
|
| 508 |
}
|
| 509 |
if (us) {
|
| 510 |
err |= PAGEFAULT_ERR_US_BIT;
|
| 511 |
}
|
| 512 |
current->vmctl.generate_pagefault (err, cr2);
|
| 513 |
}
|