From 9115ba95c97b58fb060ba15c325aca44432bad9d Mon Sep 17 00:00:00 2001 From: yaya Date: Sun, 1 Sep 2024 16:36:37 +0800 Subject: [PATCH] =?UTF-8?q?=EF=BB=BF.=20=E4=BF=AE=E6=AD=A3=E5=87=BD?= =?UTF-8?q?=E6=95=B0=20map=20--unmap=3D=20.=20=E5=A2=9E=E5=8A=A0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=20map=20--alloc-only=EF=BC=8C=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E6=89=B9=E5=A4=84=E7=90=86=E5=88=86=E9=85=8D=E8=87=AA=E7=94=B1?= =?UTF-8?q?=E5=86=85=E5=AD=98=E3=80=82=20=20=20=E4=BE=8B=E5=A6=82=EF=BC=9A?= =?UTF-8?q?map=20--alloc-only=20(md)0+0x1b61b0=20(3)=20//=E5=88=86?= =?UTF-8?q?=E9=85=8D0x1b61b0=E6=89=87=E5=8C=BA=E8=87=AA=E7=94=B1=E6=89=87?= =?UTF-8?q?=E5=8C=BA=20=20=20=20=20=20=20=20=20map=20--status=3D3=20=20=20?= =?UTF-8?q?=20=20=20=20=20=20set=20add=3D%=3F%=20=20//=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E5=88=86=E9=85=8D=E7=9A=84=E8=87=AA=E7=94=B1=E5=86=85=E5=AD=98?= =?UTF-8?q?=20.=20=E5=8A=A0=E5=BF=AB=E9=9D=9E=E5=8E=8B=E7=BC=A9=E6=96=87?= =?UTF-8?q?=E4=BB=B6(img,iso,=E9=9D=99=E6=80=81vhd)=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E5=88=B0=E8=99=9A=E6=8B=9F=E6=9C=BA=E5=86=85=E5=AD=98=E7=9A=84?= =?UTF-8?q?=E9=80=9F=E5=BA=A6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog_UEFI.txt | 8 +++++ stage2/builtins.c | 83 +++++++++++++++++++++++++++++++++++++++++++++- stage2/disk_io.c | 7 ++-- 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/ChangeLog_UEFI.txt b/ChangeLog_UEFI.txt index 4ad34a1..83ba67a 100644 --- a/ChangeLog_UEFI.txt +++ b/ChangeLog_UEFI.txt @@ -1,4 +1,12 @@ 更新说明: +2024-09-01 (yaya) + 修正函数 map --unmap= + 增加参数 map --alloc-only,用于批处理分配自由内存。 + 例如:map --alloc-only (md)0+0x1b61b0 (3) //分配0x1b61b0扇区自由扇区 + map --status=3 + set add=%?% //返回分配的自由内存 + 加快非压缩文件(img,iso,静态vhd)加载到虚拟机内存的速度。 + 2024-02-26 (yaya) 改进uuid/vol函数,支持10个以上分区。 diff --git a/stage2/builtins.c b/stage2/builtins.c index 82f31a4..afdb82f 100644 --- a/stage2/builtins.c +++ b/stage2/builtins.c @@ -7471,6 +7471,7 @@ map_func (char *arg, int flags) //对设备进行映射 返回: 0/1=失败/成 int prefer_top = 0; int no_hook = 0; int vhd_disk = 0; + int alloc_only = 0; vhd_start_sector = 0; //struct master_and_dos_boot_sector *BS = (struct master_and_dos_boot_sector *) RAW_ADDR (0x8000); @@ -7864,6 +7865,10 @@ struct drive_map_slot { return 1; } + else if (grub_memcmp (arg, "--alloc-only", 12) == 0) //仅分配内存,不用复制 2024-09-01 + { + alloc_only = 1; + } else break; arg = skip_to (0, arg); //跳到空格后 @@ -8556,11 +8561,49 @@ struct drive_map_slot if (status != GRUB_EFI_SUCCESS) //如果失败 { printf_errinfo ("out of map memory: %d\n",(int)status); + errnum = ERR_WONT_FIT; //2024-09-01 return 0; } } /////////////////////////////////////////////////////////////////////////////////////////////////////以上插入分配内存 +/* +VHD测试 +镜像:qbus_gd.vhd 716Mb(包含qbus);qbus_dt.vhd 642Mb;hdd_boot_gd.vhd(无qbus) +环境:QEMU虚拟机; VirtualBox虚拟机; 笔记本电脑。 +条件1:不加载到内存/加载到内存 +条件2:使用grub_read读文件簇/使用read_blocks读碎片块 +条件3:U盘/SSD固态盘 +-------------------------------------------------------------------------------------------------------------- +环境 镜像 条件1 条件2 条件3 启动时间(秒) 说明 +-------------------------------------------------------------------------------------------------------------- +QEMU hdd_boot_gd.vhd map 可以正常启动 +QEMU qbus_gd.vhd map 可以正常启动 +QEMU qbus_gd.vhd map --mem grub_read U盘 167 +QEMU qbus_gd.vhd map --mem read_blocks U盘 94 +QEMU qbus_dt.vhd map 不能启动 +QEMU qbus_dt.vhd map --mem grub_read U盘 93 +-------------------------------------------------------------------------------------------------------------- +VirtualBox hdd_boot_gd.vhd map 可以正常启动 +VirtualBox qbus_gd.vhd map 不能启动(一直转圈) +VirtualBox qbus_gd.vhd map --mem grub_read U盘 503 +VirtualBox qbus_gd.vhd map --mem read_blocks U盘 150 +-------------------------------------------------------------------------------------------------------------- +笔记本电脑 hdd_boot_gd.vhd map 可以正常启动 +笔记本电脑 qbus_gd.vhd map 不能启动(转圈之后重启) +笔记本电脑 qbus_gd.vhd map --mem grub_read U盘 85 +笔记本电脑 qbus_gd.vhd map --mem read_blocks U盘 82 +笔记本电脑 qbus_gd.vhd map --mem grub_read SSD固态盘 2 +笔记本电脑 qbus_gd.vhd map --mem read_blocks SSD固态盘 1 +-------------------------------------------------------------------------------------------------------------- + +结论: +1. 加载速度取决于UEFI固件。实机区别不大,虚拟机有改进。 +2. 静态VHD映射为硬盘,可以是内存盘,也可以不是。可以使用chainloader加载,也可以使用ntboot加载。 +3. 动态/差分VHD使用chainloader加载,必须映射为内存盘。 +4. 动态/差分VHD使用ntboot加载,内部必须包含BCD。 + +*/ mem_ok: sector_count = bytes_needed >> 9; //扇区计数=加载到内存的扇区数,每扇区0x200字节 // sector_count = bytes_needed >> buf_geom.log2_sector_size; //扇区计数=需要扇区 @@ -8569,9 +8612,47 @@ struct drive_map_slot if ((to == 0xffff || to == ram_drive) && !compressed_file) //如果映像在内存中,并且没有压缩,我们可以简单地移动它。 { // if (bytes_needed != start_byte) //如果需要字节!=起始字节 + if (!alloc_only) //不是仅分配 2024-09-01 + { + printf ("Copying data, please wait......\n"); grub_memmove64 (alloc, start_byte, filemax); + } } - else //如果映像不在内存中,或者被压缩 + else if (!compressed_file) //如果映像不在内存,而且没有压缩(img,iso,静态vhd),使用读碎片块方法 2024-09-01 加快静态vhd的读取速度 + { + //在QEMU虚拟机测试qbus_gd.vhd,716Mb,用时94秒。如果使用grub_read函数,用时167秒。94/167=56% + //在QEMU虚拟机测试qbus_dt.vhd,642Mb,用时93秒。 + //在实机测试qbus_gd.vhd(ssd固态硬盘),716Mb,用时1秒。如果使用grub_read函数,用时2秒。 + //在实机测试qbus_gd.vhd(2.0启动U盘),716Mb,用时82秒。如果使用grub_read函数,用时85秒。 + //在Qracle VM虚拟机测试qbus_gd.vhd,716Mb,用时150秒。如果使用grub_read函数,用时503秒。150/503=30% + //静态VHD(内涵qbus)不加载到内存,QEMU虚拟机可以启动成功,Qracle VM虚拟机一直转圈,实机转圈后重启。 + unsigned long long add = alloc; //内存扇区地址 + filepos = skip_sectors << 9; + + for (k = 0; k < blklst_num_entries; k++) + { + struct grub_disk_data *d = 0; + grub_efi_block_io_t *bio = 0; + d = get_device_by_drive (to,0); + if (!d) + return (!(errnum = ERR_NO_DISK)); + bio = d->block_io; //块io + printf ("Copying data, please wait......\n"); + status = efi_call_5 (bio->read_blocks, bio, bio->media->media_id, (grub_efi_uint64_t) map_start_sector[k], + (grub_efi_uintn_t) map_num_sectors[k] << 9, (char *)(grub_size_t)add); //读写(读,本身块io,media_id,扇区,字节尺寸,缓存) + if (status) //如果错误 + { + grub_close (); //关闭to驱动器 + errnum = ERR_READ; + return 0; + } + + add += map_num_sectors[k] << 9; + filepos += map_num_sectors[k] << 9; + } + blklst_num_entries = 1; //如果文件有碎片,加载到内存后就连续了。避免后续设置碎片。 + } + else //如果映像不在内存,而且被压缩,使用读文件簇方法 { unsigned long long read_result; //读结果 unsigned long long read_size = bytes_needed; //读尺寸 diff --git a/stage2/disk_io.c b/stage2/disk_io.c index f8ec800..2a66ed9 100644 --- a/stage2/disk_io.c +++ b/stage2/disk_io.c @@ -2690,7 +2690,7 @@ uninstall (unsigned int drive, struct grub_disk_data *d) //释放磁盘映射 //卸载映射内存 if (d->to_drive == 0xff && d->to_log2_sector != 0xb) //内存映射 - efi_call_2 (b->free_pages, d->start_sector >> 9, d->sector_count >> 3); //释放页 + efi_call_2 (b->free_pages, d->start_sector << 9, d->sector_count >> 3); //释放页 2024-09-01 //卸载虚拟磁盘 if (d->vdisk) //是映射磁盘,并且挂载 @@ -3029,7 +3029,8 @@ grub_efidisk_readwrite (int drive, grub_disk_addr_t sector, //动态vhd处理 if (df->vhd_disk & 1 && !vhd_read) //vhd不加载到内存,并且不是dec_vhd读磁盘 { - filepos = sector << 9; +// filepos = sector << 9; + filepos = lba_byte; //2024-09-01 dec_vhd_read ((unsigned long long)(grub_size_t)buf, (unsigned long long)size, read_write); return 0; } @@ -4777,7 +4778,7 @@ grub_load_image (grub_efi_device_path_t *path, const char *filename, void *boot_ grub_efi_print_device_path(boot_file); if (!boot_image) { - //加载映像 将EFI映像加载到内存中 要读磁盘 + //加载映像 将EFI映像加载到内存中 此函数要读磁盘 status = efi_call_6 (b->load_image, TRUE, //启动策略. 如果为true,则表示请求来自引导管理器,并且引导管理器正尝试将设备路径作为引导选择加载 grub_efi_image_handle, //调用方的映像句柄. 此字段用于为正在加载的映像初始化EFI加载的映像协议的父句柄字段。 boot_file, //从中加载映像的设备句柄特定文件路径