mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-21 13:08:42 +00:00
page walk during copy_from_vm/copy_to_vm
there are data transfer between guest(GPA) & hv(HPA), especially for hypercall from guest. guest should make sure these GPAs are address continous, but hv cannot assure HPAs which mapped to these GPAs are address continous, for example, after enable hugetlb, a contious GPA range could come from two different 2M pages. this patch is handling such case by doing gpa page walking during copy_from_vm & copy_to_vm. Signed-off-by: Jason Chen CJ <jason.cj.chen@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
parent
58c109e8de
commit
2ff7bf826e
@ -137,46 +137,37 @@ void destroy_ept(struct vm *vm)
|
||||
free_ept_mem(HPA2HVA(vm->arch_vm.sworld_eptp));
|
||||
}
|
||||
|
||||
uint64_t gpa2hpa_check(struct vm *vm, uint64_t gpa,
|
||||
uint64_t size, int *found, bool assert)
|
||||
uint64_t _gpa2hpa(struct vm *vm, uint64_t gpa, uint32_t *size)
|
||||
{
|
||||
uint64_t hpa = 0;
|
||||
int _found = 0;
|
||||
uint32_t pg_size = 0;
|
||||
struct entry_params entry;
|
||||
struct map_params map_params;
|
||||
|
||||
map_params.page_table_type = PTT_EPT;
|
||||
map_params.pml4_base = HPA2HVA(vm->arch_vm.nworld_eptp);
|
||||
map_params.pml4_inverted = HPA2HVA(vm->arch_vm.m2p);
|
||||
obtain_last_page_table_entry(&map_params, &entry,
|
||||
(void *)gpa, true);
|
||||
if (entry.entry_present == PT_PRESENT
|
||||
/* if cross several pages, now not handle it,
|
||||
* only print error info
|
||||
*/
|
||||
&& ((gpa % entry.page_size) + size) <= entry.page_size) {
|
||||
_found = 1;
|
||||
obtain_last_page_table_entry(&map_params, &entry, (void *)gpa, true);
|
||||
if (entry.entry_present == PT_PRESENT) {
|
||||
hpa = ((entry.entry_val & (~(entry.page_size - 1)))
|
||||
| (gpa & (entry.page_size - 1)));
|
||||
}
|
||||
|
||||
if (found != NULL)
|
||||
*found = _found;
|
||||
|
||||
if (_found == 0 && assert) {
|
||||
pg_size = entry.page_size;
|
||||
pr_dbg("GPA2HPA: 0x%llx->0x%llx", gpa, hpa);
|
||||
} else {
|
||||
pr_err("VM %d GPA2HPA: failed for gpa 0x%llx",
|
||||
vm->attr.boot_idx, gpa);
|
||||
ASSERT(_found != 0, "GPA2HPA not found");
|
||||
}
|
||||
|
||||
pr_dbg("GPA2HPA: 0x%llx->0x%llx", gpa, hpa);
|
||||
if (size)
|
||||
*size = pg_size;
|
||||
|
||||
return hpa;
|
||||
}
|
||||
|
||||
/* using return value 0 as failure, make sure guest will not use hpa 0 */
|
||||
uint64_t gpa2hpa(struct vm *vm, uint64_t gpa)
|
||||
{
|
||||
return gpa2hpa_check(vm, gpa, 0, NULL, true);
|
||||
return _gpa2hpa(vm, gpa, NULL);
|
||||
}
|
||||
|
||||
uint64_t hpa2gpa(struct vm *vm, uint64_t hpa)
|
||||
|
@ -120,6 +120,68 @@ inline bool vm_lapic_disabled(struct vm *vm)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Caller(Guest) should make sure gpa is continuous.
|
||||
* - gpa from hypercall input which from kernel stack is gpa continous, not
|
||||
* support kernel stack from vmap
|
||||
* - some other gpa from hypercall parameters, VHM should make sure it's
|
||||
* continous
|
||||
*/
|
||||
int copy_from_vm(struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size)
|
||||
{
|
||||
uint64_t hpa;
|
||||
uint32_t off_in_pg, len, pg_size;
|
||||
void *g_ptr;
|
||||
|
||||
do {
|
||||
hpa = _gpa2hpa(vm, gpa, &pg_size);
|
||||
if (pg_size == 0) {
|
||||
ASSERT(0, "copy_from_vm: GPA2HPA not found");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
off_in_pg = gpa & (pg_size - 1);
|
||||
if (size > pg_size - off_in_pg)
|
||||
len = pg_size - off_in_pg;
|
||||
else
|
||||
len = size;
|
||||
|
||||
g_ptr = HPA2HVA(hpa);
|
||||
memcpy_s(h_ptr, len, g_ptr, len);
|
||||
gpa += len;
|
||||
size -= len;
|
||||
} while (size > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copy_to_vm(struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size)
|
||||
{
|
||||
uint64_t hpa;
|
||||
uint32_t off_in_pg, len, pg_size;
|
||||
void *g_ptr;
|
||||
|
||||
do {
|
||||
hpa = _gpa2hpa(vm, gpa, &pg_size);
|
||||
if (pg_size == 0) {
|
||||
ASSERT(0, "copy_to_vm: GPA2HPA not found");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
off_in_pg = gpa & (pg_size - 1);
|
||||
if (size > pg_size - off_in_pg)
|
||||
len = pg_size - off_in_pg;
|
||||
else
|
||||
len = size;
|
||||
|
||||
g_ptr = HPA2HVA(hpa);
|
||||
memcpy_s(g_ptr, len, h_ptr, len);
|
||||
gpa += len;
|
||||
size -= len;
|
||||
} while (size > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t gva2gpa(struct vm *vm, uint64_t cr3, uint64_t gva)
|
||||
{
|
||||
int level, index, shift;
|
||||
|
@ -139,6 +139,8 @@ int general_sw_loader(struct vm *vm, struct vcpu *vcpu);
|
||||
typedef int (*vm_sw_loader_t)(struct vm *, struct vcpu *);
|
||||
extern vm_sw_loader_t vm_sw_loader;
|
||||
|
||||
int copy_from_vm(struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size);
|
||||
int copy_to_vm(struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size);
|
||||
#endif /* !ASSEMBLER */
|
||||
|
||||
#endif /* GUEST_H*/
|
||||
|
@ -392,8 +392,7 @@ int is_ept_supported(void);
|
||||
uint64_t create_guest_initial_paging(struct vm *vm);
|
||||
void destroy_ept(struct vm *vm);
|
||||
uint64_t gpa2hpa(struct vm *vm, uint64_t gpa);
|
||||
uint64_t gpa2hpa_check(struct vm *vm, uint64_t gpa,
|
||||
uint64_t size, int *found, bool assert);
|
||||
uint64_t _gpa2hpa(struct vm *vm, uint64_t gpa, uint32_t *size);
|
||||
uint64_t hpa2gpa(struct vm *vm, uint64_t hpa);
|
||||
int ept_mmap(struct vm *vm, uint64_t hpa,
|
||||
uint64_t gpa, uint64_t size, uint32_t type, uint32_t prot);
|
||||
|
@ -372,33 +372,4 @@ int64_t hcall_initialize_trusty(struct vcpu *vcpu, uint64_t param);
|
||||
* @}
|
||||
*/
|
||||
|
||||
static inline int check_result(int found)
|
||||
{
|
||||
return found ? 0 : -1;
|
||||
}
|
||||
|
||||
#define copy_from_vm(vm, ptr, gpa, size) ({ \
|
||||
int found = 0; \
|
||||
typeof(*(ptr)) *h_ptr = (ptr); \
|
||||
typeof(*(ptr)) *g_ptr = \
|
||||
HPA2HVA(gpa2hpa_check(vm, gpa, \
|
||||
size, &found, true)); \
|
||||
if (found) { \
|
||||
memcpy_s(h_ptr, size, g_ptr, size); \
|
||||
} \
|
||||
check_result(found); \
|
||||
})
|
||||
|
||||
#define copy_to_vm(vm, ptr, gpa, size) ({ \
|
||||
int found = 0; \
|
||||
typeof(*(ptr)) *h_ptr = (ptr); \
|
||||
typeof(*(ptr)) *g_ptr = \
|
||||
HPA2HVA(gpa2hpa_check(vm, gpa, \
|
||||
size, &found, true)); \
|
||||
if (found) { \
|
||||
memcpy_s(g_ptr, size, h_ptr, size); \
|
||||
} \
|
||||
check_result(found); \
|
||||
})
|
||||
|
||||
#endif /* HYPERCALL_H*/
|
||||
|
Loading…
Reference in New Issue
Block a user