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 void *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 bool pa_space_read64(struct pa_space
*ps
, uint64_t pa
, uint64_t *value
)
38 uint64_t *resolved
= pa_space_resolve(ps
, pa
);
49 static void pa_block_align(struct pa_block
*b
)
51 uint64_t low_align
= ((b
->paddr
- 1) | ELF2DMP_PAGE_MASK
) + 1 - b
->paddr
;
52 uint64_t high_align
= (b
->paddr
+ b
->size
) & ELF2DMP_PAGE_MASK
;
54 if (low_align
== 0 && high_align
== 0) {
58 if (low_align
+ high_align
< b
->size
) {
59 printf("Block 0x%"PRIx64
"+:0x%"PRIx64
" will be aligned to "
60 "0x%"PRIx64
"+:0x%"PRIx64
"\n", b
->paddr
, b
->size
,
61 b
->paddr
+ low_align
, b
->size
- low_align
- high_align
);
62 b
->size
-= low_align
+ high_align
;
64 printf("Block 0x%"PRIx64
"+:0x%"PRIx64
" is too small to align\n",
70 b
->paddr
+= low_align
;
73 void pa_space_create(struct pa_space
*ps
, QEMU_Elf
*qemu_elf
)
75 Elf64_Half phdr_nr
= elf_getphdrnum(qemu_elf
->map
);
76 Elf64_Phdr
*phdr
= elf64_getphdr(qemu_elf
->map
);
82 for (i
= 0; i
< phdr_nr
; i
++) {
83 if (phdr
[i
].p_type
== PT_LOAD
) {
88 ps
->block
= g_new(struct pa_block
, ps
->block_nr
);
90 for (i
= 0; i
< phdr_nr
; i
++) {
91 if (phdr
[i
].p_type
== PT_LOAD
&& phdr
[i
].p_offset
< qemu_elf
->size
) {
92 ps
->block
[block_i
] = (struct pa_block
) {
93 .addr
= (uint8_t *)qemu_elf
->map
+ phdr
[i
].p_offset
,
94 .paddr
= phdr
[i
].p_paddr
,
95 .size
= MIN(phdr
[i
].p_filesz
,
96 qemu_elf
->size
- phdr
[i
].p_offset
),
98 pa_block_align(&ps
->block
[block_i
]);
99 block_i
= ps
->block
[block_i
].size
? (block_i
+ 1) : block_i
;
103 ps
->block_nr
= block_i
;
106 void pa_space_destroy(struct pa_space
*ps
)
112 void va_space_set_dtb(struct va_space
*vs
, uint64_t dtb
)
114 vs
->dtb
= dtb
& 0x00ffffffffff000;
117 void va_space_create(struct va_space
*vs
, struct pa_space
*ps
, uint64_t dtb
)
120 va_space_set_dtb(vs
, dtb
);
123 static bool get_pml4e(struct va_space
*vs
, uint64_t va
, uint64_t *value
)
125 uint64_t pa
= (vs
->dtb
& 0xffffffffff000) | ((va
& 0xff8000000000) >> 36);
127 return pa_space_read64(vs
->ps
, pa
, value
);
130 static bool get_pdpi(struct va_space
*vs
, uint64_t va
, uint64_t pml4e
,
133 uint64_t pdpte_paddr
= (pml4e
& 0xffffffffff000) |
134 ((va
& 0x7FC0000000) >> 27);
136 return pa_space_read64(vs
->ps
, pdpte_paddr
, value
);
139 static uint64_t pde_index(uint64_t va
)
141 return (va
>> 21) & 0x1FF;
144 static uint64_t pdba_base(uint64_t pdpe
)
146 return pdpe
& 0xFFFFFFFFFF000;
149 static bool get_pgd(struct va_space
*vs
, uint64_t va
, uint64_t pdpe
,
152 uint64_t pgd_entry
= pdba_base(pdpe
) + pde_index(va
) * 8;
154 return pa_space_read64(vs
->ps
, pgd_entry
, value
);
157 static uint64_t pte_index(uint64_t va
)
159 return (va
>> 12) & 0x1FF;
162 static uint64_t ptba_base(uint64_t pde
)
164 return pde
& 0xFFFFFFFFFF000;
167 static bool get_pte(struct va_space
*vs
, uint64_t va
, uint64_t pgd
,
170 uint64_t pgd_val
= ptba_base(pgd
) + pte_index(va
) * 8;
172 return pa_space_read64(vs
->ps
, pgd_val
, value
);
175 static uint64_t get_paddr(uint64_t va
, uint64_t pte
)
177 return (pte
& 0xFFFFFFFFFF000) | (va
& 0xFFF);
180 static bool is_present(uint64_t entry
)
185 static bool page_size_flag(uint64_t entry
)
187 return entry
& (1 << 7);
190 static uint64_t get_1GB_paddr(uint64_t va
, uint64_t pdpte
)
192 return (pdpte
& 0xfffffc0000000) | (va
& 0x3fffffff);
195 static uint64_t get_2MB_paddr(uint64_t va
, uint64_t pgd_entry
)
197 return (pgd_entry
& 0xfffffffe00000) | (va
& 0x00000001fffff);
200 static uint64_t va_space_va2pa(struct va_space
*vs
, uint64_t va
)
202 uint64_t pml4e
, pdpe
, pgd
, pte
;
204 if (!get_pml4e(vs
, va
, &pml4e
) || !is_present(pml4e
)) {
208 if (!get_pdpi(vs
, va
, pml4e
, &pdpe
) || !is_present(pdpe
)) {
212 if (page_size_flag(pdpe
)) {
213 return get_1GB_paddr(va
, pdpe
);
216 if (!get_pgd(vs
, va
, pdpe
, &pgd
) || !is_present(pgd
)) {
220 if (page_size_flag(pgd
)) {
221 return get_2MB_paddr(va
, pgd
);
224 if (!get_pte(vs
, va
, pgd
, &pte
) || !is_present(pte
)) {
228 return get_paddr(va
, pte
);
231 void *va_space_resolve(struct va_space
*vs
, uint64_t va
)
233 uint64_t pa
= va_space_va2pa(vs
, va
);
235 if (pa
== INVALID_PA
) {
239 return pa_space_resolve(vs
->ps
, pa
);
242 bool va_space_rw(struct va_space
*vs
, uint64_t addr
,
243 void *buf
, size_t size
, int is_write
)
246 uint64_t page
= addr
& ELF2DMP_PFN_MASK
;
247 size_t s
= (page
+ ELF2DMP_PAGE_SIZE
) - addr
;
250 s
= (s
> size
) ? size
: s
;
252 ptr
= va_space_resolve(vs
, addr
);
264 buf
= (uint8_t *)buf
+ s
;