memslot: Detect host addresses and threat them verbatim

This allows to fix https://gitlab.freedesktop.org/spice/spice/-/issues/88.
Some technologies like ARM64 TBI, AMD UAI or Intel LAM use higher
address bits to store some additional information.
We should preserve such bits.
In order to do that detect if the group is for host addresses and
threat the address verbatim.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Tested-by: Momin Juned
This commit is contained in:
Frediano Ziglio 2025-03-30 21:17:00 +01:00
parent 272964dd34
commit bd378ad956
2 changed files with 33 additions and 4 deletions

View File

@ -52,6 +52,13 @@ int memslot_validate_virt(RedMemSlotInfo *info, uintptr_t virt, int slot_id,
{
MemSlot *slot;
/* detect host group, see comment in memslot_get_virt */
slot = &info->mem_slots[group_id][0];
if (slot->virt_end_addr == ~(uintptr_t)0 && slot->virt_start_addr == 0 &&
slot->address_delta == 0) {
return 1;
}
slot = &info->mem_slots[group_id][slot_id];
if ((virt + add_size) < virt) {
spice_critical("virtual address overlap");
@ -102,6 +109,25 @@ void *memslot_get_virt(RedMemSlotInfo *info, QXLPHYSICAL addr, uint32_t add_size
return NULL;
}
/* Detect host group.
* If the first slot covers the entire memory that group is the host
* group, that spans the entire memory.
* And if the group spans the entire memory all the virtual address is
* basically the host memory address with no slot encoded.
* When Qemu computes the QXL address from host memory it does not fill
* slot and generation but just converts the pointer to QXL address and
* expects to be able to convert back that number to a valid pointer.
* But in the cases of some technologies like ARM64 TBI, AMD UAI or Intel
* LAM that use the higher address bits to store additional information
* the ways QXL addresses are split and joined back causes issues.
* So here we ignore the slot from caller and keep the entire address.
*/
slot = &info->mem_slots[group_id][0];
if (slot->virt_end_addr == ~(uintptr_t)0 && slot->virt_start_addr == 0 &&
slot->address_delta == 0) {
return (void *)(uintptr_t)addr;
}
slot_id = memslot_get_id(info, addr);
if (slot_id >= info->num_memslots) {
print_memslots(info);

View File

@ -58,8 +58,11 @@ create_chunk(size_t prefix, uint32_t size, QXLDataChunk* prev, int fill)
static void init_meminfo(RedMemSlotInfo *mem_info)
{
memslot_info_init(mem_info, 1 /* groups */, 1 /* slots */, 1, 1);
memslot_info_add_slot(mem_info, 0, 0, 0 /* delta */, 0 /* start */, UINTPTR_MAX /* end */, 0 /* generation */);
memslot_info_init(mem_info, 2 /* groups */, 1 /* slots */, 1, 1);
memslot_info_add_slot(mem_info, 0, 0, 0 /* delta */, 0 /* start */, UINTPTR_MAX /* end */,
0 /* generation */);
memslot_info_add_slot(mem_info, 1, 0, 0 /* delta */, 0 /* start */, 0x80000000u /* end */,
0 /* generation */);
}
static void init_qxl_surface(QXLSurfaceCmd *qxl)
@ -88,7 +91,7 @@ static void test_memslot_invalid_group_id(void)
RedMemSlotInfo mem_info;
init_meminfo(&mem_info);
memslot_get_virt(&mem_info, 0, 16, 1);
memslot_get_virt(&mem_info, 0, 16, 2);
}
static void test_memslot_invalid_slot_id(void)
@ -96,7 +99,7 @@ static void test_memslot_invalid_slot_id(void)
RedMemSlotInfo mem_info;
init_meminfo(&mem_info);
memslot_get_virt(&mem_info, UINT64_C(1) << mem_info.memslot_id_shift, 16, 0);
memslot_get_virt(&mem_info, UINT64_C(1) << mem_info.memslot_id_shift, 16, 1);
}
static void test_memslot_invalid_addresses(void)