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
)
15 for (i
= 0; i
< ps
->block_nr
; i
++) {
16 if (ps
->block
[i
].paddr
<= pa
&&
17 pa
< ps
->block
[i
].paddr
+ ps
->block
[i
].size
) {
25 static uint8_t *pa_space_resolve(struct pa_space
*ps
, uint64_t pa
)
27 struct pa_block
*block
= pa_space_find_block(ps
, pa
);
33 return block
->addr
+ (pa
- block
->paddr
);
36 static void pa_block_align(struct pa_block
*b
)
38 uint64_t low_align
= ((b
->paddr
- 1) | ELF2DMP_PAGE_MASK
) + 1 - b
->paddr
;
39 uint64_t high_align
= (b
->paddr
+ b
->size
) & ELF2DMP_PAGE_MASK
;
41 if (low_align
== 0 && high_align
== 0) {
45 if (low_align
+ high_align
< b
->size
) {
46 printf("Block 0x%"PRIx64
"+:0x%"PRIx64
" will be aligned to "
47 "0x%"PRIx64
"+:0x%"PRIx64
"\n", b
->paddr
, b
->size
,
48 b
->paddr
+ low_align
, b
->size
- low_align
- high_align
);
49 b
->size
-= low_align
+ high_align
;
51 printf("Block 0x%"PRIx64
"+:0x%"PRIx64
" is too small to align\n",
57 b
->paddr
+= low_align
;
60 void pa_space_create(struct pa_space
*ps
, QEMU_Elf
*qemu_elf
)
62 Elf64_Half phdr_nr
= elf_getphdrnum(qemu_elf
->map
);
63 Elf64_Phdr
*phdr
= elf64_getphdr(qemu_elf
->map
);
69 for (i
= 0; i
< phdr_nr
; i
++) {
70 if (phdr
[i
].p_type
== PT_LOAD
) {
75 ps
->block
= g_new(struct pa_block
, ps
->block_nr
);
77 for (i
= 0; i
< phdr_nr
; i
++) {
78 if (phdr
[i
].p_type
== PT_LOAD
) {
79 ps
->block
[block_i
] = (struct pa_block
) {
80 .addr
= (uint8_t *)qemu_elf
->map
+ phdr
[i
].p_offset
,
81 .paddr
= phdr
[i
].p_paddr
,
82 .size
= phdr
[i
].p_filesz
,
84 pa_block_align(&ps
->block
[block_i
]);
85 block_i
= ps
->block
[block_i
].size
? (block_i
+ 1) : block_i
;
89 ps
->block_nr
= block_i
;
92 void pa_space_destroy(struct pa_space
*ps
)
98 void va_space_set_dtb(struct va_space
*vs
, uint64_t dtb
)
100 vs
->dtb
= dtb
& 0x00ffffffffff000;
103 void va_space_create(struct va_space
*vs
, struct pa_space
*ps
, uint64_t dtb
)
106 va_space_set_dtb(vs
, dtb
);
109 static uint64_t get_pml4e(struct va_space
*vs
, uint64_t va
)
111 uint64_t pa
= (vs
->dtb
& 0xffffffffff000) | ((va
& 0xff8000000000) >> 36);
113 return *(uint64_t *)pa_space_resolve(vs
->ps
, pa
);
116 static uint64_t get_pdpi(struct va_space
*vs
, uint64_t va
, uint64_t pml4e
)
118 uint64_t pdpte_paddr
= (pml4e
& 0xffffffffff000) |
119 ((va
& 0x7FC0000000) >> 27);
121 return *(uint64_t *)pa_space_resolve(vs
->ps
, pdpte_paddr
);
124 static uint64_t pde_index(uint64_t va
)
126 return (va
>> 21) & 0x1FF;
129 static uint64_t pdba_base(uint64_t pdpe
)
131 return pdpe
& 0xFFFFFFFFFF000;
134 static uint64_t get_pgd(struct va_space
*vs
, uint64_t va
, uint64_t pdpe
)
136 uint64_t pgd_entry
= pdba_base(pdpe
) + pde_index(va
) * 8;
138 return *(uint64_t *)pa_space_resolve(vs
->ps
, pgd_entry
);
141 static uint64_t pte_index(uint64_t va
)
143 return (va
>> 12) & 0x1FF;
146 static uint64_t ptba_base(uint64_t pde
)
148 return pde
& 0xFFFFFFFFFF000;
151 static uint64_t get_pte(struct va_space
*vs
, uint64_t va
, uint64_t pgd
)
153 uint64_t pgd_val
= ptba_base(pgd
) + pte_index(va
) * 8;
155 return *(uint64_t *)pa_space_resolve(vs
->ps
, pgd_val
);
158 static uint64_t get_paddr(uint64_t va
, uint64_t pte
)
160 return (pte
& 0xFFFFFFFFFF000) | (va
& 0xFFF);
163 static bool is_present(uint64_t entry
)
168 static bool page_size_flag(uint64_t entry
)
170 return entry
& (1 << 7);
173 static uint64_t get_1GB_paddr(uint64_t va
, uint64_t pdpte
)
175 return (pdpte
& 0xfffffc0000000) | (va
& 0x3fffffff);
178 static uint64_t get_2MB_paddr(uint64_t va
, uint64_t pgd_entry
)
180 return (pgd_entry
& 0xfffffffe00000) | (va
& 0x00000001fffff);
183 static uint64_t va_space_va2pa(struct va_space
*vs
, uint64_t va
)
185 uint64_t pml4e
, pdpe
, pgd
, pte
;
187 pml4e
= get_pml4e(vs
, va
);
188 if (!is_present(pml4e
)) {
192 pdpe
= get_pdpi(vs
, va
, pml4e
);
193 if (!is_present(pdpe
)) {
197 if (page_size_flag(pdpe
)) {
198 return get_1GB_paddr(va
, pdpe
);
201 pgd
= get_pgd(vs
, va
, pdpe
);
202 if (!is_present(pgd
)) {
206 if (page_size_flag(pgd
)) {
207 return get_2MB_paddr(va
, pgd
);
210 pte
= get_pte(vs
, va
, pgd
);
211 if (!is_present(pte
)) {
215 return get_paddr(va
, pte
);
218 void *va_space_resolve(struct va_space
*vs
, uint64_t va
)
220 uint64_t pa
= va_space_va2pa(vs
, va
);
222 if (pa
== INVALID_PA
) {
226 return pa_space_resolve(vs
->ps
, pa
);
229 bool va_space_rw(struct va_space
*vs
, uint64_t addr
,
230 void *buf
, size_t size
, int is_write
)
233 uint64_t page
= addr
& ELF2DMP_PFN_MASK
;
234 size_t s
= (page
+ ELF2DMP_PAGE_SIZE
) - addr
;
237 s
= (s
> size
) ? size
: s
;
239 ptr
= va_space_resolve(vs
, addr
);
251 buf
= (uint8_t *)buf
+ s
;