xref: /qemu/contrib/elf2dmp/addrspace.c (revision 3fa2d384c245bcee3a9ecfa11f298b76ea4c9d57)
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