Пытаюсь получить список сегментов памяти через вызов GetMemoryMap. Первый раз функция отрабатывает корректно и возвращает необходимый объём буфера, затем я успешно выделяю память с помощью AllocatedPages, после снова вызываю GetMemoryMap, и qemu вылетает с ошибкой:
KVM internal error. Suberror: 1
emulation failure
RAX=0000000007f28240 RBX=0000000007f11588 RCX=000000000685f398 RDX=0000000006727100
RSI=0000000007f116e8 RDI=000000000685f318 RBP=0000000007f11578 RSP=0000000007f11518
R8 =0000000007f11588 R9 =0000000000006000 R10=000000000685f188 R11=00000000d848021d
R12=0000000000000000 R13=000000000685fa18 R14=0000000006727100 R15=000000000678c1e8
RIP=00000000000b0000 RFL=00000282 [--S----] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0030 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA]
CS =0038 0000000000000000 ffffffff 00a09b00 DPL=0 CS64 [-RA]
SS =0030 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA]
DS =0030 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA]
FS =0030 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA]
GS =0030 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= 00000000079de000 00000047
IDT= 0000000007272018 00000fff
CR0=80010033 CR2=0000000000000000 CR3=0000000007c01000 CR4=00000668
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
EFER=0000000000000d00
Code=00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 <ff> ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
Я пробовал использовать AllocateMemoryPool вместо AllocatePages, также пробовал статичный буфер размером 8192 байта (необходимый размер буфера не превышает 6000 байт), но qemu всё равно падает с ошибкой. Почему так происходит?
Код:
#define ROUNDUP(x,b) (((unsigned long)x+b-1)&(~(b-1)))
#define PAGEUP(x) ROUNDUP(x, PAGE_SIZE)
#define PAGE_SIZE 4096
#define handle_error(err) do { \
printf(L"Error: %s\r\n", str_status(err)); \
exit(2); \
} while(0)
EfiMemoryDescriptor* get_memory_map(size_t *map_key) {
puts(L"Retrieve size for memory map buffer");
size_t descriptor_size;
uint32_t descriptor_version;
size_t buffer_size = 0;
size_t err = system_table->boot_services->get_memory_map(
&buffer_size,
NULL,
map_key,
&descriptor_size,
&descriptor_version
);
if(error_code(err) != EfiBufferTooSmall)
handle_error(err);
puts(L"Allocate memory for memory map buffer");
EfiMemoryDescriptor *buffer = NULL;
size_t num_pages = PAGEUP(buffer_size) / PAGE_SIZE;
buffer_size = num_pages * PAGE_SIZE;
err = system_table->boot_services->allocate_pages(
AllocateAnyPages,
EfiLoaderData,
num_pages,
(uint64_t*)&buffer
);
if(err != 0)
handle_error(err);
puts(L"Retrieve memory map");
err = system_table->boot_services->get_memory_map(
&buffer_size,
buffer,
map_key,
&descriptor_size,
&descriptor_version
);
if(err != 0)
handle_error(err);
return buffer;
}
size_t efi_main(EfiHandle _image_handle, EfiSystemTable *_system_table) {
image_handle = _image_handle;
system_table = _system_table;
size_t map_key;
get_memory_map(&map_key);
system_table->boot_services->exit_boot_services(image_handle, map_key);
return 0;
}
Ссылка на репозиторий.