]> glassweightruler.freedombox.rocks Git - Ventoy.git/commitdiff
Add support for boot conf replace for distro which use systemd-boot in UEFI mode.
authorlongpanda <admin@ventoy.net>
Sat, 23 Oct 2021 15:15:25 +0000 (23:15 +0800)
committerlongpanda <admin@ventoy.net>
Sat, 23 Oct 2021 15:15:25 +0000 (23:15 +0800)
(#1170)

EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.c
EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.h
EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/VentoyProtocol.c
EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/VtoyUtil/VtoyUtil.h
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c
GRUB2/MOD_SRC/grub-2.04/include/grub/ventoy.h

index 3b7cf24475b5a1d59c15614ab5b25170dd579cf6..cfcf41059dfd8d6b9b137731a3b7e4ff0c8ef98d 100644 (file)
@@ -59,6 +59,9 @@ static grub_env_set_pf grub_env_set = NULL;
 ventoy_grub_param_file_replace *g_file_replace_list = NULL;
 ventoy_efi_file_replace g_efi_file_replace;
 
+ventoy_grub_param_file_replace *g_img_replace_list = NULL;
+ventoy_efi_file_replace g_img_file_replace;
+
 CONST CHAR16 gIso9660EfiDriverPath[] = ISO9660_EFI_DRIVER_PATH;
 CONST CHAR16 gUdfEfiDriverPath[] = UDF_EFI_DRIVER_PATH;
 
@@ -707,6 +710,35 @@ STATIC EFI_STATUS EFIAPI ventoy_load_isoefi_driver(IN EFI_HANDLE ImageHandle)
     return EFI_SUCCESS;
 }
 
+STATIC EFI_STATUS ventoy_proc_img_replace_name(ventoy_grub_param_file_replace *replace)
+{
+    UINT32 i;
+    char tmp[256];
+
+    if (replace->magic != GRUB_IMG_REPLACE_MAGIC)
+    {
+        return EFI_SUCCESS;
+    }
+
+    if (replace->old_file_name[0][0] == 0)
+    {
+        return EFI_SUCCESS;
+    }
+
+    AsciiStrCpyS(tmp, sizeof(tmp), replace->old_file_name[0]);
+    
+    for (i = 0; i < 256 && tmp[i]; i++)
+    {
+        if (tmp[i] == '/')
+        {
+            tmp[i] = '\\';
+        }
+    }
+
+    AsciiStrCpyS(replace->old_file_name[0], 256, tmp);
+    return EFI_SUCCESS;
+}
+
 STATIC EFI_STATUS EFIAPI ventoy_parse_cmdline(IN EFI_HANDLE ImageHandle)
 {   
     UINT32 i = 0;
@@ -817,6 +849,19 @@ STATIC EFI_STATUS EFIAPI ventoy_parse_cmdline(IN EFI_HANDLE ImageHandle)
         old_cnt > 3 ? g_file_replace_list->old_file_name[3] : ""
         );
 
+    g_img_replace_list = &pGrubParam->img_replace;
+    ventoy_proc_img_replace_name(g_img_replace_list);
+    old_cnt = g_img_replace_list->old_file_cnt;
+    debug("img replace: magic:0x%x virtid:%u name count:%u <%a> <%a> <%a> <%a>",
+        g_img_replace_list->magic,
+        g_img_replace_list->new_file_virtual_id,
+        old_cnt,
+        old_cnt > 0 ? g_img_replace_list->old_file_name[0] : "",
+        old_cnt > 1 ? g_img_replace_list->old_file_name[1] : "",
+        old_cnt > 2 ? g_img_replace_list->old_file_name[2] : "",
+        old_cnt > 3 ? g_img_replace_list->old_file_name[3] : ""
+        );
+    
     pPos = StrStr(pCmdLine, L"mem:");
     chain = (ventoy_chain_head *)StrHexToUintn(pPos + 4);
 
@@ -1050,7 +1095,8 @@ EFI_STATUS EFIAPI ventoy_boot(IN EFI_HANDLE ImageHandle)
                 gST->ConIn->Reset(gST->ConIn, FALSE);
             }
             
