xref: /qemu/contrib/elf2dmp/addrspace.c (revision 2d0fc797faaa73fbc1d30f5f9e90407bf3dd93f0)
13fa2d384SViktor Prutyanov /*
23fa2d384SViktor Prutyanov  * Copyright (c) 2018 Virtuozzo International GmbH
33fa2d384SViktor Prutyanov  *
43fa2d384SViktor Prutyanov  * This work is licensed under the terms of the GNU GPL, version 2 or later.
53fa2d384SViktor Prutyanov  *
63fa2d384SViktor Prutyanov  */
73fa2d384SViktor Prutyanov 
83fa2d384SViktor Prutyanov #include "qemu/osdep.h"
93fa2d384SViktor Prutyanov #include "addrspace.h"
103fa2d384SViktor Prutyanov 
113fa2d384SViktor Prutyanov static struct pa_block *pa_space_find_block(struct pa_space *ps, uint64_t pa)
123fa2d384SViktor Prutyanov {
133fa2d384SViktor Prutyanov     size_t i;
143fa2d384SViktor Prutyanov     for (i = 0; i < ps->block_nr; i++) {
153fa2d384SViktor Prutyanov         if (ps->block[i].paddr <= pa &&
163fa2d384SViktor Prutyanov                 pa <= ps->block[i].paddr + ps->block[i].size) {
173fa2d384SViktor Prutyanov             return ps->block + i;
183fa2d384SViktor Prutyanov         }
193fa2d384SViktor Prutyanov     }
203fa2d384SViktor Prutyanov 
213fa2d384SViktor Prutyanov     return NULL;
223fa2d384SViktor Prutyanov }
233fa2d384SViktor Prutyanov 
243fa2d384SViktor Prutyanov static uint8_t *pa_space_resolve(struct pa_space *ps, uint64_t pa)
253fa2d384SViktor Prutyanov {
263fa2d384SViktor Prutyanov     struct pa_block *block = pa_space_find_block(ps, pa);
273fa2d384SViktor Prutyanov 
283fa2d384SViktor Prutyanov     if (!block) {
293fa2d384SViktor Prutyanov         return NULL;
303fa2d384SViktor Prutyanov     }
313fa2d384SViktor Prutyanov 
323fa2d384SViktor Prutyanov     return block->addr + (pa - block->paddr);
333fa2d384SViktor Prutyanov }
343fa2d384SViktor Prutyanov 
353fa2d384SViktor Prutyanov int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
363fa2d384SViktor Prutyanov {
373fa2d384SViktor Prutyanov     Elf64_Half phdr_nr = elf_getphdrnum(qemu_elf->map);
383fa2d384SViktor Prutyanov     Elf64_Phdr *phdr = elf64_getphdr(qemu_elf->map);
393fa2d384SViktor Prutyanov     size_t block_i = 0;
403fa2d384SViktor Prutyanov     size_t i;
413fa2d384SViktor Prutyanov 
423fa2d384SViktor Prutyanov     ps->block_nr = 0;
433fa2d384SViktor Prutyanov 
443fa2d384SViktor Prutyanov     for (i = 0; i < phdr_nr; i++) {
453fa2d384SViktor Prutyanov         if (phdr[i].p_type == PT_LOAD) {
463fa2d384SViktor Prutyanov             ps->block_nr++;
473fa2d384SViktor Prutyanov         }
483fa2d384SViktor Prutyanov     }
493fa2d384SViktor Prutyanov 
503fa2d384SViktor Prutyanov     ps->block = malloc(sizeof(*ps->block) * ps->block_nr);
513fa2d384SViktor Prutyanov     if (!ps->block) {
523fa2d384SViktor Prutyanov         return 1;
533fa2d384SViktor Prutyanov     }
543fa2d384SViktor Prutyanov 
553fa2d384SViktor Prutyanov     for (i = 0; i < phdr_nr; i++) {
563fa2d384SViktor Prutyanov         if (phdr[i].p_type == PT_LOAD) {
573fa2d384SViktor Prutyanov             ps->block[block_i] = (struct pa_block) {
583fa2d384SViktor Prutyanov                 .addr = (uint8_t *)qemu_elf->map + phdr[i].p_offset,
593fa2d384SViktor Prutyanov                 .paddr = phdr[i].p_paddr,
603fa2d384SViktor Prutyanov                 .size = phdr[i].p_filesz,
613fa2d384SViktor Prutyanov             };
623fa2d384SViktor Prutyanov             block_i++;
633fa2d384SViktor Prutyanov         }
643fa2d384SViktor Prutyanov     }
653fa2d384SViktor Prutyanov 
663fa2d384SViktor Prutyanov     return 0;
673fa2d384SViktor Prutyanov }
683fa2d384SViktor Prutyanov 
693fa2d384SViktor Prutyanov void pa_space_destroy(struct pa_space *ps)
703fa2d384SViktor Prutyanov {
713fa2d384SViktor Prutyanov     ps->block_nr = 0;
723fa2d384SViktor Prutyanov     free(ps->block);
733fa2d384SViktor Prutyanov }
743fa2d384SViktor Prutyanov 
753fa2d384SViktor Prutyanov void va_space_set_dtb(struct va_space *vs, uint64_t dtb)
763fa2d384SViktor Prutyanov {
773fa2d384SViktor Prutyanov     vs->dtb = dtb & 0x00ffffffffff000;
783fa2d384SViktor Prutyanov }
793fa2d384SViktor Prutyanov 
803fa2d384SViktor Prutyanov void va_space_create(struct va_space *vs, struct pa_space *ps, uint64_t dtb)
813fa2d384SViktor Prutyanov {
823fa2d384SViktor Prutyanov     vs->ps = ps;
833fa2d384SViktor Prutyanov     va_space_set_dtb(vs, dtb);
843fa2d384SViktor Prutyanov }
853fa2d384SViktor Prutyanov 
863fa2d384SViktor Prutyanov static uint64_t get_pml4e(struct va_space *vs, uint64_t va)
873fa2d384SViktor Prutyanov {
883fa2d384SViktor Prutyanov     uint64_t pa = (vs->dtb & 0xffffffffff000) | ((va & 0xff8000000000) >> 36);
893fa2d384SViktor Prutyanov 
903fa2d384SViktor Prutyanov     return *(uint64_t *)pa_space_resolve(vs->ps, pa);
913fa2d384SViktor Prutyanov }
923fa2d384SViktor Prutyanov 
933fa2d384SViktor Prutyanov static uint64_t get_pdpi(struct va_space *vs, uint64_t va, uint64_t pml4e)
943fa2d384SViktor Prutyanov {
953fa2d384SViktor Prutyanov     uint64_t pdpte_paddr = (pml4e & 0xffffffffff000) |
963fa2d384SViktor Prutyanov         ((va & 0x7FC0000000) >> 27);
973fa2d384SViktor Prutyanov 
983fa2d384SViktor Prutyanov     return *(uint64_t *)pa_space_resolve(vs->ps, pdpte_paddr);
993fa2d384SViktor Prutyanov }
1003fa2d384SViktor Prutyanov 
1013fa2d384SViktor Prutyanov static uint64_t pde_index(uint64_t va)
1023fa2d384SViktor Prutyanov {
1033fa2d384SViktor Prutyanov     return (va >> 21) & 0x1FF;
1043fa2d384SViktor Prutyanov }
1053fa2d384SViktor Prutyanov 
1063fa2d384SViktor Prutyanov static uint64_t pdba_base(uint64_t pdpe)
1073fa2d384SViktor Prutyanov {
1083fa2d384SViktor Prutyanov     return pdpe & 0xFFFFFFFFFF000;
1093fa2d384SViktor Prutyanov }
1103fa2d384SViktor Prutyanov 
1113fa2d384SViktor Prutyanov static uint64_t get_pgd(struct va_space *vs, uint64_t va, uint64_t pdpe)
1123fa2d384SViktor Prutyanov {
1133fa2d384SViktor Prutyanov     uint64_t pgd_entry = pdba_base(pdpe) + pde_index(va) * 8;
1143fa2d384SViktor Prutyanov 
1153fa2d384SViktor Prutyanov     return *(uint64_t *)pa_space_resolve(vs->ps, pgd_entry);
1163fa2d384SViktor Prutyanov }
1173fa2d384SViktor Prutyanov 
1183fa2d384SViktor Prutyanov static uint64_t pte_index(uint64_t va)
1193fa2d384SViktor Prutyanov {
1203fa2d384SViktor Prutyanov     return (va >> 12) & 0x1FF;
1213fa2d384SViktor Prutyanov }
1223fa2d384SViktor Prutyanov 
1233fa2d384SViktor Prutyanov static uint64_t ptba_base(uint64_t pde)
1243fa2d384SViktor Prutyanov {
1253fa2d384SViktor Prutyanov     return pde & 0xFFFFFFFFFF000;
1263fa2d384SViktor Prutyanov }
1273fa2d384SViktor Prutyanov 
1283fa2d384SViktor Prutyanov static uint64_t get_pte(struct va_space *vs, uint64_t va, uint64_t pgd)
1293fa2d384SViktor Prutyanov {
1303fa2d384SViktor Prutyanov     uint64_t pgd_val = ptba_base(pgd) + pte_index(va) * 8;
1313fa2d384SViktor Prutyanov 
1323fa2d384SViktor Prutyanov     return *(uint64_t *)pa_space_resolve(vs->ps, pgd_val);
1333fa2d384SViktor Prutyanov }
1343fa2d384SViktor Prutyanov 
1353fa2d384SViktor Prutyanov static uint64_t get_paddr(uint64_t va, uint64_t pte)
1363fa2d384SViktor Prutyanov {
1373fa2d384SViktor Prutyanov     return (pte & 0xFFFFFFFFFF000) | (va & 0xFFF);
1383fa2d384SViktor Prutyanov }
1393fa2d384SViktor Prutyanov 
1403fa2d384SViktor Prutyanov static bool is_present(uint64_t entry)
1413fa2d384SViktor Prutyanov {
1423fa2d384SViktor Prutyanov     return entry & 0x1;
1433fa2d384SViktor Prutyanov }
1443fa2d384SViktor Prutyanov 
1453fa2d384SViktor Prutyanov static bool page_size_flag(uint64_t entry)
1463fa2d384SViktor Prutyanov {
1473fa2d384SViktor Prutyanov     return entry & (1 << 7);
1483fa2d384SViktor Prutyanov }
1493fa2d384SViktor Prutyanov 
1503fa2d384SViktor Prutyanov static uint64_t get_1GB_paddr(uint64_t va, uint64_t pdpte)
1513fa2d384SViktor Prutyanov {
1523fa2d384SViktor Prutyanov     return (pdpte & 0xfffffc0000000) | (va & 0x3fffffff);
1533fa2d384SViktor Prutyanov }
1543fa2d384SViktor Prutyanov 
1553fa2d384SViktor Prutyanov static uint64_t get_2MB_paddr(uint64_t va, uint64_t pgd_entry)
1563fa2d384SViktor Prutyanov {
1573fa2d384SViktor Prutyanov     return (pgd_entry & 0xfffffffe00000) | (va & 0x00000001fffff);
1583fa2d384SViktor Prutyanov }
1593fa2d384SViktor Prutyanov 
1603fa2d384SViktor Prutyanov static uint64_t va_space_va2pa(struct va_space *vs, uint64_t va)
1613fa2d384SViktor Prutyanov {
1623fa2d384SViktor Prutyanov     uint64_t pml4e, pdpe, pgd, pte;
1633fa2d384SViktor Prutyanov 
1643fa2d384SViktor Prutyanov     pml4e = get_pml4e(vs, va);
1653fa2d384SViktor Prutyanov     if (!is_present(pml4e)) {
1663fa2d384SViktor Prutyanov         return INVALID_PA;
1673fa2d384SViktor Prutyanov     }
1683fa2d384SViktor Prutyanov 
1693fa2d384SViktor Prutyanov     pdpe = get_pdpi(vs, va, pml4e);
1703fa2d384SViktor Prutyanov     if (!is_present(pdpe)) {
1713fa2d384SViktor Prutyanov         return INVALID_PA;
1723fa2d384SViktor Prutyanov     }
1733fa2d384SViktor Prutyanov 
1743fa2d384SViktor Prutyanov     if (page_size_flag(pdpe)) {
1753fa2d384SViktor Prutyanov         return get_1GB_paddr(va, pdpe);
1763fa2d384SViktor Prutyanov     }
1773fa2d384SViktor Prutyanov 
1783fa2d384SViktor Prutyanov     pgd = get_pgd(vs, va, pdpe);
1793fa2d384SViktor Prutyanov     if (!is_present(pgd)) {
1803fa2d384SViktor Prutyanov         return INVALID_PA;
1813fa2d384SViktor Prutyanov     }
1823fa2d384SViktor Prutyanov 
1833fa2d384SViktor Prutyanov     if (page_size_flag(pgd)) {
1843fa2d384SViktor Prutyanov         return get_2MB_paddr(va, pgd);
1853fa2d384SViktor Prutyanov     }
1863fa2d384SViktor Prutyanov 
1873fa2d384SViktor Prutyanov     pte = get_pte(vs, va, pgd);
1883fa2d384SViktor Prutyanov     if (!is_present(pte)) {
1893fa2d384SViktor Prutyanov         return INVALID_PA;
1903fa2d384SViktor Prutyanov     }
1913fa2d384SViktor Prutyanov 
1923fa2d384SViktor Prutyanov     return get_paddr(va, pte);
1933fa2d384SViktor Prutyanov }
1943fa2d384SViktor Prutyanov 
1953fa2d384SViktor Prutyanov void *va_space_resolve(struct va_space *vs, uint64_t va)
1963fa2d384SViktor Prutyanov {
1973fa2d384SViktor Prutyanov     uint64_t pa = va_space_va2pa(vs, va);
1983fa2d384SViktor Prutyanov 
1993fa2d384SViktor Prutyanov     if (pa == INVALID_PA) {
2003fa2d384SViktor Prutyanov         return NULL;
2013fa2d384SViktor Prutyanov     }
2023fa2d384SViktor Prutyanov 
2033fa2d384SViktor Prutyanov     return pa_space_resolve(vs->ps, pa);
2043fa2d384SViktor Prutyanov }
2053fa2d384SViktor Prutyanov 
2063fa2d384SViktor Prutyanov int va_space_rw(struct va_space *vs, uint64_t addr,
2073fa2d384SViktor Prutyanov         void *buf, size_t size, int is_write)
2083fa2d384SViktor Prutyanov {
2093fa2d384SViktor Prutyanov     while (size) {
210*2d0fc797SJiaxun Yang         uint64_t page = addr & ELF2DMP_PFN_MASK;
211*2d0fc797SJiaxun Yang         size_t s = (page + ELF2DMP_PAGE_SIZE) - addr;
2123fa2d384SViktor Prutyanov         void *ptr;
2133fa2d384SViktor Prutyanov 
2143fa2d384SViktor Prutyanov         s = (s > size) ? size : s;
2153fa2d384SViktor Prutyanov 
2163fa2d384SViktor Prutyanov         ptr = va_space_resolve(vs, addr);
2173fa2d384SViktor Prutyanov         if (!ptr) {
2183fa2d384SViktor Prutyanov             return 1;
2193fa2d384SViktor Prutyanov         }
2203fa2d384SViktor Prutyanov 
2213fa2d384SViktor Prutyanov         if (is_write) {
2223fa2d384SViktor Prutyanov             memcpy(ptr, buf, s);
2233fa2d384SViktor Prutyanov         } else {
2243fa2d384SViktor Prutyanov             memcpy(buf, ptr, s);
2253fa2d384SViktor Prutyanov         }
2263fa2d384SViktor Prutyanov 
2273fa2d384SViktor Prutyanov         size -= s;
2283fa2d384SViktor Prutyanov         buf = (uint8_t *)buf + s;
2293fa2d384SViktor Prutyanov         addr += s;
2303fa2d384SViktor Prutyanov     }
2313fa2d384SViktor Prutyanov 
2323fa2d384SViktor Prutyanov     return 0;
2333fa2d384SViktor Prutyanov }
234