2 * Copyright (c) 2018 Virtuozzo International GmbH
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 #include "qemu/osdep.h"
11 static struct pa_block
*pa_space_find_block(struct pa_space
*ps
, uint64_t pa
)
14 for (i
= 0; i
< ps
->block_nr
; i
++) {
15 if (ps
->block
[i
].paddr
<= pa
&&
16 pa
<= ps
->block
[i
].paddr
+ ps
->block
[i
].size
) {
24 static uint8_t *pa_space_resolve(struct pa_space
*ps
, uint64_t pa
)
26 struct pa_block
*block
= pa_space_find_block(ps
, pa
);
32 return block
->addr
+ (pa
- block
->paddr
);
35 int pa_space_create(struct pa_space
*ps
, QEMU_Elf
*qemu_elf
)
37 Elf64_Half phdr_nr
= elf_getphdrnum(qemu_elf
->map
);
38 Elf64_Phdr
*phdr
= elf64_getphdr(qemu_elf
->map
);
44 for (i
= 0; i
< phdr_nr
; i
++) {
45 if (phdr
[i
].p_type
== PT_LOAD
) {
50 ps
->block
= malloc(sizeof(*ps
->block
) * ps
->block_nr
);
55 for (i
= 0; i
< phdr_nr
; i
++) {
56 if (phdr
[i
].p_type
== PT_LOAD
) {
57 ps
->block
[block_i
] = (struct pa_block
) {
58 .addr
= (uint8_t *)qemu_elf
->map
+ phdr
[i
].p_offset
,
59 .paddr
= phdr
[i
].p_paddr
,
60 .size
= phdr
[i
].p_filesz
,
69 void pa_space_destroy(struct pa_space
*ps
)
75 void va_space_set_dtb(struct va_space
*vs
, uint64_t dtb
)
77 vs
->dtb
= dtb
& 0x00ffffffffff000;
80 void va_space_create(struct va_space
*vs
, struct pa_space
*ps
, uint64_t dtb
)
83 va_space_set_dtb(vs
, dtb
);
86 static uint64_t get_pml4e(struct va_space
*vs
, uint64_t va
)
88 uint64_t pa
= (vs
->dtb
& 0xffffffffff000) | ((va
& 0xff8000000000) >> 36);
90 return *(uint64_t *)pa_space_resolve(vs
->ps
, pa
);
93 static uint64_t get_pdpi(struct va_space
*vs
, uint64_t va
, uint64_t pml4e
)
95 uint64_t pdpte_paddr
= (pml4e
& 0xffffffffff000) |
96 ((va
& 0x7FC0000000) >> 27);
98 return *(uint64_t *)pa_space_resolve(vs
->ps
, pdpte_paddr
);
101 static uint64_t pde_index(uint64_t va
)
103 return (va
>> 21) & 0x1FF;
106 static uint64_t pdba_base(uint64_t pdpe
)
108 return pdpe
& 0xFFFFFFFFFF000;
111 static uint64_t get_pgd(struct va_space
*vs
, uint64_t va
, uint64_t pdpe
)
113 uint64_t pgd_entry
= pdba_base(pdpe
) + pde_index(va
) * 8;
115 return *(uint64_t *)pa_space_resolve(vs
->ps
, pgd_entry
);
118 static uint64_t pte_index(uint64_t va
)
120 return (va
>> 12) & 0x1FF;
123 static uint64_t ptba_base(uint64_t pde
)
125 return pde
& 0xFFFFFFFFFF000;
128 static uint64_t get_pte(struct va_space
*vs
, uint64_t va
, uint64_t pgd
)
130 uint64_t pgd_val
= ptba_base(pgd
) + pte_index(va
) * 8;
132 return *(uint64_t *)pa_space_resolve(vs
->ps
, pgd_val
);
135 static uint64_t get_paddr(uint64_t va
, uint64_t pte
)
137 return (pte
& 0xFFFFFFFFFF000) | (va
& 0xFFF);
140 static bool is_present(uint64_t entry
)
145 static bool page_size_flag(uint64_t entry
)
147 return entry
& (1 << 7);
150 static uint64_t get_1GB_paddr(uint64_t va
, uint64_t pdpte
)
152 return (pdpte
& 0xfffffc0000000) | (va
& 0x3fffffff);
155 static uint64_t get_2MB_paddr(uint64_t va
, uint64_t pgd_entry
)
157 return (pgd_entry
& 0xfffffffe00000) | (va
& 0x00000001fffff);
160 static uint64_t va_space_va2pa(struct va_space
*vs
, uint64_t va
)
162 uint64_t pml4e
, pdpe
, pgd
, pte
;
164 pml4e
= get_pml4e(vs
, va
);
165 if (!is_present(pml4e
)) {
169 pdpe
= get_pdpi(vs
, va
, pml4e
);
170 if (!is_present(pdpe
)) {
174 if (page_size_flag(pdpe
)) {
175 return get_1GB_paddr(va
, pdpe
);
178 pgd
= get_pgd(vs
, va
, pdpe
);
179 if (!is_present(pgd
)) {
183 if (page_size_flag(pgd
)) {
184 return get_2MB_paddr(va
, pgd
);
187 pte
= get_pte(vs
, va
, pgd
);
188 if (!is_present(pte
)) {
192 return get_paddr(va
, pte
);
195 void *va_space_resolve(struct va_space
*vs
, uint64_t va
)
197 uint64_t pa
= va_space_va2pa(vs
, va
);
199 if (pa
== INVALID_PA
) {
203 return pa_space_resolve(vs
->ps
, pa
);
206 int va_space_rw(struct va_space
*vs
, uint64_t addr
,
207 void *buf
, size_t size
, int is_write
)
210 uint64_t page
= addr
& PFN_MASK
;
211 size_t s
= (page
+ PAGE_SIZE
) - addr
;
214 s
= (s
> size
) ? size
: s
;
216 ptr
= va_space_resolve(vs
, addr
);
228 buf
= (uint8_t *)buf
+ s
;