-            if (g_file_replace_list && g_file_replace_list->magic == GRUB_FILE_REPLACE_MAGIC)
+            if ((g_file_replace_list && g_file_replace_list->magic == GRUB_FILE_REPLACE_MAGIC) ||
+                (g_img_replace_list && g_img_replace_list->magic == GRUB_IMG_REPLACE_MAGIC))
             {
                 ventoy_wrapper_push_openvolume(pFile->OpenVolume);
                 pFile->OpenVolume = ventoy_wrapper_open_volume;
index 04b67e797c417d40f8a180bb1d45a44b66d24550..30ed3c5c9cb71ef6385db4aa633491a996d37e99 100644 (file)
@@ -243,6 +243,7 @@ typedef int (*grub_env_printf_pf)(const char *fmt, ...);
 #pragma pack(1)
 
 #define GRUB_FILE_REPLACE_MAGIC  0x1258BEEF
+#define GRUB_IMG_REPLACE_MAGIC   0x1259BEEF
 
 typedef struct ventoy_efi_file_replace
 {
@@ -267,6 +268,7 @@ typedef struct ventoy_grub_param
     grub_env_get_pf grub_env_get;
     grub_env_set_pf grub_env_set;
     ventoy_grub_param_file_replace file_replace;
+    ventoy_grub_param_file_replace img_replace;
     grub_env_printf_pf grub_env_printf;    
 }ventoy_grub_param;
 
@@ -396,6 +398,7 @@ extern ventoy_virt_chunk *g_virt_chunk;
 extern UINT32 g_virt_chunk_num;
 extern vtoy_block_data gBlockData;
 extern ventoy_efi_file_replace g_efi_file_replace;
+extern ventoy_efi_file_replace g_img_file_replace;
 extern ventoy_sector_flag *g_sector_flag;
 extern UINT32 g_sector_flag_num;
 extern BOOLEAN gMemdiskMode;
@@ -403,6 +406,7 @@ extern BOOLEAN gSector512Mode;
 extern UINTN g_iso_buf_size;
 extern UINT8 *g_iso_data_buf;
 extern ventoy_grub_param_file_replace *g_file_replace_list;
+extern ventoy_grub_param_file_replace *g_img_replace_list;
 extern BOOLEAN g_fixup_iso9660_secover_enable;
 extern EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *g_con_simple_input_ex;
 extern BOOLEAN g_fix_windows_1st_cdrom_issue;
index 9c8fc0e741b529d6c004feef594c30ca4f69c9c7..1f44355b28a48c678bd63de983098f5681350f62 100644 (file)
@@ -37,6 +37,9 @@
 #include <Protocol/DriverBinding.h>
 #include <Ventoy.h>
 
+#define ASSIGN_REPLACE(This, replace) \
+    replace = (This->FlushEx == ventoy_wrapper_file_flush_ex) ? &g_efi_file_replace : &g_img_file_replace
+
 UINT8 *g_iso_data_buf = NULL;
 UINTN g_iso_buf_size = 0;
 BOOLEAN gMemdiskMode = FALSE;
@@ -1245,6 +1248,15 @@ ventoy_wrapper_file_flush_ex(EFI_FILE_HANDLE This, EFI_FILE_IO_TOKEN *Token)
        return EFI_SUCCESS;
 }
 
+/* Ex version */
+STATIC EFI_STATUS EFIAPI
+ventoy_wrapper_file_flush_ex_img(EFI_FILE_HANDLE This, EFI_FILE_IO_TOKEN *Token)
+{
+    (VOID)This;
+    (VOID)Token;
+       return EFI_SUCCESS;
+}
+
 
 STATIC EFI_STATUS EFIAPI
 ventoy_wrapper_file_write(EFI_FILE_HANDLE This, UINTN *Len, VOID *Data)
@@ -1270,19 +1282,20 @@ ventoy_wrapper_file_close(EFI_FILE_HANDLE This)
     return EFI_SUCCESS;
 }
 
