aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXianglai Li <lixianglai@loongson.cn>2025-05-06 16:09:46 +0800
committerSong Gao <gaosong@loongson.cn>2025-05-14 15:57:23 +0800
commita3d5f62254a48b7c260d5aa7bd8e8467a0bb8ea3 (patch)
treedcc7599a5f0de8b29066f3438cbc728196c62361
parentf4881c67ba8a852687566610949d8e9ab0542a31 (diff)
downloadqemu-a3d5f62254a48b7c260d5aa7bd8e8467a0bb8ea3.zip
qemu-a3d5f62254a48b7c260d5aa7bd8e8467a0bb8ea3.tar.gz
qemu-a3d5f62254a48b7c260d5aa7bd8e8467a0bb8ea3.tar.bz2
hw/loongarch/boot: Adjust the loading position of the initrd
When only the -kernel parameter is used to load the elf kernel, the initrd is loaded in the ram. If the initrd size is too large, the loading fails, resulting in a VM startup failure. This patch first loads initrd near the kernel. When the nearby memory space of the kernel is insufficient, it tries to load it to the starting position of high memory. If there is still not enough, qemu will report an error and ask the user to increase the memory space for the virtual machine to boot. Signed-off-by: Xianglai Li <lixianglai@loongson.cn> Message-Id: <20250506080946.817092-1-lixianglai@loongson.cn> Signed-off-by: Song Gao <gaosong@loongson.cn>
-rw-r--r--hw/loongarch/boot.c52
1 files changed, 43 insertions, 9 deletions
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 0324d6a..9b6292e 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -235,6 +235,45 @@ static int64_t load_loongarch_linux_image(const char *filename,
return size;
}
+static ram_addr_t alloc_initrd_memory(struct loongarch_boot_info *info,
+ uint64_t advice_start, ssize_t rd_size)
+{
+ hwaddr base, ram_size, gap, low_end;
+ ram_addr_t initrd_end, initrd_start;
+
+ base = VIRT_LOWMEM_BASE;
+ gap = VIRT_LOWMEM_SIZE;
+ initrd_start = advice_start;
+ initrd_end = initrd_start + rd_size;
+
+ ram_size = info->ram_size;
+ low_end = base + MIN(ram_size, gap);
+ if (initrd_end <= low_end) {
+ return initrd_start;
+ }
+
+ if (ram_size <= gap) {
+ error_report("The low memory too small for initial ram disk '%s',"
+ "You need to expand the ram",
+ info->initrd_filename);
+ exit(1);
+ }
+
+ /*
+ * Try to load initrd in the high memory
+ */
+ ram_size -= gap;
+ initrd_start = VIRT_HIGHMEM_BASE;
+ if (rd_size <= ram_size) {
+ return initrd_start;
+ }
+
+ error_report("The high memory too small for initial ram disk '%s',"
+ "You need to expand the ram",
+ info->initrd_filename);
+ exit(1);
+}
+
static int64_t load_kernel_info(struct loongarch_boot_info *info)
{
uint64_t kernel_entry, kernel_low, kernel_high;
@@ -263,15 +302,10 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info)
initrd_size = get_image_size(info->initrd_filename);
if (initrd_size > 0) {
initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB);
-
- if (initrd_offset + initrd_size > info->ram_size) {
- error_report("memory too small for initial ram disk '%s'",
- info->initrd_filename);
- exit(1);
- }
-
- initrd_size = load_image_targphys(info->initrd_filename, initrd_offset,
- info->ram_size - initrd_offset);
+ initrd_offset = alloc_initrd_memory(info, initrd_offset,
+ initrd_size);
+ initrd_size = load_image_targphys(info->initrd_filename,
+ initrd_offset, initrd_size);
}
if (initrd_size == (target_ulong)-1) {