1 /* 2 * S390x MMU related functions 3 * 4 * Copyright (c) 2011 Alexander Graf 5 * Copyright (c) 2015 Thomas Huth, IBM Corporation 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18 #include "qemu/osdep.h" 19 #include "qemu/error-report.h" 20 #include "exec/address-spaces.h" 21 #include "cpu.h" 22 #include "sysemu/kvm.h" 23 #include "trace.h" 24 #include "hw/s390x/storage-keys.h" 25 26 /* #define DEBUG_S390 */ 27 /* #define DEBUG_S390_PTE */ 28 /* #define DEBUG_S390_STDOUT */ 29 30 #ifdef DEBUG_S390 31 #ifdef DEBUG_S390_STDOUT 32 #define DPRINTF(fmt, ...) \ 33 do { fprintf(stderr, fmt, ## __VA_ARGS__); \ 34 if (qemu_log_separate()) qemu_log(fmt, ##__VA_ARGS__); } while (0) 35 #else 36 #define DPRINTF(fmt, ...) \ 37 do { qemu_log(fmt, ## __VA_ARGS__); } while (0) 38 #endif 39 #else 40 #define DPRINTF(fmt, ...) \ 41 do { } while (0) 42 #endif 43 44 #ifdef DEBUG_S390_PTE 45 #define PTE_DPRINTF DPRINTF 46 #else 47 #define PTE_DPRINTF(fmt, ...) \ 48 do { } while (0) 49 #endif 50 51 /* Fetch/store bits in the translation exception code: */ 52 #define FS_READ 0x800 53 #define FS_WRITE 0x400 54 55 static void trigger_access_exception(CPUS390XState *env, uint32_t type, 56 uint32_t ilen, uint64_t tec) 57 { 58 S390CPU *cpu = s390_env_get_cpu(env); 59 60 if (kvm_enabled()) { 61 kvm_s390_access_exception(cpu, type, tec); 62 } else { 63 CPUState *cs = CPU(cpu); 64 stq_phys(cs->as, env->psa + offsetof(LowCore, trans_exc_code), tec); 65 trigger_pgm_exception(env, type, ilen); 66 } 67 } 68 69 static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, 70 uint64_t asc, int rw, bool exc) 71 { 72 uint64_t tec; 73 74 tec = vaddr | (rw == MMU_DATA_STORE ? FS_WRITE : FS_READ) | 4 | asc >> 46; 75 76 DPRINTF("%s: trans_exc_code=%016" PRIx64 "\n", __func__, tec); 77 78 if (!exc) { 79 return; 80 } 81 82 trigger_access_exception(env, PGM_PROTECTION, ILEN_LATER_INC, tec); 83 } 84 85 static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, 86 uint32_t type, uint64_t asc, int rw, bool exc) 87 { 88 int ilen = ILEN_LATER; 89 uint64_t tec; 90 91 tec = vaddr | (rw == MMU_DATA_STORE ? FS_WRITE : FS_READ) | asc >> 46; 92 93 DPRINTF("%s: trans_exc_code=%016" PRIx64 "\n", __func__, tec); 94 95 if (!exc) { 96 return; 97 } 98 99 /* Code accesses have an undefined ilc. */ 100 if (rw == MMU_INST_FETCH) { 101 ilen = 2; 102 } 103 104 trigger_access_exception(env, type, ilen, tec); 105 } 106 107 /** 108 * Translate real address to absolute (= physical) 109 * address by taking care of the prefix mapping. 110 */ 111 static target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr) 112 { 113 if (raddr < 0x2000) { 114 return raddr + env->psa; /* Map the lowcore. */ 115 } else if (raddr >= env->psa && raddr < env->psa + 0x2000) { 116 return raddr - env->psa; /* Map the 0 page. */ 117 } 118 return raddr; 119 } 120 121 /* Decode page table entry (normal 4KB page) */ 122 static int mmu_translate_pte(CPUS390XState *env, target_ulong vaddr, 123 uint64_t asc, uint64_t pt_entry, 124 target_ulong *raddr, int *flags, int rw, bool exc) 125 { 126 if (pt_entry & _PAGE_INVALID) { 127 DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __func__, pt_entry); 128 trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw, exc); 129 return -1; 130 } 131 if (pt_entry & _PAGE_RES0) { 132 trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw, exc); 133 return -1; 134 } 135 if (pt_entry & _PAGE_RO) { 136 *flags &= ~PAGE_WRITE; 137 } 138 139 *raddr = pt_entry & _ASCE_ORIGIN; 140 141 PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __func__, pt_entry); 142 143 return 0; 144 } 145 146 #define VADDR_PX 0xff000 /* Page index bits */ 147 148 /* Decode segment table entry */ 149 static int mmu_translate_segment(CPUS390XState *env, target_ulong vaddr, 150 uint64_t asc, uint64_t st_entry, 151 target_ulong *raddr, int *flags, int rw, 152 bool exc) 153 { 154 CPUState *cs = CPU(s390_env_get_cpu(env)); 155 uint64_t origin, offs, pt_entry; 156 157 if (st_entry & _SEGMENT_ENTRY_RO) { 158 *flags &= ~PAGE_WRITE; 159 } 160 161 if ((st_entry & _SEGMENT_ENTRY_FC) && (env->cregs[0] & CR0_EDAT)) { 162 /* Decode EDAT1 segment frame absolute address (1MB page) */ 163 *raddr = (st_entry & 0xfffffffffff00000ULL) | (vaddr & 0xfffff); 164 PTE_DPRINTF("%s: SEG=0x%" PRIx64 "\n", __func__, st_entry); 165 return 0; 166 } 167 168 /* Look up 4KB page entry */ 169 origin = st_entry & _SEGMENT_ENTRY_ORIGIN; 170 offs = (vaddr & VADDR_PX) >> 9; 171 pt_entry = ldq_phys(cs->as, origin + offs); 172 PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n", 173 __func__, origin, offs, pt_entry); 174 return mmu_translate_pte(env, vaddr, asc, pt_entry, raddr, flags, rw, exc); 175 } 176 177 /* Decode region table entries */ 178 static int mmu_translate_region(CPUS390XState *env, target_ulong vaddr, 179 uint64_t asc, uint64_t entry, int level, 180 target_ulong *raddr, int *flags, int rw, 181 bool exc) 182 { 183 CPUState *cs = CPU(s390_env_get_cpu(env)); 184 uint64_t origin, offs, new_entry; 185 const int pchks[4] = { 186 PGM_SEGMENT_TRANS, PGM_REG_THIRD_TRANS, 187 PGM_REG_SEC_TRANS, PGM_REG_FIRST_TRANS 188 }; 189 190 PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __func__, entry); 191 192 origin = entry & _REGION_ENTRY_ORIGIN; 193 offs = (vaddr >> (17 + 11 * level / 4)) & 0x3ff8; 194 195 new_entry = ldq_phys(cs->as, origin + offs); 196 PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n", 197 __func__, origin, offs, new_entry); 198 199 if ((new_entry & _REGION_ENTRY_INV) != 0) { 200 DPRINTF("%s: invalid region\n", __func__); 201 trigger_page_fault(env, vaddr, pchks[level / 4], asc, rw, exc); 202 return -1; 203 } 204 205 if ((new_entry & _REGION_ENTRY_TYPE_MASK) != level) { 206 trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw, exc); 207 return -1; 208 } 209 210 if (level == _ASCE_TYPE_SEGMENT) { 211 return mmu_translate_segment(env, vaddr, asc, new_entry, raddr, flags, 212 rw, exc); 213 } 214 215 /* Check region table offset and length */ 216 offs = (vaddr >> (28 + 11 * (level - 4) / 4)) & 3; 217 if (offs < ((new_entry & _REGION_ENTRY_TF) >> 6) 218 || offs > (new_entry & _REGION_ENTRY_LENGTH)) { 219 DPRINTF("%s: invalid offset or len (%lx)\n", __func__, new_entry); 220 trigger_page_fault(env, vaddr, pchks[level / 4 - 1], asc, rw, exc); 221 return -1; 222 } 223 224 if ((env->cregs[0] & CR0_EDAT) && (new_entry & _REGION_ENTRY_RO)) { 225 *flags &= ~PAGE_WRITE; 226 } 227 228 /* yet another region */ 229 return mmu_translate_region(env, vaddr, asc, new_entry, level - 4, 230 raddr, flags, rw, exc); 231 } 232 233 static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, 234 uint64_t asc, uint64_t asce, target_ulong *raddr, 235 int *flags, int rw, bool exc) 236 { 237 int level; 238 int r; 239 240 if (asce & _ASCE_REAL_SPACE) { 241 /* direct mapping */ 242 *raddr = vaddr; 243 return 0; 244 } 245 246 level = asce & _ASCE_TYPE_MASK; 247 switch (level) { 248 case _ASCE_TYPE_REGION1: 249 if ((vaddr >> 62) > (asce & _ASCE_TABLE_LENGTH)) { 250 trigger_page_fault(env, vaddr, PGM_REG_FIRST_TRANS, asc, rw, exc); 251 return -1; 252 } 253 break; 254 case _ASCE_TYPE_REGION2: 255 if (vaddr & 0xffe0000000000000ULL) { 256 DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 257 " 0xffe0000000000000ULL\n", __func__, vaddr); 258 trigger_page_fault(env, vaddr, PGM_ASCE_TYPE, asc, rw, exc); 259 return -1; 260 } 261 if ((vaddr >> 51 & 3) > (asce & _ASCE_TABLE_LENGTH)) { 262 trigger_page_fault(env, vaddr, PGM_REG_SEC_TRANS, asc, rw, exc); 263 return -1; 264 } 265 break; 266 case _ASCE_TYPE_REGION3: 267 if (vaddr & 0xfffffc0000000000ULL) { 268 DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 269 " 0xfffffc0000000000ULL\n", __func__, vaddr); 270 trigger_page_fault(env, vaddr, PGM_ASCE_TYPE, asc, rw, exc); 271 return -1; 272 } 273 if ((vaddr >> 40 & 3) > (asce & _ASCE_TABLE_LENGTH)) { 274 trigger_page_fault(env, vaddr, PGM_REG_THIRD_TRANS, asc, rw, exc); 275 return -1; 276 } 277 break; 278 case _ASCE_TYPE_SEGMENT: 279 if (vaddr & 0xffffffff80000000ULL) { 280 DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 281 " 0xffffffff80000000ULL\n", __func__, vaddr); 282 trigger_page_fault(env, vaddr, PGM_ASCE_TYPE, asc, rw, exc); 283 return -1; 284 } 285 if ((vaddr >> 29 & 3) > (asce & _ASCE_TABLE_LENGTH)) { 286 trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw, exc); 287 return -1; 288 } 289 break; 290 } 291 292 r = mmu_translate_region(env, vaddr, asc, asce, level, raddr, flags, rw, 293 exc); 294 if (rw == MMU_DATA_STORE && !(*flags & PAGE_WRITE)) { 295 trigger_prot_fault(env, vaddr, asc, rw, exc); 296 return -1; 297 } 298 299 return r; 300 } 301 302 /** 303 * Translate a virtual (logical) address into a physical (absolute) address. 304 * @param vaddr the virtual address 305 * @param rw 0 = read, 1 = write, 2 = code fetch 306 * @param asc address space control (one of the PSW_ASC_* modes) 307 * @param raddr the translated address is stored to this pointer 308 * @param flags the PAGE_READ/WRITE/EXEC flags are stored to this pointer 309 * @param exc true = inject a program check if a fault occurred 310 * @return 0 if the translation was successful, -1 if a fault occurred 311 */ 312 int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, 313 target_ulong *raddr, int *flags, bool exc) 314 { 315 static S390SKeysState *ss; 316 static S390SKeysClass *skeyclass; 317 int r = -1; 318 uint8_t key; 319 320 if (unlikely(!ss)) { 321 ss = s390_get_skeys_device(); 322 skeyclass = S390_SKEYS_GET_CLASS(ss); 323 } 324 325 *flags = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 326 vaddr &= TARGET_PAGE_MASK; 327 328 if (!(env->psw.mask & PSW_MASK_DAT)) { 329 *raddr = vaddr; 330 r = 0; 331 goto out; 332 } 333 334 switch (asc) { 335 case PSW_ASC_PRIMARY: 336 PTE_DPRINTF("%s: asc=primary\n", __func__); 337 r = mmu_translate_asce(env, vaddr, asc, env->cregs[1], raddr, flags, 338 rw, exc); 339 break; 340 case PSW_ASC_HOME: 341 PTE_DPRINTF("%s: asc=home\n", __func__); 342 r = mmu_translate_asce(env, vaddr, asc, env->cregs[13], raddr, flags, 343 rw, exc); 344 break; 345 case PSW_ASC_SECONDARY: 346 PTE_DPRINTF("%s: asc=secondary\n", __func__); 347 /* 348 * Instruction: Primary 349 * Data: Secondary 350 */ 351 if (rw == MMU_INST_FETCH) { 352 r = mmu_translate_asce(env, vaddr, PSW_ASC_PRIMARY, env->cregs[1], 353 raddr, flags, rw, exc); 354 *flags &= ~(PAGE_READ | PAGE_WRITE); 355 } else { 356 r = mmu_translate_asce(env, vaddr, PSW_ASC_SECONDARY, env->cregs[7], 357 raddr, flags, rw, exc); 358 *flags &= ~(PAGE_EXEC); 359 } 360 break; 361 case PSW_ASC_ACCREG: 362 default: 363 hw_error("guest switched to unknown asc mode\n"); 364 break; 365 } 366 367 out: 368 /* Convert real address -> absolute address */ 369 *raddr = mmu_real2abs(env, *raddr); 370 371 if (r == 0 && *raddr < ram_size) { 372 if (skeyclass->get_skeys(ss, *raddr / TARGET_PAGE_SIZE, 1, &key)) { 373 trace_get_skeys_nonzero(r); 374 return 0; 375 } 376 377 if (*flags & PAGE_READ) { 378 key |= SK_R; 379 } 380 381 if (*flags & PAGE_WRITE) { 382 key |= SK_C; 383 } 384 385 if (skeyclass->set_skeys(ss, *raddr / TARGET_PAGE_SIZE, 1, &key)) { 386 trace_set_skeys_nonzero(r); 387 return 0; 388 } 389 } 390 391 return r; 392 } 393 394 /** 395 * lowprot_enabled: Check whether low-address protection is enabled 396 */ 397 static bool lowprot_enabled(const CPUS390XState *env) 398 { 399 if (!(env->cregs[0] & CR0_LOWPROT)) { 400 return false; 401 } 402 if (!(env->psw.mask & PSW_MASK_DAT)) { 403 return true; 404 } 405 406 /* Check the private-space control bit */ 407 switch (env->psw.mask & PSW_MASK_ASC) { 408 case PSW_ASC_PRIMARY: 409 return !(env->cregs[1] & _ASCE_PRIVATE_SPACE); 410 case PSW_ASC_SECONDARY: 411 return !(env->cregs[7] & _ASCE_PRIVATE_SPACE); 412 case PSW_ASC_HOME: 413 return !(env->cregs[13] & _ASCE_PRIVATE_SPACE); 414 default: 415 /* We don't support access register mode */ 416 error_report("unsupported addressing mode"); 417 exit(1); 418 } 419 } 420 421 /** 422 * translate_pages: Translate a set of consecutive logical page addresses 423 * to absolute addresses 424 */ 425 static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages, 426 target_ulong *pages, bool is_write) 427 { 428 bool lowprot = is_write && lowprot_enabled(&cpu->env); 429 uint64_t asc = cpu->env.psw.mask & PSW_MASK_ASC; 430 CPUS390XState *env = &cpu->env; 431 int ret, i, pflags; 432 433 for (i = 0; i < nr_pages; i++) { 434 /* Low-address protection? */ 435 if (lowprot && (addr < 512 || (addr >= 4096 && addr < 4096 + 512))) { 436 trigger_access_exception(env, PGM_PROTECTION, ILEN_LATER_INC, 0); 437 return -EACCES; 438 } 439 ret = mmu_translate(env, addr, is_write, asc, &pages[i], &pflags, true); 440 if (ret) { 441 return ret; 442 } 443 if (!address_space_access_valid(&address_space_memory, pages[i], 444 TARGET_PAGE_SIZE, is_write)) { 445 program_interrupt(env, PGM_ADDRESSING, 0); 446 return -EFAULT; 447 } 448 addr += TARGET_PAGE_SIZE; 449 } 450 451 return 0; 452 } 453 454 /** 455 * s390_cpu_virt_mem_rw: 456 * @laddr: the logical start address 457 * @ar: the access register number 458 * @hostbuf: buffer in host memory. NULL = do only checks w/o copying 459 * @len: length that should be transferred 460 * @is_write: true = write, false = read 461 * Returns: 0 on success, non-zero if an exception occurred 462 * 463 * Copy from/to guest memory using logical addresses. Note that we inject a 464 * program interrupt in case there is an error while accessing the memory. 465 */ 466 int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf, 467 int len, bool is_write) 468 { 469 int currlen, nr_pages, i; 470 target_ulong *pages; 471 int ret; 472 473 if (kvm_enabled()) { 474 ret = kvm_s390_mem_op(cpu, laddr, ar, hostbuf, len, is_write); 475 if (ret >= 0) { 476 return ret; 477 } 478 } 479 480 nr_pages = (((laddr & ~TARGET_PAGE_MASK) + len - 1) >> TARGET_PAGE_BITS) 481 + 1; 482 pages = g_malloc(nr_pages * sizeof(*pages)); 483 484 ret = translate_pages(cpu, laddr, nr_pages, pages, is_write); 485 if (ret == 0 && hostbuf != NULL) { 486 /* Copy data by stepping through the area page by page */ 487 for (i = 0; i < nr_pages; i++) { 488 currlen = MIN(len, TARGET_PAGE_SIZE - (laddr % TARGET_PAGE_SIZE)); 489 cpu_physical_memory_rw(pages[i] | (laddr & ~TARGET_PAGE_MASK), 490 hostbuf, currlen, is_write); 491 laddr += currlen; 492 hostbuf += currlen; 493 len -= currlen; 494 } 495 } 496 497 g_free(pages); 498 return ret; 499 } 500