-
 STATIC EFI_STATUS EFIAPI
 ventoy_wrapper_file_set_pos(EFI_FILE_HANDLE This, UINT64 Position)
 {
-    (VOID)This;
-        
-    if (Position <= g_efi_file_replace.FileSizeBytes)
+    ventoy_efi_file_replace *replace = NULL;
+
+    ASSIGN_REPLACE(This, replace);
+    
+    if (Position <= replace->FileSizeBytes)
     {
-        g_efi_file_replace.CurPos = Position;
+        replace->CurPos = Position;
     }
     else
     {
-        g_efi_file_replace.CurPos = g_efi_file_replace.FileSizeBytes;
+        replace->CurPos = replace->FileSizeBytes;
     }
     
     return EFI_SUCCESS;
@@ -1291,9 +1304,11 @@ ventoy_wrapper_file_set_pos(EFI_FILE_HANDLE This, UINT64 Position)
 STATIC EFI_STATUS EFIAPI
 ventoy_wrapper_file_get_pos(EFI_FILE_HANDLE This, UINT64 *Position)
 {
-    (VOID)This;
+    ventoy_efi_file_replace *replace = NULL;
 
-    *Position = g_efi_file_replace.CurPos;
+    ASSIGN_REPLACE(This, replace);
+
+    *Position = replace->CurPos;
 
     return EFI_SUCCESS;
 }
@@ -1303,6 +1318,9 @@ STATIC EFI_STATUS EFIAPI
 ventoy_wrapper_file_get_info(EFI_FILE_HANDLE This, EFI_GUID *Type, UINTN *Len, VOID *Data)
 {
     EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data;
+    ventoy_efi_file_replace *replace = NULL;
+
+    ASSIGN_REPLACE(This, replace);
 
     debug("ventoy_wrapper_file_get_info ... %u", *Len);
 
@@ -1320,8 +1338,8 @@ ventoy_wrapper_file_get_info(EFI_FILE_HANDLE This, EFI_GUID *Type, UINTN *Len, V
     ZeroMem(Data, sizeof(EFI_FILE_INFO));
 
     Info->Size = sizeof(EFI_FILE_INFO);
-    Info->FileSize = g_efi_file_replace.FileSizeBytes;
-    Info->PhysicalSize = g_efi_file_replace.FileSizeBytes;
+    Info->FileSize = replace->FileSizeBytes;
+    Info->PhysicalSize = replace->FileSizeBytes;
     Info->Attribute = EFI_FILE_READ_ONLY;
     //Info->FileName = EFI_FILE_READ_ONLY;
 
@@ -1335,23 +1353,24 @@ ventoy_wrapper_file_read(EFI_FILE_HANDLE This, UINTN *Len, VOID *Data)
 {
     EFI_LBA Lba;
     UINTN ReadLen = *Len;
-    
-    (VOID)This;
+    ventoy_efi_file_replace *replace = NULL;
 
+    ASSIGN_REPLACE(This, replace);
+    
     debug("ventoy_wrapper_file_read ... %u", *Len);
 
-    if (g_efi_file_replace.CurPos + ReadLen > g_efi_file_replace.FileSizeBytes)
+    if (replace->CurPos + ReadLen > replace->FileSizeBytes)
     {
-        ReadLen = g_efi_file_replace.FileSizeBytes - g_efi_file_replace.CurPos;
+        ReadLen = replace->FileSizeBytes - replace->CurPos;
     }
 
-    Lba = g_efi_file_replace.CurPos / 2048 + g_efi_file_replace.BlockIoSectorStart;
+    Lba = replace->CurPos / 2048 + replace->BlockIoSectorStart;
 
     ventoy_block_io_read(NULL, 0, Lba, ReadLen, Data);
 
     *Len = ReadLen;
 
-    g_efi_file_replace.CurPos += ReadLen;
+    replace->CurPos += ReadLen;
 
     return EFI_SUCCESS;
 }
@@ -1362,7 +1381,7 @@ ventoy_wrapper_file_read_ex(IN EFI_FILE_PROTOCOL *This, IN OUT EFI_FILE_IO_TOKEN
        return ventoy_wrapper_file_read(This, &(Token->BufferSize), Token->Buffer);
 }
 
-STATIC EFI_STATUS EFIAPI ventoy_wrapper_file_procotol(EFI_FILE_PROTOCOL *File)
+STATIC EFI_STATUS EFIAPI ventoy_wrapper_file_procotol(EFI_FILE_PROTOCOL *File, BOOLEAN Img)
 {
     File->Revision    = EFI_FILE_PROTOCOL_REVISION2;
     File->Open        = ventoy_wrapper_fs_open;
@@ -1378,7 +1397,7 @@ STATIC EFI_STATUS EFIAPI ventoy_wrapper_file_procotol(EFI_FILE_PROTOCOL *File)
     File->OpenEx      = ventoy_wrapper_file_open_ex;
     File->ReadEx      = ventoy_wrapper_file_read_ex;
     File->WriteEx     = ventoy_wrapper_file_write_ex;
-    File->FlushEx     = ventoy_wrapper_file_flush_ex;
+    File->FlushEx     = Img ? ventoy_wrapper_file_flush_ex_img : ventoy_wrapper_file_flush_ex;
 
     return EFI_SUCCESS;
 }
@@ -1397,6 +1416,7 @@ STATIC EFI_STATUS EFIAPI ventoy_wrapper_file_open
     UINT64 Sectors = 0;
     EFI_STATUS Status = EFI_SUCCESS;
     CHAR8 TmpName[256];
+    CHAR8 OldName[256];
     ventoy_virt_chunk *virt = NULL;
 
     debug("## ventoy_wrapper_file_open <%s> ", Name);
@@ -1417,6 +1437,7 @@ STATIC EFI_STATUS EFIAPI ventoy_wrapper_file_open
         return Status;
     }
 
+
     if (g_file_replace_list && g_file_replace_list->magic == GRUB_FILE_REPLACE_MAGIC &&
         g_file_replace_list->new_file_virtual_id < g_virt_chunk_num)
     {
@@ -1427,7 +1448,7 @@ STATIC EFI_STATUS EFIAPI ventoy_wrapper_file_open
             {
                 g_original_fclose(*New);
                 *New = &g_efi_file_replace.WrapperHandle;
-                ventoy_wrapper_file_procotol(*New);
+                ventoy_wrapper_file_procotol(*New, FALSE);
 
                 virt = g_virt_chunk + g_file_replace_list->new_file_virtual_id;
 
@@ -1453,6 +1474,49 @@ STATIC EFI_STATUS EFIAPI ventoy_wrapper_file_open
         }
     }
 
+
+
+    if (g_img_replace_list && g_img_replace_list->magic == GRUB_IMG_REPLACE_MAGIC &&
+        g_img_replace_list->new_file_virtual_id < g_virt_chunk_num)
+    {
+        AsciiSPrint(TmpName, sizeof(TmpName), "%s", Name);
+        for (j = 0; j < g_img_replace_list->old_file_cnt; j++)
+        {
+            AsciiStrCpyS(OldName, sizeof(OldName), g_img_replace_list[i].old_file_name[j]);
+            if ((0 == AsciiStrCmp(OldName, TmpName)) ||
+                 (AsciiStrnCmp(OldName, "\\loader\\entries", 15) == 0 && 
+                  AsciiStrCmp(OldName + 16, TmpName) == 0
+                  )  
+                )
+            {
+                g_original_fclose(*New);
+                *New = &g_img_file_replace.WrapperHandle;
+                ventoy_wrapper_file_procotol(*New, TRUE);
+
+                virt = g_virt_chunk + g_img_replace_list->new_file_virtual_id;
+
+                Sectors = (virt->mem_sector_end - virt->mem_sector_start) + (virt->remap_sector_end - virt->remap_sector_start);
+                
+                g_img_file_replace.BlockIoSectorStart = virt->mem_sector_start;
+                g_img_file_replace.FileSizeBytes = Sectors * 2048;
+
+                if (gDebugPrint)
+                {
+                    debug("## ventoy_wrapper_file_open2 <%s> BlockStart:%lu Sectors:%lu Bytes:%lu", Name,
+                        g_img_file_replace.BlockIoSectorStart, Sectors, Sectors * 2048);
+                    sleep(3);
+                }
+                
+                return Status;
+            }
+        }
+
+        if (StrCmp(Name, L"\\loader\\entries") == 0)
+        {
+            (*New)->Open = ventoy_wrapper_file_open;
+        }
+    }
+
     return Status;
 }
 
index 5f3ae6d0ccaffac6cd8027591ff0b6f26a3bff39..702a3f5ffe06d89f71a0687c71888a882149b558 100644 (file)
@@ -41,6 +41,7 @@ typedef struct ventoy_grub_param
     grub_env_get_pf grub_env_get;
     grub_env_set_pf grub_env_set;
     ventoy_grub_param_file_replace file_replace;
+    ventoy_grub_param_file_replace img_replace;
     grub_env_printf_pf grub_env_printf;    
 }ventoy_grub_param;
 #pragma pack()
