1*3fa2d384SViktor Prutyanov /* 2*3fa2d384SViktor Prutyanov * Copyright (c) 2018 Virtuozzo International GmbH 3*3fa2d384SViktor Prutyanov * 4*3fa2d384SViktor Prutyanov * This work is licensed under the terms of the GNU GPL, version 2 or later. 5*3fa2d384SViktor Prutyanov * 6*3fa2d384SViktor Prutyanov */ 7*3fa2d384SViktor Prutyanov 8*3fa2d384SViktor Prutyanov #include "qemu/osdep.h" 9*3fa2d384SViktor Prutyanov #include "addrspace.h" 10*3fa2d384SViktor Prutyanov 11*3fa2d384SViktor Prutyanov static struct pa_block *pa_space_find_block(struct pa_space *ps, uint64_t pa) 12*3fa2d384SViktor Prutyanov { 13*3fa2d384SViktor Prutyanov size_t i; 14*3fa2d384SViktor Prutyanov for (i = 0; i < ps->block_nr; i++) { 15*3fa2d384SViktor Prutyanov if (ps->block[i].paddr <= pa && 16*3fa2d384SViktor Prutyanov pa <= ps->block[i].paddr + ps->block[i].size) { 17*3fa2d384SViktor Prutyanov return ps->block + i; 18*3fa2d384SViktor Prutyanov } 19*3fa2d384SViktor Prutyanov } 20*3fa2d384SViktor Prutyanov 21*3fa2d384SViktor Prutyanov return NULL; 22*3fa2d384SViktor Prutyanov } 23*3fa2d384SViktor Prutyanov 24*3fa2d384SViktor Prutyanov static uint8_t *pa_space_resolve(struct pa_space *ps, uint64_t pa) 25*3fa2d384SViktor Prutyanov { 26*3fa2d384SViktor Prutyanov struct pa_block *block = pa_space_find_block(ps, pa); 27*3fa2d384SViktor Prutyanov 28*3fa2d384SViktor Prutyanov if (!block) { 29*3fa2d384SViktor Prutyanov return NULL; 30*3fa2d384SViktor Prutyanov } 31*3fa2d384SViktor Prutyanov 32*3fa2d384SViktor Prutyanov return block->addr + (pa - block->paddr); 33*3fa2d384SViktor Prutyanov } 34*3fa2d384SViktor Prutyanov 35*3fa2d384SViktor Prutyanov int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf) 36*3fa2d384SViktor Prutyanov { 37*3fa2d384SViktor Prutyanov Elf64_Half phdr_nr = elf_getphdrnum(qemu_elf->map); 38*3fa2d384SViktor Prutyanov Elf64_Phdr *phdr = elf64_getphdr(qemu_elf->map); 39*3fa2d384SViktor Prutyanov size_t block_i = 0; 40*3fa2d384SViktor Prutyanov size_t i; 41*3fa2d384SViktor Prutyanov 42*3fa2d384SViktor Prutyanov ps->block_nr = 0; 43*3fa2d384SViktor Prutyanov 44*3fa2d384SViktor Prutyanov for (i = 0; i < phdr_nr; i++) { 45*3fa2d384SViktor Prutyanov if (phdr[i].p_type == PT_LOAD) { 46*3fa2d384SViktor Prutyanov ps->block_nr++; 47*3fa2d384SViktor Prutyanov } 48*3fa2d384SViktor Prutyanov } 49*3fa2d384SViktor Prutyanov 50*3fa2d384SViktor Prutyanov ps->block = malloc(sizeof(*ps->block) * ps->block_nr); 51*3fa2d384SViktor Prutyanov if (!ps->block) { 52*3fa2d384SViktor Prutyanov return 1; 53*3fa2d384SViktor Prutyanov } 54*3fa2d384SViktor Prutyanov 55*3fa2d384SViktor Prutyanov for (i = 0; i < phdr_nr; i++) { 56*3fa2d384SViktor Prutyanov if (phdr[i].p_type == PT_LOAD) { 57*3fa2d384SViktor Prutyanov ps->block[block_i] = (struct pa_block) { 58*3fa2d384SViktor Prutyanov .addr = (uint8_t *)qemu_elf->map + phdr[i].p_offset, 59*3fa2d384SViktor Prutyanov .paddr = phdr[i].p_paddr, 60*3fa2d384SViktor Prutyanov .size = phdr[i].p_filesz, 61*3fa2d384SViktor Prutyanov }; 62*3fa2d384SViktor Prutyanov block_i++; 63*3fa2d384SViktor Prutyanov } 64*3fa2d384SViktor Prutyanov } 65*3fa2d384SViktor Prutyanov 66*3fa2d384SViktor Prutyanov return 0; 67*3fa2d384SViktor Prutyanov } 68*3fa2d384SViktor Prutyanov 69*3fa2d384SViktor Prutyanov void pa_space_destroy(struct pa_space *ps) 70*3fa2d384SViktor Prutyanov { 71*3fa2d384SViktor Prutyanov ps->block_nr = 0; 72*3fa2d384SViktor Prutyanov free(ps->block); 73*3fa2d384SViktor Prutyanov } 74*3fa2d384SViktor Prutyanov 75*3fa2d384SViktor Prutyanov void va_space_set_dtb(struct va_space *vs, uint64_t dtb) 76*3fa2d384SViktor Prutyanov { 77*3fa2d384SViktor Prutyanov vs->dtb = dtb & 0x00ffffffffff000; 78*3fa2d384SViktor Prutyanov } 79*3fa2d384SViktor Prutyanov 80*3fa2d384SViktor Prutyanov void va_space_create(struct va_space *vs, struct pa_space *ps, uint64_t dtb) 81*3fa2d384SViktor Prutyanov { 82*3fa2d384SViktor Prutyanov vs->ps = ps; 83*3fa2d384SViktor Prutyanov va_space_set_dtb(vs, dtb); 84*3fa2d384SViktor Prutyanov } 85*3fa2d384SViktor Prutyanov 86*3fa2d384SViktor Prutyanov static uint64_t get_pml4e(struct va_space *vs, uint64_t va) 87*3fa2d384SViktor Prutyanov { 88*3fa2d384SViktor Prutyanov uint64_t pa = (vs->dtb & 0xffffffffff000) | ((va & 0xff8000000000) >> 36); 89*3fa2d384SViktor Prutyanov 90*3fa2d384SViktor Prutyanov return *(uint64_t *)pa_space_resolve(vs->ps, pa); 91*3fa2d384SViktor Prutyanov } 92*3fa2d384SViktor Prutyanov 93*3fa2d384SViktor Prutyanov static uint64_t get_pdpi(struct va_space *vs, uint64_t va, uint64_t pml4e) 94*3fa2d384SViktor Prutyanov { 95*3fa2d384SViktor Prutyanov uint64_t pdpte_paddr = (pml4e & 0xffffffffff000) | 96*3fa2d384SViktor Prutyanov ((va & 0x7FC0000000) >> 27); 97*3fa2d384SViktor Prutyanov 98*3fa2d384SViktor Prutyanov return *(uint64_t *)pa_space_resolve(vs->ps, pdpte_paddr); 99*3fa2d384SViktor Prutyanov } 100*3fa2d384SViktor Prutyanov 101*3fa2d384SViktor Prutyanov static uint64_t pde_index(uint64_t va) 102*3fa2d384SViktor Prutyanov { 103*3fa2d384SViktor Prutyanov return (va >> 21) & 0x1FF; 104*3fa2d384SViktor Prutyanov } 105*3fa2d384SViktor Prutyanov 106*3fa2d384SViktor Prutyanov static uint64_t pdba_base(uint64_t pdpe) 107*3fa2d384SViktor Prutyanov { 108*3fa2d384SViktor Prutyanov return pdpe & 0xFFFFFFFFFF000; 109*3fa2d384SViktor Prutyanov } 110*3fa2d384SViktor Prutyanov 111*3fa2d384SViktor Prutyanov static uint64_t get_pgd(struct va_space *vs, uint64_t va, uint64_t pdpe) 112*3fa2d384SViktor Prutyanov { 113*3fa2d384SViktor Prutyanov uint64_t pgd_entry = pdba_base(pdpe) + pde_index(va) * 8; 114*3fa2d384SViktor Prutyanov 115*3fa2d384SViktor Prutyanov return *(uint64_t *)pa_space_resolve(vs->ps, pgd_entry); 116*3fa2d384SViktor Prutyanov } 117*3fa2d384SViktor Prutyanov 118*3fa2d384SViktor Prutyanov static uint64_t pte_index(uint64_t va) 119*3fa2d384SViktor Prutyanov { 120*3fa2d384SViktor Prutyanov return (va >> 12) & 0x1FF; 121*3fa2d384SViktor Prutyanov } 122*3fa2d384SViktor Prutyanov 123*3fa2d384SViktor Prutyanov static uint64_t ptba_base(uint64_t pde) 124*3fa2d384SViktor Prutyanov { 125*3fa2d384SViktor Prutyanov return pde & 0xFFFFFFFFFF000; 126*3fa2d384SViktor Prutyanov } 127*3fa2d384SViktor Prutyanov 128*3fa2d384SViktor Prutyanov static uint64_t get_pte(struct va_space *vs, uint64_t va, uint64_t pgd) 129*3fa2d384SViktor Prutyanov { 130*3fa2d384SViktor Prutyanov uint64_t pgd_val = ptba_base(pgd) + pte_index(va) * 8; 131*3fa2d384SViktor Prutyanov 132*3fa2d384SViktor Prutyanov return *(uint64_t *)pa_space_resolve(vs->ps, pgd_val); 133*3fa2d384SViktor Prutyanov } 134*3fa2d384SViktor Prutyanov 135*3fa2d384SViktor Prutyanov static uint64_t get_paddr(uint64_t va, uint64_t pte) 136*3fa2d384SViktor Prutyanov { 137*3fa2d384SViktor Prutyanov return (pte & 0xFFFFFFFFFF000) | (va & 0xFFF); 138*3fa2d384SViktor Prutyanov } 139*3fa2d384SViktor Prutyanov 140*3fa2d384SViktor Prutyanov static bool is_present(uint64_t entry) 141*3fa2d384SViktor Prutyanov { 142*3fa2d384SViktor Prutyanov return entry & 0x1; 143*3fa2d384SViktor Prutyanov } 144*3fa2d384SViktor Prutyanov 145*3fa2d384SViktor Prutyanov static bool page_size_flag(uint64_t entry) 146*3fa2d384SViktor Prutyanov { 147*3fa2d384SViktor Prutyanov return entry & (1 << 7); 148*3fa2d384SViktor Prutyanov } 149*3fa2d384SViktor Prutyanov 150*3fa2d384SViktor Prutyanov static uint64_t get_1GB_paddr(uint64_t va, uint64_t pdpte) 151*3fa2d384SViktor Prutyanov { 152*3fa2d384SViktor Prutyanov return (pdpte & 0xfffffc0000000) | (va & 0x3fffffff); 153*3fa2d384SViktor Prutyanov } 154*3fa2d384SViktor Prutyanov 155*3fa2d384SViktor Prutyanov static uint64_t get_2MB_paddr(uint64_t va, uint64_t pgd_entry) 156*3fa2d384SViktor Prutyanov { 157*3fa2d384SViktor Prutyanov return (pgd_entry & 0xfffffffe00000) | (va & 0x00000001fffff); 158*3fa2d384SViktor Prutyanov } 159*3fa2d384SViktor Prutyanov 160*3fa2d384SViktor Prutyanov static uint64_t va_space_va2pa(struct va_space *vs, uint64_t va) 161*3fa2d384SViktor Prutyanov { 162*3fa2d384SViktor Prutyanov uint64_t pml4e, pdpe, pgd, pte; 163*3fa2d384SViktor Prutyanov 164*3fa2d384SViktor Prutyanov pml4e = get_pml4e(vs, va); 165*3fa2d384SViktor Prutyanov if (!is_present(pml4e)) { 166*3fa2d384SViktor Prutyanov return INVALID_PA; 167*3fa2d384SViktor Prutyanov } 168*3fa2d384SViktor Prutyanov 169*3fa2d384SViktor Prutyanov pdpe = get_pdpi(vs, va, pml4e); 170*3fa2d384SViktor Prutyanov if (!is_present(pdpe)) { 171*3fa2d384SViktor Prutyanov return INVALID_PA; 172*3fa2d384SViktor Prutyanov } 173*3fa2d384SViktor Prutyanov 174*3fa2d384SViktor Prutyanov if (page_size_flag(pdpe)) { 175*3fa2d384SViktor Prutyanov return get_1GB_paddr(va, pdpe); 176*3fa2d384SViktor Prutyanov } 177*3fa2d384SViktor Prutyanov 178*3fa2d384SViktor Prutyanov pgd = get_pgd(vs, va, pdpe); 179*3fa2d384SViktor Prutyanov if (!is_present(pgd)) { 180*3fa2d384SViktor Prutyanov return INVALID_PA; 181*3fa2d384SViktor Prutyanov } 182*3fa2d384SViktor Prutyanov 183*3fa2d384SViktor Prutyanov if (page_size_flag(pgd)) { 184*3fa2d384SViktor Prutyanov return get_2MB_paddr(va, pgd); 185*3fa2d384SViktor Prutyanov } 186*3fa2d384SViktor Prutyanov 187*3fa2d384SViktor Prutyanov pte = get_pte(vs, va, pgd); 188*3fa2d384SViktor Prutyanov if (!is_present(pte)) { 189*3fa2d384SViktor Prutyanov return INVALID_PA; 190*3fa2d384SViktor Prutyanov } 191*3fa2d384SViktor Prutyanov 192*3fa2d384SViktor Prutyanov return get_paddr(va, pte); 193*3fa2d384SViktor Prutyanov } 194*3fa2d384SViktor Prutyanov 195*3fa2d384SViktor Prutyanov void *va_space_resolve(struct va_space *vs, uint64_t va) 196*3fa2d384SViktor Prutyanov { 197*3fa2d384SViktor Prutyanov uint64_t pa = va_space_va2pa(vs, va); 198*3fa2d384SViktor Prutyanov 199*3fa2d384SViktor Prutyanov if (pa == INVALID_PA) { 200*3fa2d384SViktor Prutyanov return NULL; 201*3fa2d384SViktor Prutyanov } 202*3fa2d384SViktor Prutyanov 203*3fa2d384SViktor Prutyanov return pa_space_resolve(vs->ps, pa); 204*3fa2d384SViktor Prutyanov } 205*3fa2d384SViktor Prutyanov 206*3fa2d384SViktor Prutyanov int va_space_rw(struct va_space *vs, uint64_t addr, 207*3fa2d384SViktor Prutyanov void *buf, size_t size, int is_write) 208*3fa2d384SViktor Prutyanov { 209*3fa2d384SViktor Prutyanov while (size) { 210*3fa2d384SViktor Prutyanov uint64_t page = addr & PFN_MASK; 211*3fa2d384SViktor Prutyanov size_t s = (page + PAGE_SIZE) - addr; 212*3fa2d384SViktor Prutyanov void *ptr; 213*3fa2d384SViktor Prutyanov 214*3fa2d384SViktor Prutyanov s = (s > size) ? size : s; 215*3fa2d384SViktor Prutyanov 216*3fa2d384SViktor Prutyanov ptr = va_space_resolve(vs, addr); 217*3fa2d384SViktor Prutyanov if (!ptr) { 218*3fa2d384SViktor Prutyanov return 1; 219*3fa2d384SViktor Prutyanov } 220*3fa2d384SViktor Prutyanov 221*3fa2d384SViktor Prutyanov if (is_write) { 222*3fa2d384SViktor Prutyanov memcpy(ptr, buf, s); 223*3fa2d384SViktor Prutyanov } else { 224*3fa2d384SViktor Prutyanov memcpy(buf, ptr, s); 225*3fa2d384SViktor Prutyanov } 226*3fa2d384SViktor Prutyanov 227*3fa2d384SViktor Prutyanov size -= s; 228*3fa2d384SViktor Prutyanov buf = (uint8_t *)buf + s; 229*3fa2d384SViktor Prutyanov addr += s; 230*3fa2d384SViktor Prutyanov } 231*3fa2d384SViktor Prutyanov 232*3fa2d384SViktor Prutyanov return 0; 233*3fa2d384SViktor Prutyanov } 234