@@ -213,19 +213,28 @@ static void setup_64bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t g
213213#define MEM_REGION_FLAG_EXECUTOR_CODE (1 << 3)
214214#define MEM_REGION_FLAG_GPA0 (1 << 5)
215215#define MEM_REGION_FLAG_NO_HOST_MEM (1 << 6)
216+ #define MEM_REGION_FLAG_REMAINING (1 << 7)
216217
217218struct mem_region {
218219 uint64 gpa ;
219220 int pages ;
220221 uint32 flags ;
221222};
222223
224+ struct syzos_boot_args {
225+ uint32 region_count ;
226+ uint32 reserved ;
227+ struct mem_region regions [];
228+ };
229+
223230// SYZOS guest virtual memory layout (must be in sync with executor/kvm.h):
224231static const struct mem_region syzos_mem_regions [] = {
225232 // AMD64 fixed data structures (5 pages: Zero, GDT, PML4, PDP, PD).
226233 {X86_SYZOS_ADDR_ZERO , 5 , MEM_REGION_FLAG_GPA0 },
227- // High fixed data (IDT, TSS).
228- {X86_SYZOS_ADDR_VAR_IDT , 11 , 0 },
234+ // High fixed data (IDT, TSS). Reduced to 10 pages to make room for Boot Args.
235+ {X86_SYZOS_ADDR_VAR_IDT , 10 , 0 },
236+ // Boot Configuration Page.
237+ {X86_SYZOS_ADDR_BOOT_ARGS , 1 , 0 },
229238 // Dynamic Page Table Pool.
230239 {X86_SYZOS_ADDR_PT_POOL , X86_SYZOS_PT_POOL_SIZE , 0 },
231240 // SMRAM memory.
@@ -246,6 +255,8 @@ static const struct mem_region syzos_mem_regions[] = {
246255 {X86_SYZOS_PER_VCPU_REGIONS_BASE , (KVM_MAX_VCPU * X86_SYZOS_L1_VCPU_REGION_SIZE ) / KVM_PAGE_SIZE , 0 },
247256 // IOAPIC memory.
248257 {X86_SYZOS_ADDR_IOAPIC , 1 , 0 },
258+ // Remainder of memory (Unused Heap). Must be last.
259+ {X86_SYZOS_ADDR_UNUSED , 0 , MEM_REGION_FLAG_REMAINING },
249260};
250261#endif
251262
@@ -376,15 +387,25 @@ static void setup_pg_table(struct kvm_syz_vm* vm)
376387
377388 // Zero-out the PT Pool memory.
378389 memset (vm -> pt_pool_mem , 0 , X86_SYZOS_PT_POOL_SIZE * KVM_PAGE_SIZE );
379-
380390 // Zero-out the fixed system pages (PML4/PDP/PD).
381- // They are in the first 5 pages of gpa0_mem.
382391 memset (vm -> gpa0_mem , 0 , 5 * KVM_PAGE_SIZE );
383392
384393 // Map all the regions defined in setup_vm()
385- for (size_t i = 0 ; i < sizeof (syzos_mem_regions ) / sizeof (syzos_mem_regions [0 ]); i ++ )
386- total -= map_4k_region (vm , & alloc , syzos_mem_regions [i ].gpa , syzos_mem_regions [i ].pages );
387- map_4k_region (vm , & alloc , X86_SYZOS_ADDR_UNUSED , total );
394+ for (size_t i = 0 ; i < sizeof (syzos_mem_regions ) / sizeof (syzos_mem_regions [0 ]); i ++ ) {
395+ int pages = syzos_mem_regions [i ].pages ;
396+ if (syzos_mem_regions [i ].flags & MEM_REGION_FLAG_REMAINING ) {
397+ if (total < 0 )
398+ fail ("Guest memory accounting underflow" );
399+ pages = total ;
400+ }
401+ map_4k_region (vm , & alloc , syzos_mem_regions [i ].gpa , pages );
402+
403+ // Only consume 'total' if the region is actually backed by host RAM.
404+ if (!(syzos_mem_regions [i ].flags & MEM_REGION_FLAG_NO_HOST_MEM ))
405+ total -= pages ;
406+ if (syzos_mem_regions [i ].flags & MEM_REGION_FLAG_REMAINING )
407+ break ;
408+ }
388409}
389410
390411// A 64-bit GDT entry for a code or data segment.
@@ -1152,12 +1173,18 @@ static void setup_vm(int vmfd, struct kvm_syz_vm* vm)
11521173{
11531174 struct addr_size allocator = {.addr = vm -> host_mem , .size = vm -> total_pages * KVM_PAGE_SIZE };
11541175 int slot = 0 ; // Slot numbers do not matter, they just have to be different.
1176+ struct syzos_boot_args * boot_args = NULL ;
11551177
11561178 for (size_t i = 0 ; i < sizeof (syzos_mem_regions ) / sizeof (syzos_mem_regions [0 ]); i ++ ) {
11571179 const struct mem_region * r = & syzos_mem_regions [i ];
11581180 if (r -> flags & MEM_REGION_FLAG_NO_HOST_MEM )
11591181 continue ;
1160- struct addr_size next = alloc_guest_mem (& allocator , r -> pages * KVM_PAGE_SIZE );
1182+
1183+ size_t pages = r -> pages ;
1184+ if (r -> flags & MEM_REGION_FLAG_REMAINING )
1185+ pages = allocator .size / KVM_PAGE_SIZE ;
1186+
1187+ struct addr_size next = alloc_guest_mem (& allocator , pages * KVM_PAGE_SIZE );
11611188 uint32 flags = 0 ;
11621189 if (r -> flags & MEM_REGION_FLAG_DIRTY_LOG )
11631190 flags |= KVM_MEM_LOG_DIRTY_PAGES ;
@@ -1169,14 +1196,24 @@ static void setup_vm(int vmfd, struct kvm_syz_vm* vm)
11691196 vm -> gpa0_mem = next .addr ;
11701197 if (r -> gpa == X86_SYZOS_ADDR_PT_POOL )
11711198 vm -> pt_pool_mem = next .addr ;
1199+
1200+ if (r -> gpa == X86_SYZOS_ADDR_BOOT_ARGS ) {
1201+ boot_args = (struct syzos_boot_args * )next .addr ;
1202+ boot_args -> region_count = sizeof (syzos_mem_regions ) / sizeof (syzos_mem_regions [0 ]);
1203+ for (size_t k = 0 ; k < boot_args -> region_count ; k ++ )
1204+ boot_args -> regions [k ] = syzos_mem_regions [k ];
1205+ }
1206+
1207+ if ((r -> flags & MEM_REGION_FLAG_REMAINING ) && boot_args )
1208+ boot_args -> regions [i ].pages = pages ;
1209+
11721210 if (r -> flags & MEM_REGION_FLAG_EXECUTOR_CODE )
11731211 install_syzos_code (next .addr , next .size );
11741212 vm_set_user_memory_region (vmfd , slot ++ , flags , r -> gpa , next .size , (uintptr_t )next .addr );
1175- }
11761213
1177- // Map the remaining pages at an unused address.
1178- struct addr_size next = alloc_guest_mem ( & allocator , allocator . size ) ;
1179- vm_set_user_memory_region ( vmfd , slot ++ , 0 , X86_SYZOS_ADDR_UNUSED , next . size , ( uintptr_t ) next . addr );
1214+ if ( r -> flags & MEM_REGION_FLAG_REMAINING )
1215+ break ;
1216+ }
11801217}
11811218#endif
11821219
@@ -1289,4 +1326,4 @@ static long syz_kvm_assert_syzos_uexit(volatile long a0, volatile long a1, volat
12891326}
12901327#endif
12911328
1292- #endif // EXECUTOR_COMMON_KVM_AMD64_H
1329+ #endif // EXECUTOR_COMMON_KVM_AMD64_H
0 commit comments