index 4b0d95b62b2bd13ff8d2b61f5ad91b0c3348be0f..248a76820c8447c39093d0a60526bc05762e7211 100644 (file)
@@ -2946,6 +2946,7 @@ static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, ch
     }
 
     grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
+    grub_memset(&g_grub_param->img_replace, 0, sizeof(g_grub_param->img_replace));
     VENTOY_CMD_RETURN(GRUB_ERR_NONE);
 }
 
@@ -2977,15 +2978,21 @@ static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int arg
     debug("Find conf replace for %s\n", args[1]);
 
     file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
-    if (!file)
+    if (file)
+    {
+        offset = grub_iso9660_get_last_file_dirent_pos(file);
+        grub_file_close(file);  
+    }
+    else if (node->img > 0)
+    {
+        offset = 0;
+    }
+    else
     {
         debug("<(loop)%s> NOT exist\n", node->orgconf);
         goto end;
     }
 
-    offset = grub_iso9660_get_last_file_dirent_pos(file);
-    grub_file_close(file);    
-
     file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
     if (!file)
     {
@@ -3008,6 +3015,13 @@ static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int arg
     g_conf_replace_node = node;
     g_conf_replace_offset = offset + 2;
 
+    if (node->img > 0)
+    {
+        g_grub_param->img_replace.magic = GRUB_IMG_REPLACE_MAGIC;
+        g_grub_param->img_replace.old_name_cnt = 1;
+        grub_snprintf(g_grub_param->img_replace.old_file_name[0], 256, "%s", node->orgconf);
+    }
+
     debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
 
 end:
index 3c51aa61296cad3110d044f52b77ad42b19b9233..82a5754d16b2c7fd4a58f4f8583e38f27c0ce7be 100644 (file)
@@ -925,6 +925,7 @@ typedef struct custom_boot
 typedef struct conf_replace
 {
     int pathlen;
+    int img;
     char isopath[256];
     char orgconf[256];
     char newconf[256];
@@ -1109,5 +1110,7 @@ int ventoy_chain_file_read(const char *path, int offset, int len, void *buf);
 
 #define ret_goto_end(a) ret = a; goto end;
 
+extern ventoy_grub_param *g_grub_param;
+
 #endif /* __VENTOY_DEF_H__ */
 
index 98296f7657b9b1c537d31b9b940ba10cd8275202..37910c76cc2b7e1dec25bf15a7dcf03c59cd65ca 100644 (file)
@@ -691,6 +691,7 @@ static grub_uint32_t ventoy_linux_get_virt_chunk_size(void)
 static void ventoy_linux_fill_virt_data(    grub_uint64_t isosize, ventoy_chain_head *chain)
 {
     int id = 0;
+    int virtid = 0;
     initrd_info *node;
     grub_uint64_t sector;
     grub_uint32_t offset;
@@ -738,6 +739,7 @@ static void ventoy_linux_fill_virt_data(    grub_uint64_t isosize, ventoy_chain_
         offset += g_ventoy_cpio_size;
         sector += cpio_secs + initrd_secs;
         cur++;
+        virtid++;
     }
 
     /* Lenovo EasyStartup need an addional sector for boundary check */
@@ -759,6 +761,7 @@ static void ventoy_linux_fill_virt_data(    grub_uint64_t isosize, ventoy_chain_
         offset += VTOY_APPEND_EXT_SIZE;
         sector += cpio_secs;
         cur++;
+        virtid++;
     }
 
     if (g_conf_replace_offset > 0)
@@ -776,9 +779,15 @@ static void ventoy_linux_fill_virt_data(    grub_uint64_t isosize, ventoy_chain_
 
         chain->virt_img_size_in_bytes += g_conf_replace_new_len_align;
 
+        if (g_grub_param->img_replace.magic == GRUB_IMG_REPLACE_MAGIC)
+        {
+            g_grub_param->img_replace.new_file_virtual_id = virtid;
+        }
+
         offset += g_conf_replace_new_len_align;
         sector += cpio_secs;
         cur++;
+        virtid++;
     }
 
     return;
index 53c1142baadaf8bb5e0ffabedcfb7b321038a323..e260440920cf25a123bbe0c46e58fa5f0b50ef62 100644 (file)
@@ -2005,6 +2005,7 @@ static int ventoy_plugin_custom_boot_check(VTOY_JSON *json, const char *isodisk)
 
 static int ventoy_plugin_conf_replace_entry(VTOY_JSON *json, const char *isodisk)
 {
+    int img = 0;
     const char *isof = NULL;
     const char *orgf = NULL;
     const char *newf = NULL;
@@ -2042,6 +2043,11 @@ static int ventoy_plugin_conf_replace_entry(VTOY_JSON *json, const char *isodisk
             node = grub_zalloc(sizeof(conf_replace));
             if (node)
             {
+                if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "img", &img))
+                {
+                    node->img = img;
+                }
+
                 node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", isof);
                 grub_snprintf(node->orgconf, sizeof(node->orgconf), "%s", orgf);
                 grub_snprintf(node->newconf, sizeof(node->newconf), "%s", newf);
@@ -2064,6 +2070,7 @@ static int ventoy_plugin_conf_replace_entry(VTOY_JSON *json, const char *isodisk
 
 static int ventoy_plugin_conf_replace_check(VTOY_JSON *json, const char *isodisk)
 {
+    int img = 0;
     const char *isof = NULL;
     const char *orgf = NULL;
     const char *newf = NULL;
@@ -2133,7 +2140,7 @@ static int ventoy_plugin_conf_replace_check(VTOY_JSON *json, const char *isodisk
                 }
                 else
                 {
-                    grub_printf("new:<%s> [OK]\n", newf);                    
+                    grub_printf("new1:<%s> [OK]\n", newf);                    
                 }
                 grub_file_close(file);
             }
@@ -2141,6 +2148,12 @@ static int ventoy_plugin_conf_replace_check(VTOY_JSON *json, const char *isodisk
             {
                 grub_printf("new:<%s> [NOT Exist]\n", newf);   
             }
+
+            if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "img", &img))
+            {
+                grub_printf("img:<%d>\n", img);           
+            }
+            
             grub_printf("\n");
         }
     }
index ee76b5bd21f380f3ff1f726582cce5416bad8f5d..5cb04d8bccb6e6e8f8bf4832ade979820af595e4 100644 (file)
@@ -242,6 +242,7 @@ typedef struct ventoy_img_chunk_list
 #pragma pack(1)
 
 #define GRUB_FILE_REPLACE_MAGIC  0x1258BEEF
+#define GRUB_IMG_REPLACE_MAGIC   0x1259BEEF
 
 typedef const char * (*grub_env_get_pf)(const char *name);
 typedef int (*grub_env_set_pf)(const char *name, const char *val);
@@ -260,6 +261,7 @@ typedef struct ventoy_grub_param
     grub_env_get_pf grub_env_get;
     grub_env_set_pf grub_env_set;
     ventoy_grub_param_file_replace file_replace;
+    ventoy_grub_param_file_replace img_replace;
     grub_env_printf_pf grub_env_printf;
 }ventoy_grub_param;