diff --git a/ChangeLog_UEFI.txt b/ChangeLog_UEFI.txt index 83ba67a..12dfff9 100644 --- a/ChangeLog_UEFI.txt +++ b/ChangeLog_UEFI.txt @@ -1,4 +1,11 @@ 更新说明: +2024-12-16 (yaya) + 支持http网起。 + 例如:map (http)/imgs/pe.iso (cd) + chainloader (cd-1) + boor + 例如:/efi/grub/ext/ntboot (http)/imgs/pe.wim + 2024-09-01 (yaya) 修正函数 map --unmap= 增加参数 map --alloc-only,用于批处理分配自由内存。 diff --git a/menu.lst b/menu.lst index 0f644cc..a6c7771 100644 --- a/menu.lst +++ b/menu.lst @@ -131,6 +131,15 @@ title 使用外部命令 NTBOOT 启动 Windows 系统 /efi/grub/ext/ntboot (hdx,y)/win boot +title 使用 http 网起 iso 或者 img 镜象 +map (http)/imgs/pe.iso (cd) +chainloader (cd-1) +boor + +title 使用 http 及外部命令 NTBOOT 网启 wim 镜象 +/efi/grub/ext/ntboot (http)/imgs/pe.wim +boot + title 命令行 commandline diff --git a/stage2/asm.S b/stage2/asm.S index 3650827..e73d592 100644 --- a/stage2/asm.S +++ b/stage2/asm.S @@ -527,12 +527,12 @@ VARIABLE(pxe_tftp_open) //PXENV_TFTP_OPEN_t .space 128 # FileName[128]; 文件名 .word 0 # TFTPPort TFTP端口 .word 0 # PacketSize 包尺寸 - +/* //boot.c .align 8 VARIABLE(mbi) //multiboot_info .space (22 * 4) - +*/ /****************************************************************************/ /************************* 32-bit functions follow **************************/ @@ -656,7 +656,7 @@ VARIABLE(system_functions) //IMG(0x8300) .extent ABS(EXT_C(dir)) //61 .extent ABS(EXT_C(print_a_completion)) //62 .extent ABS(EXT_C(print_completions)) //63 - .extent ABS(EXT_C(devread)) //64 + .extent 0 //64 .extent ABS(EXT_C(probe_bpb)) //65 .extent ABS(EXT_C(probe_mbr)) //66 .extent ABS(EXT_C(unicode_to_utf8)) //67 @@ -726,7 +726,7 @@ VARIABLE(filesystem_type) //13 int //VARIABLE(query_block_entries) .extent ABS(EXT_C(grub_efi_image_handle)) //14 void * //VARIABLE(map_start_sector) - .extent ABS(EXT_C(grub_efi_system_table)) //15 struct grub_efi_system_table + .extent ABS(EXT_C(grub_efi_system_table)) //15 grub_efi_system_table * .extent ABS(EXT_C(buf_geom)) //16 geometry .extent ABS(EXT_C(tmp_geom)) //17 geometry VARIABLE(CONFIG_ENTRIES) //18 char * @@ -752,16 +752,20 @@ VARIABLE(graphics_CURSOR) //28 void * .extent (EXT_C(menu_border)) //29 border 数组 VARIABLE(gzip_filemax) //30 long long .extent 0 - .extent ABS(EXT_C(WENV_ENVI)) //31 char * + .extent ABS(EXT_C(WENV_ENVI)) //31 char * (实际是char **)!!! //reserved for wee VARIABLE(bat_md_start) //32 grub_size_t .extent 0 VARIABLE(bat_md_count) //33 unsigned int .extent 0 - .extent 0 //34 reserved - .extent 0 //35 reserved - .extent 0 //36 reserved - .extent 0 //37 reserved +VARIABLE(ext_data_0) //34 unsigned long long + .extent 0 +VARIABLE(ext_data_1) //35 unsigned long long + .extent 0 +VARIABLE(map_start_sector) //36 unsigned long long* + .extent 0 +VARIABLE(map_num_sectors) //37 unsigned long long* + .extent 0 .extent 0 //38 reserved .extent 0 //39 reserved .extent 0 //40 reserved diff --git a/stage2/boot.c b/stage2/boot.c index b1b253c..7de3eba 100644 --- a/stage2/boot.c +++ b/stage2/boot.c @@ -1185,6 +1185,7 @@ load_initrd (char *initrd) void bsd_boot (kernel_t type, int bootdev, char *arg) { +#if 0 char *str; int clval = 0, i; @@ -1321,4 +1322,5 @@ bsd_boot (kernel_t type, int bootdev, char *arg) //(*entry_addr) (clval, bootdev, 0, end_mark, extended_memory, (*(unsigned short *)0x413)/*saved_mem_lower*/); //multi_boot ((int) entry_addr, clval, bootdev, 0, end_mark, extended_memory, (*(unsigned short *)0x413)/*saved_mem_lower*/); } +#endif } diff --git a/stage2/builtins.c b/stage2/builtins.c index afdb82f..91a3eff 100644 --- a/stage2/builtins.c +++ b/stage2/builtins.c @@ -243,10 +243,10 @@ disk_read_print_func (unsigned long long sector, unsigned int offset, unsigned l } extern int rawread_ignore_memmove_overflow; /* defined in disk_io.c */ -int query_block_entries; +int query_block_entries; //小于0,填充map_start_sector/map_num_sectors,不打印信息。大于等于0,只打印信息。 //static unsigned long long map_start_sector[DRIVE_MAP_FRAGMENT]; //static unsigned long long map_num_sectors[DRIVE_MAP_FRAGMENT]; -unsigned long long* map_start_sector=0; +unsigned long long* map_start_sector; unsigned long long* map_num_sectors; static unsigned long long blklst_start_sector; @@ -336,25 +336,12 @@ blocklist_func (char *arg, int flags) blklst_num_sectors = 0; blklst_num_entries = 0; blklst_last_length = 0; - if (!map_start_sector) - { - map_start_sector = grub_zalloc(DRIVE_MAP_FRAGMENT); - map_num_sectors = grub_zalloc(DRIVE_MAP_FRAGMENT); - } - else - { - grub_memset (map_start_sector, 0, DRIVE_MAP_FRAGMENT); - grub_memset (map_num_sectors, 0, DRIVE_MAP_FRAGMENT); - - } -#if 0 - int i; - for (i = 0; i < DRIVE_MAP_FRAGMENT; i++) - { - map_start_sector[i] =0; - map_num_sectors[i] =0; - } -#endif + grub_memset (map_start_sector, 0, DRIVE_MAP_FRAGMENT); + grub_memset (map_num_sectors, 0, DRIVE_MAP_FRAGMENT); + + if (flags==255) + query_block_entries = -1; + /* Open the file. */ if (! grub_open (arg)) goto fail_open; @@ -619,7 +606,7 @@ cat_func (char *arg, int flags) no_decompression = no_decompression_bak; } grub_close(); - printf_debug0 ("Filesize is 0x%lX\n", (unsigned long long)filesize); + printf_debug ("Filesize is 0x%lX\n", (unsigned long long)filesize); return (filesize>>32)?(unsigned long long)-1:filesize; } @@ -939,6 +926,7 @@ get_efi_device_boot_path (int drive, int flags) //获得硬盘/光盘启动分 } if (flags) { + if (!map_pd) if (!grub_open (chainloader_file_orig)) goto fail_free_cache; } @@ -1229,7 +1217,10 @@ boot_func (char *arg, int flags) grub_efi_boot_services_t *b; grub_efi_status_t status; b = grub_efi_system_table->boot_services; //引导服务 - + char tmp[6]; + sprintf(tmp,"%d",graphics_mode); //sunsea报告:在图形模式下,进入没有安装好显卡驱动的PE或者新windows桌面后,会强制锁定在当前分辨率,无法修改。2024-12-04 + graphicsmode_func ("3", flags); //采用文本模式显示 + if (kernel_type == KERNEL_TYPE_LINUX) { if (kernel_load_type == KERTNEL_LOAD_HANDOVER) @@ -1274,6 +1265,7 @@ boot_func (char *arg, int flags) return 0; printf_debug ("StartImage: %x\n", image_handle); //开始映射 status = efi_call_3 (b->start_image, image_handle, 0, NULL); //启动映像 + graphicsmode_func (tmp, flags); //启动失败后,显示采用以前的图形模式 printf_debug ("StartImage returned 0x%lx\n", (grub_size_t) status); //开始映射返回 status = efi_call_1 (b->unload_image, image_handle); //卸载映射 return 1; @@ -1498,7 +1490,7 @@ chainloader_func (char *arg, int flags) if (current_partition == 0xFFFFFF) { d = get_device_by_drive (current_drive,0); - if (!d) + if (!d || !d->device_handle) return (!(errnum = ERR_NO_DISK)); dp = grub_efi_get_device_path (d->device_handle); temp = d->device_handle; @@ -1506,7 +1498,7 @@ chainloader_func (char *arg, int flags) else { part_data = get_partition_info (current_drive, current_partition); - if (!part_data) + if (!part_data || !part_data->part_handle) return (!(errnum = ERR_NO_DISK)); dp = grub_efi_get_device_path (part_data->part_handle); temp = part_data->part_handle; @@ -7454,7 +7446,6 @@ unsigned int ext_start_lba; unsigned int ext_total_sectors; /* map */ /* Map FROM_DRIVE to TO_DRIVE. 映射 FROM 驱动器到 TO 驱动器*/ -int map_func (char *arg, int flags); int map_func (char *arg, int flags) //对设备进行映射 返回: 0/1=失败/成功 { @@ -7472,6 +7463,7 @@ map_func (char *arg, int flags) //对设备进行映射 返回: 0/1=失败/成 int no_hook = 0; int vhd_disk = 0; int alloc_only = 0; + int no_alloc = 0; vhd_start_sector = 0; //struct master_and_dos_boot_sector *BS = (struct master_and_dos_boot_sector *) RAW_ADDR (0x8000); @@ -7521,15 +7513,15 @@ map_func (char *arg, int flags) //对设备进行映射 返回: 0/1=失败/成 { if (disk_drive_map[i].from_drive != (unsigned char)mem) //如果from驱动器号不等于输入参数,继续 continue; -// *(unsigned int *)ADDR_RET_STR = (unsigned int)disk_drive_map[i].start_sector; - sprintf(ADDR_RET_STR,"0x%lx",(unsigned int)disk_drive_map[i].start_sector); + *(unsigned int *)ADDR_RET_STR = (unsigned int)disk_drive_map[i].start_sector; return disk_drive_map[i].sector_count; //返回起始扇区(32位) } #else df = get_device_by_drive ((unsigned int)mem,1); if (df) { - sprintf(ADDR_RET_STR,"0x%lx",df->start_sector); +// sprintf(ADDR_RET_STR,"0x%lx",df->start_sector); + *(unsigned int *)ADDR_RET_STR = df->start_sector; //2024-12-12 return df->sector_count; //返回起始扇区(32位) } #endif @@ -7869,6 +7861,10 @@ struct drive_map_slot { alloc_only = 1; } + else if (grub_memcmp (arg, "--no-alloc", 10) == 0) //0/1/2=正常分配内存/使用rd,md的值/使用efi_pxe_buf 2024-11-21 + { + no_alloc = 1; + } else break; arg = skip_to (0, arg); //跳到空格后 @@ -7907,6 +7903,10 @@ struct drive_map_slot to = current_drive; //to=当前驱动器 primeval_to = to; //保存原始to /* if mem device is used, assume the --mem option 如果使用mem驱动器,假设--mem已选择*/ +//printf ("from-0,%x,%x,%x,%x\n",from,to,current_drive,saved_drive); +//a0,21,21,21; 60,ffff,ffff,21; map (http)/imgs/ifu352.iso (cd) +//a0,21,21,21; 60,ffff,ffff,21; map --mem (http)/imgs/ifu352.iso (cd) +//81,ffff,ffff.21; 82,7f,7f,81; ntboot (http)/imgs/boot.wim if (to == 0xffff || to == ram_drive || from == ram_drive || to == 0x21) //如果to=md,或to=rd,或from=rd,或网络驱动器 { if (mem == -1ULL) //如果mem=-1ULL=0xffffffffffffffff 不加载到内存 @@ -7974,6 +7974,20 @@ struct drive_map_slot grub_memmove (vhd_file_path, chainloader_file, grub_strlen (chainloader_file) + 1); } +//printf ("from-1,%x,%x,%x,%x\n",from,to,current_drive,saved_drive); +//a0,21,21,21; 60,ffff,ffff,21; +//a0,21,21,21; 60,ffff,ffff,21; +//81,ffff,ffff.21; 82,7f,7f,81; + if (to == 0x21) + { + if (! grub_open (to_drive)) //打开to驱动器 + goto fail_free; + rd_base = (unsigned long long)(grub_size_t)efi_pxe_buf; + rd_size = (unsigned long long)filemax; + to_drive = "(rd)+1"; + map_pd = 1; + efi_pxe_buf = 0; + } // if (mem == -1ULL) //如果不加载到内存 { @@ -7981,12 +7995,15 @@ struct drive_map_slot query_block_entries = -1; /* query block list only 仅请求块列表*/ k = no_decompression; no_decompression = 1; + //第一次读to驱动器,建立扇区序列 blocklist_func (to_drive, flags); //请求块列表 执行成功后,将设置query_block_entries=1,设置errnum=0 no_decompression = k; if (errnum) return 0; vhd_start_sector = map_start_sector[0]; + if (map_pd) + vhd_start_sector += rd_base; if ((compressed_file && decomp_type != DECOMP_TYPE_VHD) || query_block_entries > DRIVE_MAP_FRAGMENT) //如果是压缩文件且不是VHD, 或者碎片太多 { printf_warning ("Too many fragments or compressed file needs to be loaded into memory."); @@ -8017,10 +8034,13 @@ struct drive_map_slot #endif { //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - { +//printf ("from-2,%x,%x,%x,%x\n",from,to,current_drive,saved_drive); +//a0,21,7f,21; 60,ffff,ffff,21; +//a0,21,7f,21; 60,ffff,ffff,21; +//81,ffff,ffff.21; 82,7f,7f,81; + //第二次读to驱动器,建立form驱动器映射 if (! grub_open (to_drive)) //打开to驱动器 goto fail_free; - } // if ((skip_sectors << SECTOR_BITS) > filemax) if (skip_sectors > (filemax >> 9)) //如果跳过扇区>文件最大扇区 { @@ -8367,7 +8387,11 @@ struct drive_map_slot //j=from驱动器的父插槽号 也就是说,to不是原生磁盘,是映射盘 dt是from的父驱动器设备 //i=from驱动器的插槽号 df是from驱动器的设备 //==================================================================================================================== - if (from != ram_drive && from != 0xffff) +//printf ("from-3,%x,%x,%x,%x\n",from,to,current_drive,saved_drive); +//a0,21,7f,21; 60,ffff,ffff,21; +//a0,21,7f,21; 60,ffff,ffff,21; +//81,ffff,ffff.21; 82,7f,7f,81; + if (from != ram_drive && from != 0xffff && !alloc_only) { //获取to驱动器,虚拟分区信息 // disk_drive_map[i].start_sector = start_sector; @@ -8470,8 +8494,12 @@ struct drive_map_slot if (mem == -1ULL) //如果不加载到内存 grub_close (); //关闭to驱动器 //==================================================================================================================== +//printf ("from-4,%x,%x,%x,%x\n",from,to,current_drive,saved_drive); +//a0,21,7f,21; 60,ffff,ffff,21; +//a0,21,7f,21; 60,ffff,ffff,21; +//81,ffff,ffff.21; 82,7f,7f,81; /* how much memory should we use for the drive emulation? */ - if (mem != -1ULL) //如果加载到内存 + if (mem != -1ULL && !no_alloc) //如果加载到内存 { unsigned long long start_byte; //起始字节 unsigned long long bytes_needed; //需要字节 @@ -8557,7 +8585,6 @@ struct drive_map_slot // GRUB_EFI_RUNTIME_SERVICES_DATA, GRUB_EFI_RESERVED_MEMORY_TYPE, //保留内存类型 0 (grub_efi_uintn_t)bytes_needed >> 12, &alloc); //调用(分配页面,分配类型->任意页面,存储类型->运行时服务数据(6),分配页,地址) - if (status != GRUB_EFI_SUCCESS) //如果失败 { printf_errinfo ("out of map memory: %d\n",(int)status); @@ -8606,15 +8633,30 @@ VirtualBox qbus_gd.vhd map --mem read_blocks U盘 150 */ mem_ok: sector_count = bytes_needed >> 9; //扇区计数=加载到内存的扇区数,每扇区0x200字节 + start_sector = alloc >> 9; + + if (alloc_only) + { + from_log2_sector = 9; + grub_close (); //关闭to驱动器 + to = 0xFFFF; + goto no_fragment; + } // sector_count = bytes_needed >> buf_geom.log2_sector_size; //扇区计数=需要扇区 //向内存移动映像 第一扇区已经读到了BS /* if image is in memory and not compressed, we can simply move it. */ - if ((to == 0xffff || to == ram_drive) && !compressed_file) //如果映像在内存中,并且没有压缩,我们可以简单地移动它。 +//printf ("from-5,%x,%x,%x,%x\n",from,to,current_drive,saved_drive); +//a0,21,7f,21; 60,ffff,ffff,21; +//a0,21,7f,21; 60,ffff,ffff,21; +//81,ffff,ffff.21; + if ((to == 0xffff || to == ram_drive || to == 0x21) && !compressed_file) //如果映像在内存中,并且没有压缩,我们可以简单地移动它。 { // if (bytes_needed != start_byte) //如果需要字节!=起始字节 - if (!alloc_only) //不是仅分配 2024-09-01 - { +// if (!alloc_only) //不是仅分配 2024-09-01 + { printf ("Copying data, please wait......\n"); + if (to == 0x21) //2024-12-12 + start_byte = rd_base; grub_memmove64 (alloc, start_byte, filemax); } } @@ -8676,8 +8718,12 @@ VirtualBox qbus_gd.vhd map --mem read_blocks U盘 150 blklst_num_entries = 1; //如果文件有碎片,加载到内存后就连续了。避免后续设置碎片。 } grub_close (); //关闭to驱动器 - start_sector = alloc >> 9; +// start_sector = alloc >> 9; to = 0xFFFF/*GRUB_INVALID_DRIVE*/; +//printf ("from-6,%x,%x,%x,%x\n",from,to,current_drive,saved_drive); +//a0,ffff,7f,21; 60,ffff,ffff,21; +//a0,ffff,7f,21; 60,ffff,ffff,21; +//81,ffff,ffff.21; /* if FROM is (rd), no mapping is established. but the image will be //如果FROM是rd,没有建立映射 * loaded into memory, and (rd) will point to it. Note that Master //但是映像将装载到内存,并且rd指向它. * Boot Track and MBR code have been built as above when needed //注意主引导磁道和MBR代码已经建立,需要ram_drive是硬盘. @@ -8693,6 +8739,24 @@ VirtualBox qbus_gd.vhd map --mem read_blocks U盘 150 return 1; } } //if (mem != -1ULL)结束 //如果加载到内存结束 +//printf ("from-7,%x,%x,%x,%x\n",from,to,current_drive,saved_drive); +//a0,ffff,7f,21; 60,ffff,ffff,21; +//a0,ffff,7f,21; 60,ffff,ffff,21; +//81,ffff,ffff.21; 82,7f,7f,81; + if (no_alloc) + { + if (current_drive == 0x21) + { + start_sector = (grub_size_t)efi_pxe_buf >> 9; + efi_pxe_buf = 0; + } + else if (current_drive == ram_drive) + { + start_sector = rd_base >> 9; + } + grub_close (); //关闭to驱动器 + to = 0xFFFF; + } //加载到内存结束 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if 0 @@ -8915,6 +8979,7 @@ VirtualBox qbus_gd.vhd map --mem read_blocks U盘 150 d->from_log2_sector = from_log2_sector; d->to_log2_sector = buf_geom.log2_sector_size; d->start_sector = start_sector; + ext_data_0 = start_sector; d->sector_count = sector_count; d->total_sectors = (filemax + (1 << from_log2_sector) - 1) >> from_log2_sector; d->to_block_size = buf_geom.sector_size; @@ -8922,7 +8987,10 @@ VirtualBox qbus_gd.vhd map --mem read_blocks U盘 150 d->fragment = (blklst_num_entries > 1); d->read_only = read_only; d->vhd_disk = vhd_disk; - +//printf ("from-8,%x,%x,%x,%x\n",from,to,current_drive,saved_drive); +//a0,ffff,7f,21; 60,ffff,ffff,21; +//a0,ffff,7f,21; 60,ffff,ffff,21; +//81,ffff,ffff.21; 82,ffff,7f,81; if (vhd_file_name) { grub_free (vhd_file_name); @@ -8957,6 +9025,7 @@ VirtualBox qbus_gd.vhd map --mem read_blocks U盘 150 } if (d->drive >= 0x80) { + //第三次读to驱动器,探测引导扇区 add_part_data (d->drive); if (!no_hook) { @@ -8973,7 +9042,11 @@ VirtualBox qbus_gd.vhd map --mem read_blocks U盘 150 } } } - +//printf ("from-9,%x,%x,%x,%x\n",from,to,current_drive,saved_drive); +//; 60,ffff,ffff,21; a0,ffff,a0,21; +//; 60,ffff,ffff,21; a0,ffff,a0,21; +//81,ffff,ffff.21; 82,ffff,82,81; + map_pd = 0; return 1; fail_close_free: @@ -9984,7 +10057,7 @@ static struct builtin builtin_pause = "--test-key display keyboard code." }; - +#if 0 #ifdef FSYS_PXE /* pxe */ static struct builtin builtin_pxe = @@ -9996,6 +10069,7 @@ static struct builtin builtin_pxe = "Call PXE command." }; #endif +#endif #if 0 #ifdef FSYS_IPXE /* pxe */ @@ -13123,6 +13197,16 @@ static int set_func(char *arg, int flags) errnum = 0; if( *arg == '*' ) return reset_env_all(); //envi_cmd(NULL, NULL, 3) + else if (grub_memcmp (arg, "tftp", 4) == 0) + { + cur_pxe_type = 0; + return 1; + } + else if (grub_memcmp (arg, "http", 4) == 0) + { + cur_pxe_type = 1; + return 1; + } else if (strcmp(VAR[_WENV_], "?_WENV") != 0) reset_env_all(); //envi_cmd(NULL, NULL, 3) if (*arg == '@') @@ -15069,7 +15153,7 @@ struct builtin *builtin_table[] = &builtin_password, &builtin_pause, #ifdef FSYS_PXE - &builtin_pxe, +// &builtin_pxe, #endif #ifndef NO_DECOMPRESSION &builtin_raw, diff --git a/stage2/char_io.c b/stage2/char_io.c index 820ed8f..a632b02 100644 --- a/stage2/char_io.c +++ b/stage2/char_io.c @@ -1506,13 +1506,15 @@ get_cmdline (void) return ret; } -// Parse decimal or hexadecimal ASCII input string to 64-bit integer -// input number may have K,M,G,T or k,m,g,t suffix -// if unitshift is 0, the number is plain number. +// Parse decimal or hexadecimal ASCII input string to 64-bit integer 将十进制或十六进制ASCII输入字符串解析为64位整数 +// input number may have K,M,G,T or k,m,g,t suffix 输入数字可以有K、M、G、T或k、m、g、t后缀 +// if unitshift is 0, the number is plain number. 如果unitshift为0,则该数字为纯数字。 // 1K=1024, 1M=1048576, 1G=1<<30, 1T=1<<40 -// if unitshift is 9, the input number is number of 512-bytes sectors and suffixes means KBytes, MBytes,... +// if unitshift is 9, the input number is number of 512-bytes sectors and suffixes means KBytes, MBytes,... 如果unitshift为9,则输入数字是512字节扇区的数量,后缀表示KB,MB // 1K=2 sectors, 1M=2048 sectors, ... -// unitshift must be in the range 0-63 +// unitshift must be in the range 0-63 unitshift必须在0-63的范围内 +//*str_ptr返回源结束地址 +//会改变*str_ptr值,增大8字节!!! int safe_parse_maxint_with_suffix (char **str_ptr, unsigned long long *myint_ptr, int unitshift) { diff --git a/stage2/common.c b/stage2/common.c index 6412343..a2a787a 100644 --- a/stage2/common.c +++ b/stage2/common.c @@ -376,6 +376,7 @@ void grub_halt (void); void grub_halt (void) //关机 { + grub_machine_fini (); efi_call_4 (grub_efi_system_table->runtime_services->reset_system, //系统表->运行时服务->重置系统 GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL); //关机,成功 ,0,NULL for (;;) ; @@ -1400,6 +1401,143 @@ grub_realloc (void *ptr, grub_size_t size) } #endif +///////////////////////////////////////////////////////////////////////////////////////// +#define GRUB_UCS2_LIMIT 0x10000 +#define GRUB_UTF16_UPPER_SURROGATE(code) \ + (0xD800 | ((((code) - GRUB_UCS2_LIMIT) >> 10) & 0x3ff)) +#define GRUB_UTF16_LOWER_SURROGATE(code) \ + (0xDC00 | (((code) - GRUB_UCS2_LIMIT) & 0x3ff)) + +/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE + bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string. + Return the number of characters converted. DEST must be able to hold + at least DESTSIZE characters. If an invalid sequence is found, return -1. + If SRCEND is not NULL, then *SRCEND is set to the next byte after the + last byte used in SRC. */ +grub_size_t grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, + const grub_uint8_t *src, grub_size_t srcsize, + const grub_uint8_t **srcend); +grub_size_t +grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, + const grub_uint8_t *src, grub_size_t srcsize, + const grub_uint8_t **srcend) +{ + grub_uint16_t *p = dest; + int count = 0; + grub_uint32_t code = 0; + + if (srcend) + *srcend = src; + + while (srcsize && destsize) + { + int was_count = count; + if (srcsize != (grub_size_t)-1) + srcsize--; + if (!grub_utf8_process (*src++, &code, &count)) + { + code = '?'; + count = 0; + /* Character c may be valid, don't eat it. */ + if (was_count) + src--; + } + if (count != 0) + continue; + if (code == 0) + break; + if (destsize < 2 && code >= GRUB_UCS2_LIMIT) + break; + if (code >= GRUB_UCS2_LIMIT) + { + *p++ = GRUB_UTF16_UPPER_SURROGATE (code); + *p++ = GRUB_UTF16_LOWER_SURROGATE (code); + destsize -= 2; + } + else + { + *p++ = code; + destsize--; + } + } + + if (srcend) + *srcend = src; + return p - dest; +} + +/* Convert UTF-16 to UTF-8. */ +grub_uint8_t *grub_utf16_to_utf8 (grub_uint8_t *dest, const grub_uint16_t *src, grub_size_t size); +grub_uint8_t * +grub_utf16_to_utf8 (grub_uint8_t *dest, const grub_uint16_t *src, + grub_size_t size) +{ + grub_uint32_t code_high = 0; + + while (size--) + { + grub_uint32_t code = *src++; + + if (code_high) + { + if (code >= 0xDC00 && code <= 0xDFFF) + { + /* Surrogate pair. */ + code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000; + + *dest++ = (code >> 18) | 0xF0; + *dest++ = ((code >> 12) & 0x3F) | 0x80; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + } + else + { + /* Error... */ + *dest++ = '?'; + /* *src may be valid. Don't eat it. */ + src--; + } + + code_high = 0; + } + else + { + if (code <= 0x007F) + *dest++ = code; + else if (code <= 0x07FF) + { + *dest++ = (code >> 6) | 0xC0; + *dest++ = (code & 0x3F) | 0x80; + } + else if (code >= 0xD800 && code <= 0xDBFF) + { + code_high = code; + continue; + } + else if (code >= 0xDC00 && code <= 0xDFFF) + { + /* Error... */ + *dest++ = '?'; + } + else if (code < 0x10000) + { + *dest++ = (code >> 12) | 0xE0; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + } + else + { + *dest++ = (code >> 18) | 0xF0; + *dest++ = ((code >> 12) & 0x3F) | 0x80; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + } + } + } + + return dest; +} + //------------------------------------------------------------------------------------- //kern/efi/mm.c @@ -1448,8 +1586,9 @@ struct efi_allocation { grub_efi_uint64_t pages; //页 8位 struct efi_allocation *next; //下一个 4位 0=结束符 }; -static struct efi_allocation *efi_allocated_memory; //0x14位 静态,地址不变 + #if 0 +static struct efi_allocation *efi_allocated_memory; //0x14位 静态,地址不变 static void grub_efi_store_alloc (grub_efi_physical_address_t address, grub_efi_uintn_t pages); static void grub_efi_store_alloc (grub_efi_physical_address_t address, @@ -1813,7 +1952,6 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, //映射起始 return filtered_desc; } -void grub_mm_init_region (void *addr, grub_size_t size); //在使用内存堆头部,建立内存头,用于记录将来在堆内分配和释放内存. /* Initialize a region starting from ADDR and whose size is SIZE, to use it as free space. 从addr开始初始化一个大小为size的区域,将其用作可用空间。*/ @@ -1880,6 +2018,8 @@ grub_mm_init_region (void *addr, grub_size_t size) // } +grub_efi_uint64_t memory_pages; +grub_efi_physical_address_t memory_address; //分配一块将来由自己直接分配和释放的内存区域. /* Add memory regions. 添加内存区域 */ static void add_memory_regions (grub_efi_memory_descriptor_t *memory_map, grub_efi_uintn_t desc_size, @@ -1917,6 +2057,8 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, //排序后的内 (unsigned) pages); break; } + memory_address = (grub_efi_physical_address_t)(grub_size_t)addr; + memory_pages = pages; grub_mm_init_region (addr, PAGES_TO_BYTES (pages)); //初始化内存区域 break; } @@ -1932,9 +2074,24 @@ grub_efi_memory_fini (void) //内存结束 * list entry (efi_allocated_memory is the list start). Hence we (efi_allocated_memory是列表开始) * remove all entries from the list until none is left altogether. 因此,我们从列表中删除所有条目,直到没有剩下。 */ - while (efi_allocated_memory) - grub_efi_free_pages (efi_allocated_memory->address, - efi_allocated_memory->pages); //释放页 +// while (efi_allocated_memory) +// grub_efi_free_pages (efi_allocated_memory->address, +// efi_allocated_memory->pages); //释放页 + grub_efi_free_pages (memory_address, memory_pages); //释放页 + + int drive; + struct grub_disk_data *d; + grub_efi_boot_services_t *b; + for (drive = 0xFF; drive >= 0; drive--) //从0xff到0 + { + d = get_device_by_drive (drive,0); + if (!d) //避免驱动器不存在时死机 + continue; + + //卸载映射内存 + if (d->to_drive == 0xff && d->to_log2_sector != 0xb) //内存映射 + efi_call_2 (b->free_pages, d->start_sector << 9, d->sector_count >> 3); //释放页 2024-09-01 + } } #if 0 //打印内存分布 @@ -2301,6 +2458,8 @@ grub_init (void) mbr = grub_malloc (0x1000); //mbr disk_buffer = grub_malloc (0x1000); //磁盘缓存 disk_fragment_map = grub_zalloc (FRAGMENT_MAP_SLOT_SIZE); //碎片插槽 + map_start_sector = grub_zalloc(DRIVE_MAP_FRAGMENT); //(*(grub_size_t **)IMG(0x8308))[36] + map_num_sectors = grub_zalloc(DRIVE_MAP_FRAGMENT); //buffer=grub_malloc (byte) 分配内存 //buffer=grub_zalloc (byte) 分配内存, 并清零 //buffer=grub_memalign (align,byte) 对齐分配内存 diff --git a/stage2/dec_vhd.c b/stage2/dec_vhd.c index e73d3ef..6e53c2e 100644 --- a/stage2/dec_vhd.c +++ b/stage2/dec_vhd.c @@ -346,13 +346,20 @@ dec_vhd_open(void) goto quit; dec_vhd_close(); + if (current_drive == 0x21 || current_drive == 0x7f) //为了网起 2024-12-12 + { + from_log2_sector = 9; //未考虑4k磁盘 + to_log2_sector = 9; + to_block_size = 512; + goto bbb; + } d = get_device_by_drive (current_drive,0); if (!d) return 0; from_log2_sector = 9; //未考虑4k磁盘 to_log2_sector = d->from_log2_sector; to_block_size = 1 << to_log2_sector; - +bbb: vhd_vhdfc_index++; GetSectorSequence (vhd_file_name, &SectorSequence, 1); if (!SectorSequence) diff --git a/stage2/disk_io.c b/stage2/disk_io.c index 2a66ed9..9a232e2 100644 --- a/stage2/disk_io.c +++ b/stage2/disk_io.c @@ -1241,6 +1241,32 @@ set_device (char *device) else if (*(device + 1) == 'd' && !*(device + 2)) return device + 2; } + + if (pxe_entry && *(device+3) == 'p') + { + if (grub_memcmp(device,"tftp",4) == 0) + { + cur_pxe_type = PXE_FILE_TYPE_TFTP; + current_drive = PXE_DRIVE; //0x21 + device += 4; + } + else if (grub_memcmp(device,"http",4) == 0) + { + cur_pxe_type = PXE_FILE_TYPE_HTTP; + current_drive = PXE_DRIVE; //0x21 + device += 4; + if (*(device + 4) == 's') + { + device++; + pxe_http_type = 1; //https + } + else + pxe_http_type = 0; //http + } + + goto aaa; + } + if ((*device == 'f' || *device == 'h' || *device == 'm' @@ -1363,6 +1389,7 @@ set_device (char *device) } } } +aaa: if (errnum) return 0; @@ -1885,6 +1912,8 @@ grub_open (char *filename) } #endif #endif + if (current_drive == 0x21) //2024-12-12 + goto not_block_file; #ifdef NO_BLOCK_FILES return !(errnum = ERR_BAD_FILENAME); #else @@ -1979,11 +2008,11 @@ grub_open (char *filename) #endif /* block files */ } /* if (*filename != '/') */ -#if 0 -#ifdef FSYS_IPXE +//#if 0 2024-12-12 +//#ifdef FSYS_IPXE not_block_file: -#endif -#endif +//#endif +//#endif if (!errnum && fsys_type == NUM_FSYS) errnum = ERR_FSYS_MOUNT; /* set "dir" function to open a file */ @@ -2204,7 +2233,10 @@ get_diskinfo (unsigned int drive, struct geometry *geometry, unsigned int partit if (drive == 0xffff || drive == ram_drive) { geometry->sector_size = 512; - geometry->total_sectors = -1; + if (drive == ram_drive) //2024-12-12 + geometry->total_sectors = rd_size >> 9; + else + geometry->total_sectors = -1; geometry->log2_sector_size = 9; return 0; } @@ -2940,7 +2972,7 @@ grub_SectorSequence_readwrite (int drive, struct fragment *data, unsigned char f if (!size) return status; //确定本碎片还可以访问扇区数 - if (df->fragment && !fragment_len) //肯定有碎片, 否则fragment_len=size, 既然len不为零, 则fragment_len也不会为零. + if (/*df->fragment && */!fragment_len) //肯定有碎片, 否则fragment_len=size, 既然len不为零, 则fragment_len也不会为零. 2024-12-12 { sector = data[j].start_sector; fragment_len = data[j].sector_count << to_log2; @@ -3319,7 +3351,6 @@ grub_efidisk_fini (void) //efidisk结束 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //kern.misc.c -#if defined(__i386__) /* 计算原理: 1. 二进制数字和 @@ -3402,7 +3433,7 @@ grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r) //64位除法 return q; } -#endif + #if 0 grub_uint64_t __umoddi3 (grub_uint64_t a, grub_uint64_t b); grub_uint64_t @@ -3935,7 +3966,7 @@ vpart_install (int drive, struct grub_part_data *part) //安装虚拟分区 status = efi_call_4 (b->connect_controller, vpart->from_handle, NULL, NULL, TRUE); //引导服务->连接控制器,要连接驱动程序的控制器的句柄,驱动程序绑定协议的有序列表句柄的指针,指向设备路径的指针,如果为true则递归调用ConnectController(), if(status != GRUB_EFI_SUCCESS) { - printf_errinfo ("failed to install virtual partition: connect_controller.(%x)\n",status); //无法安装虚拟分区 + printf_errinfo ("failed to install virtual partition: connect_controller.(%d)\n",(int)status); //无法安装虚拟分区 // return GRUB_EFI_NOT_FOUND; } @@ -4048,7 +4079,7 @@ vdisk_install (int drive, int partition) //安装虚拟磁盘(驱动器号) d->device_handle = vdisk->from_handle; if (status != GRUB_EFI_SUCCESS) //安装失败 { - printf_errinfo ("failed to install virtual disk: install_multiple_protocol_interfaces.(%x)\n",status); //无法安装虚拟磁盘 + printf_errinfo ("failed to install virtual disk: install_multiple_protocol_interfaces.(%d)\n",(int)status); //无法安装虚拟磁盘 return status; } @@ -4060,7 +4091,7 @@ vdisk_install (int drive, int partition) //安装虚拟磁盘(驱动器号) status = efi_call_4 (b->connect_controller, vdisk->from_handle, NULL, NULL, TRUE); //引导服务->连接控制器,要连接驱动程序的控制器的句柄,驱动程序绑定协议的有序列表句柄的指针,指向设备路径的指针,如果为true则递归调用ConnectController(), if (status != GRUB_EFI_SUCCESS) //安装失败 { - printf_errinfo ("failed to install virtual disk: connect_controller.(%x)\n",status); //无法安装虚拟磁盘 + printf_errinfo ("failed to install virtual disk: connect_controller.(%d)\n",(int)status); //无法安装虚拟磁盘 return status; } @@ -4859,7 +4890,7 @@ grub_load_image (grub_efi_device_path_t *path, const char *filename, void *boot_ if (status != GRUB_EFI_SUCCESS) //失败 { - printf_errinfo ("Failed to load virtual disk image.(%x)\n",status); + printf_errinfo ("Failed to load virtual disk image.(%d)\n",(int)status); boot_image_handle = NULL; } diff --git a/stage2/fsys_pxe.c b/stage2/fsys_pxe.c index 3d90d87..01706c0 100644 --- a/stage2/fsys_pxe.c +++ b/stage2/fsys_pxe.c @@ -22,117 +22,87 @@ #include "shared.h" #include "filesys.h" #include "pxe.h" -#include "ipxe.h" - -#if !defined(__constant_htonl) -#define __constant_htonl(x) \ - ((unsigned long long)((((unsigned long long)(x) & 0x000000ffU) << 24) | \ - (((unsigned long long)(x) & 0x0000ff00U) << 8) | \ - (((unsigned long long)(x) & 0x00ff0000U) >> 8) | \ - (((unsigned long long)(x) & 0xff000000U) >> 24))) -#endif -#if !defined(__constant_htons) -#define __constant_htons(x) \ - ((unsigned int)((((unsigned int)(x) & 0x00ff) << 8) | \ - (((unsigned int)(x) & 0xff00) >> 8))) -#endif - -#define ntohl(x) \ -(__builtin_constant_p(x) ? \ - __constant_htonl((x)) : \ - __swap32(x)) -#define htonl(x) \ -(__builtin_constant_p(x) ? \ - __constant_htonl((x)) : \ - __swap32(x)) -#define ntohs(x) \ -(__builtin_constant_p(x) ? \ - __constant_htons((x)) : \ - __swap16(x)) -#define htons(x) \ -(__builtin_constant_p(x) ? \ - __constant_htons((x)) : \ - __swap16(x)) - -static inline unsigned long long __swap32(unsigned long long x) -{ - __asm__("xchgb %b0,%h0\n\t" - "rorl $16,%0\n\t" - "xchgb %b0,%h0" - : "=q" (x) - : "0" (x)); - return x; -} - -static inline unsigned int __swap16(unsigned int x) -{ - __asm__("xchgb %b0,%h0" - : "=q" (x) - : "0" (x)); - return x; -} - - -#ifndef TFTP_PORT -#define TFTP_PORT 69 -#endif - -#define PXE_MIN_BLKSIZE 128 -#define PXE_MAX_BLKSIZE 16384 - -#define DOT_SIZE 1048576 - - -/* use disk buffer for PXE_BUF */ -#define PXE_BUF BUFFERADDR -#define PXE_BUFLEN BUFFERLEN -unsigned int pxe_blksize = 512; /*PXE_MAX_BLKSIZE*/ -struct grub_efi_pxe *pxe_entry = 0; -unsigned short pxe_basemem, pxe_freemem; -unsigned int pxe_keep; - -IP4 pxe_yip, pxe_sip, pxe_gip; -grub_u8_t pxe_mac_len, pxe_mac_type; -MAC_ADDR pxe_mac; -static grub_u8_t pxe_tftp_opened; -static unsigned int pxe_saved_pos, pxe_cur_ofs, pxe_read_ofs; //保存的指针,当前偏移,读偏移 - -extern PXENV_TFTP_OPEN_t pxe_tftp_open; /* now it is defined in asm.S 现在它在asm.S中定义*/ //TFTP打开 +int map_pd = 0; +struct grub_efi_pxe *pxe_entry; +IP4 pxe_sip; +static grub_u8_t pxe_opened = 0; +static grub_u8_t pxe_already_read = 0; static char filename[128]; -static char *pxe_tftp_name = filename; - -//extern unsigned int ROM_int15; -//extern unsigned int ROM_int13; -//extern unsigned int ROM_int13_dup; -extern struct drive_map_slot bios_drive_map[DRIVE_MAP_SIZE + 1]; +static char *pxe_name = filename; +grub_u32_t pxe_http_type = 0; //0/1=http/https +static int pxe_need_read = 0; //0/1=不用读/需要读 static int pxe_open (char* name); +int pxe_mount (void); int pxe_dir (char *dirname); -grub_u32_t pxe_read_blk (grub_u32_t buf, grub_u32_t num); +unsigned long long pxe_read (unsigned long long buf, unsigned long long len, unsigned int write); +void pxe_close (void); +void pxe_unload (void); +int pxe_allocate(void); -static int tftp_open(const char *dirname); -static grub_u32_t tftp_get_size(void); -static grub_u32_t tftp_read_blk (grub_u32_t buf, grub_u32_t num); +static int tftp_open(void); +//static grub_u32_t tftp_get_size(void); +static grub_size_t tftp_read (char *buf, grub_u64_t len); int tftp_write (const char *name); -static void tftp_close (void); -static void tftp_unload(void); -s_PXE_FILE_FUNC tftp_file_func = {tftp_open,tftp_get_size,tftp_read_blk,tftp_close,tftp_unload}; +static int http_open(void); +static grub_size_t http_read (char *buf, grub_u64_t len); -grub_u32_t cur_pxe_type = 0; -grub_u32_t def_pxe_type = 0; +s_PXE_FILE_FUNC tftp_file_func = {tftp_open,tftp_read}; +s_PXE_FILE_FUNC http_file_func = {http_open,http_read}; s_PXE_FILE_FUNC *pxe_file_func[2]={ &tftp_file_func, - #if 0 - #ifdef FSYS_IPXE - &ipxe_file_func, - #endif - #endif + &http_file_func, }; +grub_u32_t cur_pxe_type = 0; +grub_u32_t def_pxe_type = 0; + +int is_ip6 = 0; +static char *default_server; +static grub_efi_net_interface_t *net_interface; +static grub_efi_net_interface_t *net_default_interface; +struct grub_efi_net_device *net_devices = 0; +BOOTPLAYER *discover_reply = 0; //引导播放器 +unsigned long long hex; + + +static grub_efi_net_interface_t *match_route (const char *server); +static void pxe_configure (void); +static void http_configure (void); +static grub_efi_ip6_config_manual_address_t *efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config); +static grub_efi_ip4_config2_manual_address_t * efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config); +static grub_err_t efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size); +static grub_efi_handle_t grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, grub_efi_device_path_t **r_device_path); +static grub_efi_net_interface_t * grub_efi_net_config_from_handle (grub_efi_handle_t *hnd, struct grub_efi_net_device *netdev, char **device, char **path); +static inline void __attribute__ ((always_inline)) write_char (char *str, grub_size_t *count, grub_size_t max_len, unsigned char ch); +static int grub_isdigit (int c); +unsigned long grub_strtoul (const char * restrict str, const char ** const restrict end, int base); +static inline char *grub_lltoa (char *str, int c, unsigned long long n); +grub_size_t grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, const grub_uint8_t *src, grub_size_t srcsize, const grub_uint8_t **srcend); +grub_uint8_t *grub_utf16_to_utf8 (grub_uint8_t *dest, const grub_uint16_t *src, grub_size_t size); +static int grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev, grub_efi_net_ip_manual_address_t *net_ip, int with_subnet); +static grub_efi_net_interface_t * grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address); +static grub_efi_net_interface_t * grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address); +static void grub_efi_net_add_pxebc_to_cards (void); +static void set_ip_policy_to_static (void); +static grub_efi_handle_t grub_efi_service_binding (grub_efi_handle_t dev, grub_efi_guid_t *service_binding_guid); + + +static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; +static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; +static grub_efi_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; +static grub_efi_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID; +static grub_efi_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID; +static grub_efi_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID; +static grub_efi_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID; +static grub_efi_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID; +static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; + +#if 0 static char* pxe_outhex (char* pc, unsigned char c); -static char* pxe_outhex (char* pc, unsigned char c) //pxe十六进制 +static char* pxe_outhex (char* pc, unsigned char c) //十六进制字节转ASCII码 { int i; @@ -151,586 +121,55 @@ static char* pxe_outhex (char* pc, unsigned char c) //pxe十六进制 } return pc; } - -grub_u32_t pxe_read_blk (grub_u32_t buf, grub_u32_t num); -grub_u32_t pxe_read_blk (grub_u32_t buf, grub_u32_t num) //pxe读大块 -{ - grub_u32_t ret = pxe_file_func[cur_pxe_type]->readblk(buf,num); - return ret; -} - - -/* - return 0 for seccess, 1 for failure 返回0表示成功,返回1表示失败 -*/ -static int try_blksize (int tmp); -static int try_blksize (int tmp) //尝试块尺寸 -{ - unsigned int nr; -#if 0 -#ifdef FSYS_IPXE - if (cur_pxe_type == PXE_FILE_TYPE_IPXE) return 0; //1 #endif -#endif - pxe_blksize = tmp; - printf_debug0 ("\nTry block size %d ...\n", pxe_blksize); //尝试块尺寸 - nr = 0; - tmp = pxe_open(pxe_tftp_name); - - if (!tmp) - { - printf_debug0 ("\nFailure: bootfile not found.\n"); //失败:找不到启动文件 - return 1; - } - - if (filemax <= pxe_blksize) - { - printf_debug0 ("\nFailure: Size %ld too small.\n", filemax); //失败:filemax尺寸太小 - pxe_close (); - return 1; - } - - nr = pxe_read_blk ((grub_u32_t)(grub_size_t)(char*)PXE_BUF, 1); //pxe读大块 - if (nr == PXE_ERR_LEN) - { - printf_debug0 ("\nFailure: Cannot read the first block.\n"); //失败:无法读取第一个块 - pxe_close (); - return 1; - } - - if (pxe_blksize != nr && filemax >= nr && nr <= PXE_MAX_BLKSIZE && nr >= PXE_MIN_BLKSIZE) - { - printf_debug0 ("\npxe_blksize tuned from %d to %d\n", pxe_blksize, nr); //pxe_blksize从%d调整为%d - pxe_blksize = nr; - } - - printf_debug0 ("\nUse block size %d\n", pxe_blksize); //使用块尺寸pxe_blksize - - pxe_close (); - return 0; -} - -static unsigned int config_already_restarted = 0; -static unsigned int server_is_dos = 0; -BOOTPLAYER *discover_reply = 0; //引导播放器 - -static void set_basedir(char *config); -static void set_basedir(char *config) //设置基本目录 +static int pxe_open (char* name) //pxe打开 { -// unsigned int n; - int n; //2023-11-24 - grub_u8_t path_sep = (cur_pxe_type == PXE_FILE_TYPE_TFTP && server_is_dos) ? '\\' : '/'; //路径分隔 - n = grub_strlen (config); //字符串尺寸 - - if (n > 126) - { - printf_warning("Warning! base name(%d chars) too long (> 126 chars).\n", n); //警告! 基本名称(%d个字符)太长 - n = 126; - config[n] = 0; - } - - if (*config != path_sep) + net_interface = NULL; + if (name != pxe_name) { - #if 0 - #ifdef FSYS_IPXE - char *ch = strstr(config,":"); - if (has_ipxe && ch && (grub_u32_t)(ch - config) < 10) - { - pxe_tftp_name = (char*)&pxe_tftp_open.FileName; - cur_pxe_type = def_pxe_type = PXE_FILE_TYPE_IPXE; //1 - } - else - { - if (cur_pxe_type == PXE_FILE_TYPE_TFTP) - #endif - #endif - pxe_tftp_name = (char*)&pxe_tftp_open.FileName; //tftp名称地址 - *pxe_tftp_name++ = path_sep; //设置tftp名称根目录 - #if 0 - #ifdef FSYS_IPXE - } - #endif - #endif + grub_strcpy (pxe_name, name); + name = pxe_name; + pxe_need_read = 1; } - - grub_memmove(pxe_tftp_name, config, n); //复制名称 - - while (n >= 0) if (pxe_tftp_name[--n] == path_sep) break; //查找路径分隔符 - - pxe_tftp_name += n; //指向分隔符后 -} - -static void print_ip (IP4 ip); - -int pxe_detect (int blksize, char *config); -int pxe_detect (int blksize, char *config) //pxe探测(块尺寸, 配置) -{ - unsigned int tmp; - char *pc; - int i, ret; - - if (! pxe_entry) - return 0; - - if (discover_reply->sip) //如果存在引导播放器->服务器IP - pxe_sip = discover_reply->sip; - if (discover_reply->gip) //如果存在引导播放器->网关IP - pxe_gip = discover_reply->gip; - else //否则 - {//get route gateway 获取路由网关 - grub_u8_t *p = discover_reply->vendor.d; //引导播放器->供应商.引导DHCPVEND - if (*(int*)p == 0x63538263)//DHCP magic cookie 99.130.83.99 - { - for(i=4;ibootfile[0]) //如果存在引导播放器->引导文件 - { - unsigned int n; - - for (n = 0; n < 127; n++) - { - if (discover_reply->bootfile[n] == '\\') //引导播放器->引导文件 - { - server_is_dos = 1; - break; - } - } - - grub_printf("\nBoot Server: "); //启动服务器 - print_ip(pxe_sip); //打印ip - grub_printf("\tBoot File: %s\n", discover_reply->bootfile); //引导播放器->引导文件: - - set_basedir((char*)discover_reply->bootfile); //设置基本目录(引导播放器->引导文件) - - /* read the boot file to determine the block size. 读取启动文件以确定块大小*/ - - if (blksize) //如果存在块尺寸 - pxe_blksize = blksize; - else if (try_blksize (1408) && try_blksize (512)) //如果块尺寸尝试1408及512失败 - { - pxe_blksize = 512; /* default to 512 默认为512*/ - printf_warning ("Warning! Cannot open bootfile. pxe_blksize set to default 512.\n"); //警告! 无法打开启动文件。 pxe_blksize设置为默认512 - } - } - else //如果不存在引导播放器->引导文件 - { - pxe_blksize = (blksize ? blksize : 512); /* default to 512 */ - printf_warning ("\nNo bootfile! pxe_blksize set to %d\n", pxe_blksize); //没有启动文件! pxe_blksize设置为 - pxe_tftp_name = (char*)&pxe_tftp_open.FileName[0]; //设置tftp名称地址 - } - - pxe_tftp_opened = 0; //没有打开 - - ret = 0; - - grub_memcpy ((char *) saved_pxe_mac, (char *) pxe_mac, 6); //备份pxe_mac 没有使用!! - saved_pxe_ip = pxe_yip; //备份客户IP 没有使用!! - - if (config) //如果存在配置 - { - if ((ret = grub_open(config))) //打开配置 - { - set_basedir(config); //设置基本目录 - grub_close(); //关闭 - goto done; //完成 - } - return 1; //退出 - } - //没有配置 - grub_strcpy (pxe_tftp_name, "/efi/grub/menu.lst"); //设置名称 - ret = pxe_dir (pxe_tftp_name); //目录 - if (ret && filemax) //如果成功,并且获得文件尺寸 - goto done; //完成 - if (pxe_tftp_open.Status != PXENV_STATUS_TFTP_FILE_NOT_FOUND)//坏服务器 找不到PXENV状态TFTP文件 - goto done; //完成 - /* Reports from Ruymbeke: opening /menu.lst will hang if it is a dir. 来自Ruymbeke的报告:如果/menu.lst是目录,则打开/menu.lst将挂起。 - * Do NOT use /menu.lst as a dir any more!! Use /menu for it instead. 不要再将/menu.lst用作目录! 使用/menu代替。 - */ - if (!config) //如果配置为零 - config = (char *)"/efi/grub/menu.lst/"; - - grub_strcpy (pxe_tftp_name, config); //设置名称 - - int MENU_DIR_NAME_LENGTH = grub_strlen(config); //菜单目录名称长度 - - pc = pxe_tftp_name + MENU_DIR_NAME_LENGTH; - pc = pxe_outhex (pc, pxe_mac_type); //pxe十六进制 - for (i = 0; i < pxe_mac_len; i++) - { - *(pc++) = '-'; - pc = pxe_outhex (pc, pxe_mac[i]); //pxe十六进制 - } - *pc = 0; - grub_printf ("\n%s\n", pxe_tftp_open.FileName); - if (pxe_dir (pxe_tftp_name)) //如果目录完成 - { - ret = 1; - goto done; //完成 - } - - pc = pxe_tftp_name + MENU_DIR_NAME_LENGTH; - tmp = pxe_yip; - for (i = 0; i < 4; i++) - { - pc = pxe_outhex (pc, tmp & 0xFF); //pxe十六进制 - tmp >>= 8; - } - *pc = 0; - do - { - grub_printf ("%s\n", pxe_tftp_open.FileName); - if (pxe_dir (pxe_tftp_name)) - { - ret = 1; - goto done; //完成 - } - if (checkkey() == 0x11b) break; - *(--pc) = 0; - } while (pc > pxe_tftp_name + MENU_DIR_NAME_LENGTH); - grub_strcpy (pc, "default"); - grub_printf ("%s\n", pxe_tftp_open.FileName); - ret = pxe_dir (pxe_tftp_name); - -#undef MENU_DIR_NAME_LENGTH - -done: //完成 - - if (ret && filemax) - { - char *new_config = config_file; - char *filename1 = pxe_tftp_name; - if (debug > 1) - { - printf_debug("\rPXE boot configfile:%s\n",(char *)pxe_tftp_open.FileName); //PXE引导配置文件: -// DEBUG_SLEEP - } - pxe_close (); - /* got file name. put it in config_file 有文件名。 把它放在config_file*/ - if (grub_strlen (filename1) >= ((char *)IMG(0x8270) - new_config)) - return ! (errnum = ERR_WONT_FIT); - /* set (pd) as root device. 设置(PD)为根设备*/ - saved_drive = PXE_DRIVE; //0x21 - saved_partition = current_partition; - /* Copy FILENAME to CONFIG_FILE. 将FILENAME复制到CONFIG_FILE*/ - while ((*new_config++ = *filename1++) != 0); - if (pxe_restart_config == 0) //如果pxe重新启动配置=0 - { - if (config_already_restarted == 0) //如果配置已重新启动=0 - { - pxe_restart_config = 1; //重新启动配置=1 - config_already_restarted = 1; //配置已重新启动=1 - } - return ret; //退出 - } - use_config_file = 1; //使用配置文件 - - /* Make sure that the user will not be authoritative. 确保用户不具有权威性。*/ - auth = 0; - - buf_drive = -1; /* invalidate disk cache. 使磁盘缓存无效*/ - buf_track = -1; /* invalidate disk cache. */ - saved_entryno = 0; //保存的条目号 - boot_drive = saved_drive; - install_partition = saved_partition; - current_drive = GRUB_INVALID_DRIVE; //0xFFFFFFFF - current_partition = 0xFFFFFF; - fsys_type = NUM_FSYS; - boot_part_addr = 0; - current_slice = 0; - - /* Restart cmain. 重新启动cmain*/ -#if 0 - asm volatile ("movl $0x7000, %esp"); /* set stack to STACKOFF */ -#ifdef HAVE_ASM_USCORE - asm volatile ("call _cmain"); - grub_halt(); -#else - asm volatile ("call cmain"); - grub_halt(); -#endif -#else - cmain(); //适应gcc高版本 2=23-05-24 -#endif - - /* Never reach here. 永不到达这里*/ - } - return ret; -} - -static int pxe_reopen (void); -static int pxe_reopen (void) //pxe重新打开 -{ - pxe_close (); - pxe_tftp_opened = pxe_file_func[cur_pxe_type]->open(pxe_tftp_name); - return pxe_tftp_opened; -} - -static int pxe_open (char* name); -static int pxe_open (char* name) //pxe打开 -{ - if (name != pxe_tftp_name) - { - grub_strcpy (pxe_tftp_name, name); - - if (cur_pxe_type == PXE_FILE_TYPE_TFTP && server_is_dos) //服务器是DOS - { - unsigned int n; - for (n = 0; n < 128; n++) - { - if (pxe_tftp_open.FileName[n] == '/') - pxe_tftp_open.FileName[n] = '\\'; - } - } - name = pxe_tftp_name; - } - pxe_close (); +// pxe_close (); /* We always use pxe_tftp_open.FileName for full file path. 我们始终使用pxe_tftp_open.FileName作为完整文件路径。名称是相对路径。 name is a relative path. */ - pxe_tftp_opened = pxe_file_func[cur_pxe_type]->open(name); - if (!pxe_tftp_opened) - { - if ((unsigned int)debug >= 0x7FFFFFFF) printf("Err: %d\n",pxe_tftp_open.Status); - return 0; - } - if (pxe_file_func[cur_pxe_type]->getsize()) - return 1; - pxe_close (); - return (pxe_tftp_opened = 0); -} + net_interface = match_route (default_server); //匹配路线 + if (!net_interface && !(net_interface = net_default_interface)) + { + printf_errinfo ("disk `%s' no route found\n", name); + return 0; + } + if (!cur_pxe_type) + pxe_configure (); //网络接口 + else + http_configure(); //网络接口 -void pxe_close (void); -void pxe_close (void) //pxe关闭 grub_pxe_close (struct grub_net_card *dev __attribute__ ((unused))) -{ - if (pxe_tftp_opened) + pxe_opened = pxe_file_func[cur_pxe_type]->open(); + if (!pxe_opened) { - pxe_file_func[cur_pxe_type]->close(); //调用关闭 - pxe_saved_pos = pxe_cur_ofs = pxe_read_ofs = 0; - pxe_tftp_opened = 0; + printf_debug ("Err: PXE is not open。\n"); + return 0; } + return 1; } -static unsigned int pxe_read_len (unsigned long long buf, unsigned long long len); -static unsigned int pxe_read_len (unsigned long long buf, unsigned long long len) //读长度(目的缓存, 尺寸字节) -{ - unsigned int old_ofs, sz; - - if (len == 0) - return 0; - - sz = 0; - old_ofs = pxe_cur_ofs; //当前偏移, 也就是起始字节 - pxe_cur_ofs += len; //结束字节 - if (pxe_cur_ofs > pxe_read_ofs) //如果结束字节>读偏移 - { - unsigned int nb, nr; - int nb_del, nb_pos; -// 原点 起始 读偏移 结束 -// |---------|------sz-------|---------------| -//PXE_BUF old_ofs pxe_read_ofs pxe_cur_ofs - - sz = (pxe_read_ofs - old_ofs); //读偏移-当前偏移=读尺寸 - if ((buf) && (sz)) //如果缓存存在, 并且读尺寸不为零 - { - grub_memmove64 (buf, (unsigned long long)(grub_size_t)(char*)(PXE_BUF + old_ofs), sz); //(PXE_BUF + old_ofs) -> buf - buf += sz; - } - pxe_cur_ofs -= pxe_read_ofs; /* bytes to read 要读取的字节*/ //当前偏移-读偏移=要读取的字节 - nb = pxe_cur_ofs / pxe_blksize; /* blocks to read 读取块*/ //要读取的字节/块尺寸=要读取的块 - nb_del = DOT_SIZE / pxe_blksize; //1000000/块尺寸=dot块 - if ((unsigned int)nb_del > nb) //如果dot块>要读取的块 - { - nb_del = 0; //dot块=0 - nb_pos = -1; // - } - else //如果dot块<=要读取的块 - nb_pos = nb - nb_del; //要读取的块-dot块 - pxe_cur_ofs -= pxe_blksize * nb; /* bytes residual 剩余字节数*/ //要读取的字节-块尺寸*要读取的块=剩余字节数 - if (pxe_read_ofs + pxe_blksize > PXE_BUFLEN) //如果读偏移+块尺寸 > 10000 - pxe_read_ofs = 0; //则读偏移=0 - while (nb > 0) //存在要读取的块 - { - unsigned int nn; - - nn = (PXE_BUFLEN - pxe_read_ofs) / pxe_blksize; //(缓存尺寸-读偏移)/块尺寸=实际读取的块 - if (nn > nb) //如果实际读取的块>要读取的块 - nn = nb; //则实际读取的块=要读取的块 - nr = pxe_read_blk ((grub_u32_t)(grub_size_t)(char*)PXE_BUF + pxe_read_ofs, nn); //pxe读大块 - - if (nr == PXE_ERR_LEN) //如果实际读字节=0 - return nr; //返回0 - sz += nr; //读尺寸+实际读字节 应当等于len - if (buf) //如果存在缓存 - { - grub_memmove64 (buf, (unsigned long long)(grub_size_t)(char*)(PXE_BUF + pxe_read_ofs), nr); //(PXE_BUF + old_ofs) -> buf - buf += nr; //调整缓存位置 - } - if (nr < nn * pxe_blksize) //如果实际读字节<实际读取的块*块尺寸, 完成了 - { - pxe_read_ofs += nr; //读偏移+实际读字节=下一读偏移 - pxe_cur_ofs = pxe_read_ofs; //当前偏移=读偏移 - return sz; //返回从起始读的字节 - } - //未完成 - nb -= nn; //要读取的块-实际读取的块 - if (nb) //如果有要读取的块 - pxe_read_ofs = 0; //读偏移=0 - else //如果没有要读取的块 - pxe_read_ofs += nr; //读偏移+实际读字节 - if ((int)nb <= nb_pos) //如果要读取的块 PXE_BUFLEN) //如果读偏移+块尺寸 > pxe缓存尺寸 - pxe_read_ofs = 0; //读偏移=0 - - nr = pxe_read_blk ((grub_u32_t)(grub_size_t)(char*)PXE_BUF + pxe_read_ofs, 1); //pxe读大块 - if (nr == PXE_ERR_LEN) //如果已读字节=0 - return nr; //返回0 - if (pxe_cur_ofs > nr) //如果剩余字节数 > 已读字节 - pxe_cur_ofs = nr; //剩余字节数 = 已读字节 - sz += pxe_cur_ofs; //读尺寸+剩余字节数 - if (buf) //如果存在缓存 - grub_memmove64 (buf, (unsigned long long)(grub_size_t)(char*)(PXE_BUF + pxe_read_ofs), pxe_cur_ofs); - pxe_cur_ofs += pxe_read_ofs; //当前偏移=剩余字节数+读偏移 - pxe_read_ofs += nr; //读偏移=读偏移+已读字节 - } - else //如果没有剩余字节数 - pxe_cur_ofs = pxe_read_ofs; //当前偏移=读偏移 - } - else //如果结束字节<=读偏移 - { - sz += len; //读尺寸+len - if (buf) //如果存在缓存 - grub_memmove64 (buf, (unsigned long long)(grub_size_t)(char *)PXE_BUF + old_ofs, len); - } - return sz; -} - -/* Mount the network drive. If the drive is ready, return 1, otherwise 安装网络驱动器。如果驱动器准备好了,返回1,否则返回0。 - return 0. */ -int pxe_mount (void); int pxe_mount (void) //pxe挂载 { if (current_drive != PXE_DRIVE || ! pxe_entry) //0x21 return 0; -#if 0 -#ifdef FSYS_IPXE - if (current_partition != IPXE_PART) //0x45585069 - cur_pxe_type = def_pxe_type; - else if (has_ipxe) - cur_pxe_type = PXE_FILE_TYPE_IPXE; //1 - else - return 0; -#endif -#endif - return 1; -} - - -//char old_name[128]; -/* Read up to SIZE bytes, returned in ADDR. 读取最多SIZE个字节,返回ADDR*/ -unsigned long long pxe_read (unsigned long long buf, unsigned long long len, unsigned int write); -unsigned long long -pxe_read (unsigned long long buf, unsigned long long len, unsigned int write) //pxe读 -{ - unsigned int nr; - - if (write == GRUB_WRITE) //如果写, 则错误 - return !(errnum = ERR_WRITE); - - if (! pxe_tftp_opened) //如果pxe没有打开, 则错误 - return PXE_ERR_LEN; - if (cur_pxe_type == PXE_FILE_TYPE_TFTP) //TFTP读, 从此完成 - { - if (!buf || write == GRUB_LISTBLK) - return 0; - - grub_memmove64 (buf, (unsigned long long)(grub_size_t)(char*)(efi_pxe_buf + filepos), len); - filepos += len; - return len; - } - - if (pxe_saved_pos != filepos) //如果保存的指针不等于文件指针 - { -//PXE_BUF filepos pxe_saved_pos filepos+pxe_cur_ofs -// 原点 文件指针 保存的指针 文件指针+当前偏移 -// |---------|------------------------------------|------------------------| -// |---------------------------旧当前偏移------------------------| -// |------新当前偏移--------| - if ((filepos < pxe_saved_pos) && (filepos+pxe_cur_ofs >= pxe_saved_pos)) //如果文件指针<保存的指针 , 并且(文件指针+当前偏移)>=保存的指针 - pxe_cur_ofs -= pxe_saved_pos - filepos; //当前偏移=当前偏移-(保存的指针-文件指针) 文件指针及保存的指针没有改变 - else //如果文件指针>=保存的指针 , 或者(文件指针+当前偏移)<保存的指针 - { -//PXE_BUF filepos filepos+pxe_cur_ofs pxe_saved_pos -// 原点 文件指针 文件指针+当前偏移 保存的指针 -// |---------|------------------------|------------------------------------| -// |--------当前偏移--------| - if (pxe_saved_pos > filepos) //如果文件指针<保存的指针 - { - if (! pxe_reopen ()) //pxe重新打开, 如果失败 - return PXE_ERR_LEN; //返回0 - } -//PXE_BUF pxe_saved_pos filepos -// 原点 保存的指针 文件指针 -// |---------|------------------------|-------------------------------------| -// |------------------(filepos-pxe_saved_pos)=nr------------------| - nr = pxe_read_len (0ULL, filepos - pxe_saved_pos); //不是实际读, 只返回尺寸 - if ((nr == PXE_ERR_LEN) || (pxe_saved_pos + nr != filepos)) //如果返回0, 或者(pxe_saved_pos + nr != filepos), 错误 - return PXE_ERR_LEN; - } - pxe_saved_pos = filepos; //更新保存的指针 - } - - nr = pxe_read_len (buf, len); //实际读 - if (nr != PXE_ERR_LEN) - { - filepos += nr; - pxe_saved_pos = filepos; - } - return nr; + return 1; } /* Check if the file DIRNAME really exists. Get the size and save it in 检查文件DIRNAME是否确实存在 @@ -748,7 +187,7 @@ int pxe_dir (char *dirname) //pxe查目录 char ch; ret = 1; ch = nul_terminate (dirname); //以00替换止字符串的空格,回车,换行,水平制表符 - + if (print_possibilities) //如果存在打印可能性 { char dir_tmp[128]; @@ -819,61 +258,122 @@ int pxe_dir (char *dirname) //pxe查目录 return ret; } -void pxe_unload (void); +/* Read up to SIZE bytes, returned in ADDR. 读取最多SIZE个字节,返回ADDR*/ +unsigned long long +pxe_read (unsigned long long buf, unsigned long long len, unsigned int write) //pxe读 +{ + if (write == GRUB_WRITE) //如果写, 则错误 + return !(errnum = ERR_WRITE); + + if (! pxe_opened) //如果pxe没有打开, 则错误 + return PXE_ERR_LEN; + + if (!buf || write == GRUB_LISTBLK) + return 0; + + if (!filepos && pxe_need_read) + { + pxe_need_read = 0; + if (len) //如果未分配内存 + pxe_allocate(); //分配内存 + + printf ("Copying data, please wait......\n"); + pxe_already_read = pxe_file_func[cur_pxe_type]->read(efi_pxe_buf, filemax); + } + + if (!len) + return 1; + if (pxe_already_read) + { + grub_memmove64 (buf, (unsigned long long)(grub_size_t)(char*)(efi_pxe_buf + filepos), len); + filepos += len; + return len; + } + + return 0; +} + +void pxe_close (void) //pxe关闭 grub_pxe_close (struct grub_net_card *dev __attribute__ ((unused))) +{ + if (pxe_opened) + { + grub_efi_boot_services_t *b; //引导服务 + b = grub_efi_system_table->boot_services; //系统表->引导服务 + if (efi_pxe_buf) + efi_call_1 (b->free_pool, efi_pxe_buf); //调用(释放池,释放数据) + efi_pxe_buf = 0; + pxe_opened = 0; + pxe_already_read = 0; + pxe_http_type = 0; //0/1=http/https + pxe_need_read = 0; //0/1=不用读/需要读 + } +} + void pxe_unload (void) //pxe卸载 { -#if 0 -#ifdef FSYS_IPXE - if (has_ipxe) pxe_file_func[PXE_FILE_TYPE_IPXE]->unload(); -#endif -#endif - pxe_file_func[PXE_FILE_TYPE_TFTP]->unload(); } -static int tftp_open(const char *name); -static int tftp_open(const char *name) //tftp打开 +int pxe_allocate(void) //分配内存 { grub_efi_status_t status; grub_efi_boot_services_t *b; //引导服务 b = grub_efi_system_table->boot_services; //系统表->引导服务 + unsigned long long bytes_needed; - if (!tftp_get_size()) - return 0; + if (map_pd) //不释放内存 + { + bytes_needed = ((filemax+4095)&(-4096ULL)); + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, + GRUB_EFI_RESERVED_MEMORY_TYPE, //保留内存类型 0 + (grub_efi_uintn_t)bytes_needed >> 12, (unsigned long long *)(grub_size_t)&efi_pxe_buf); //调用(分配页面,分配类型->任意页面,存储类型->运行时服务数据(6),分配页,地址) + if (status != GRUB_EFI_SUCCESS) //如果失败 + { + printf_errinfo ("out of map memory: %d\n",(int)status); + errnum = ERR_WONT_FIT; + return 0; + } + } + else + { + status = efi_call_3 (b->allocate_pool, GRUB_EFI_BOOT_SERVICES_DATA, //启动服务数据 4 + filemax + 0x200, (void **)(grub_size_t)&efi_pxe_buf); //(分配池,存储器类型->装载数据,分配字节,返回分配地址} + if (status != GRUB_EFI_SUCCESS) //失败 + { + printf_errinfo ("Couldn't allocate pool."); + return !(errnum = 0x1234); + } + } -// tftp_close (); //2023-11-24 - status = efi_call_3 (b->allocate_pool, GRUB_EFI_BOOT_SERVICES_DATA, //启动服务数据 4 - filemax + 0x200, (void**)&efi_pxe_buf); //(分配池,存储器类型->装载数据,分配字节,返回分配地址} - if (status != GRUB_EFI_SUCCESS) //失败 - { - printf_errinfo ("Couldn't allocate pool."); - return 0; - } memset(efi_pxe_buf,0,filemax); //2023-11-24 + return 1; +} - status = efi_call_10 (pxe_entry->mtftp, //tftp功能 - pxe_entry, //pxe结构 - GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, //TFTP读文件 - (char *)efi_pxe_buf, //缓存 - 0, - (grub_efi_uint64_t *)(grub_size_t)&filemax,//缓存尺寸 - NULL, //块尺寸 - (IP4 *)(grub_size_t)&pxe_sip, //服务器IP - (char *)name, //文件名 - NULL, - 0); +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int tftp_open(void) //tftp打开 +{ + grub_efi_status_t status; + status = efi_call_10 (pxe_entry->mtftp, //tftp功能 + pxe_entry, //pxe结构 + GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, //TFTP获得文件尺寸 + NULL, //缓存 + 0, + (grub_efi_uint64_t *)(grub_size_t)&filemax, //缓存尺寸 + NULL, //块尺寸 + (IP4 *)(grub_size_t)&pxe_sip, //服务器IP + pxe_name, //文件名 + NULL, + 0); if (status != GRUB_EFI_SUCCESS) //失败 { - printf_errinfo ("Couldn't open file."); - return 0; + printf_errinfo ("Couldn't get file size\n"); + return !(errnum = 0x1234); } - pxe_tftp_opened = 1; filepos = 0; return 1; } - -static grub_u32_t tftp_get_size(void); +#if 0 static grub_u32_t tftp_get_size(void) //TFTP获得文件尺寸 { grub_efi_status_t status; @@ -886,22 +386,41 @@ static grub_u32_t tftp_get_size(void) //TFTP获得文件尺寸 (grub_efi_uint64_t *)(grub_size_t)&filemax, //缓存尺寸 NULL, //块尺寸 (IP4 *)(grub_size_t)&pxe_sip, //服务器IP - pxe_tftp_name, //文件名 + pxe_name, //文件名 NULL, 0); - if (status != GRUB_EFI_SUCCESS) //失败 { - printf_errinfo ("Couldn't get file size"); - return 0; + printf_errinfo ("Couldn't get file size\n"); + return !(errnum = 0x1234); } return filemax; } - -static grub_u32_t tftp_read_blk (grub_u32_t buf, grub_u32_t num) +#endif +static grub_size_t +tftp_read (char *buf, grub_u64_t len) //efi读 { - return 0; + grub_efi_status_t status; + + status = efi_call_10 (pxe_entry->mtftp, //tftp功能 + pxe_entry, //pxe结构 + GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, //TFTP读文件 + buf, //缓存 + 0, + (grub_efi_uint64_t *)(grub_size_t)&filemax,//缓存尺寸 + NULL, //块尺寸 + (IP4 *)(grub_size_t)&pxe_sip, //服务器IP + pxe_name, //文件名 + NULL, + 0); + if (status != GRUB_EFI_SUCCESS) //失败 + { + printf_errinfo ("Couldn't read file."); + return !(errnum = 0x1234); + } + + return filemax; } int tftp_write (const char *name) //tftp写 2023-11-24 @@ -921,351 +440,2717 @@ int tftp_write (const char *name) //tftp写 2023-11-24 0); if (status != GRUB_EFI_SUCCESS) //失败 { - printf_errinfo ("Couldn't open file."); - return 0; + printf_errinfo ("Couldn't write file."); + return !(errnum = 0x1234); } return 1; } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//net/efi/http.c +#define GRUB_MAX_UTF16_PER_UTF8 1 +#define GRUB_EFI_IP6_PREFIX_LENGTH 64 +int prefer_ip6; +static grub_efi_boolean_t request_callback_done; +static grub_efi_boolean_t response_callback_done; -static void tftp_close (void) //tftp关闭 +static void +grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)), + void *context __attribute__ ((unused))) //请求回调 { - grub_efi_boot_services_t *b; //引导服务 - b = grub_efi_system_table->boot_services; //系统表->引导服务 - if (efi_pxe_buf) - efi_call_1 (b->free_pool, efi_pxe_buf); //调用(释放池,释放数据) - pxe_tftp_opened = 0; - efi_pxe_buf = 0; + request_callback_done = 1; } -static void tftp_unload(void) //tftp卸载 +static void +grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)), + void *context __attribute__ ((unused))) //响应回调 { - if (! pxe_entry) - return; + response_callback_done = 1; +} - pxe_close (); +static int http_open(void) //http打开 +{ + int err; - if (pxe_keep) - return; + err = efihttp_request (net_devices->http, (char *)default_server, (char *)pxe_name, 0, 1, 0); //请求头部 + if (err) + return 0; + + err = efihttp_request (net_devices->http, (char *)default_server, (char *)pxe_name, 0, 0, &filemax); //请求获得,返回尺寸 + if (err) + return 0; + + filepos = 0; + return 1; } -#endif //ifdef FSYS_PXE -static void print_ip (IP4 ip); -static void print_ip (IP4 ip) //打印ip +static grub_size_t +http_read (char *buf, grub_u64_t len) //efi读 { - int i; + grub_efi_http_message_t response_message; //响应消息 + grub_efi_http_token_t response_token; //响应令牌 + grub_efi_status_t status; //状态 + grub_size_t sum = 0; //和 + grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; //引导服务 + grub_efi_http_t *http = net_devices->http; //http入口 + + if (!len) //尺寸为零 + { + printf_errinfo ("Invalid arguments to EFI HTTP Read\n"); //EFI HTTP读取的参数无效 + return 0; + } - for (i = 0; i < 3; i++) - { - grub_printf ("%d.", (grub_size_t)(unsigned char)ip); - ip >>= 8; - } - grub_printf ("%d", (grub_size_t)(unsigned char)ip); -} - -int pxe_func (char *arg, int flags); -int pxe_func (char *arg, int flags) //pxe函数 -{ - if (! pxe_entry) - { - goto bad_argument; - } - if (*arg == 0) //无参数,打印信息 - { - char buf[4], *pc; - int i; - - pxe_tftp_name[0] = '/'; - pxe_tftp_name[1] = 0; - grub_printf ("blksize: %d [%s]\n", pxe_blksize,def_pxe_type==1?"iPXE":"pxe"); //512[pxe] 1408[pxe] - grub_printf ("basedir: %s\n",pxe_tftp_open.FileName); // / - grub_printf ("bootfile: %s\n", discover_reply->bootfile); //引导播放器->引导文件 // menu.ipxe - grub_printf ("client ip : "); //2.1.6.0 192.168.56.6 - print_ip (pxe_yip); - grub_printf ("\nserver ip : "); //75.78.30.32 192.168.56.1 - print_ip (pxe_sip); - grub_printf ("\ngateway ip : "); //0.0.128.0 0.0.0.0 - print_ip (pxe_gip); - grub_printf ("\nmac : "); // 00-0c-29-8d-cc-d9 - for (i = 0; i < pxe_mac_len; i++) - { - pc = buf; - pc = pxe_outhex (pc, pxe_mac[i]); - *pc = 0; - grub_printf ("%s%c", buf, ((i == pxe_mac_len - 1) ? '\n' : '-')); - } - } - else if (grub_memcmp(arg, "blksize", sizeof("blksize") - 1) == 0) //设置块尺寸 - { - unsigned long long val; - grub_u32_t force=arg[7] != '='; - arg = skip_to (1, arg); - if (! safe_parse_maxint (&arg, &val)) - return 0; - if (val > PXE_MAX_BLKSIZE) //16384 0x4000 - val = PXE_MAX_BLKSIZE; - if (val < PXE_MIN_BLKSIZE) //128 0x80 - val = PXE_MIN_BLKSIZE; - pxe_blksize = val; - if (!force) try_blksize(val); - } - else if (grub_memcmp (arg, "basedir", sizeof("basedir") - 1) == 0) //基本目录 - { - arg = skip_to (0, arg); - if (*arg == 0) - { - grub_printf ("No pathname\n"); - goto bad_argument; - } - set_basedir(arg); //设置基本目录 - } - else if (grub_memcmp (arg, "keep", sizeof("keep") - 1) == 0) //保持 - pxe_keep = 1; - else if (grub_memcmp (arg, "nokeep", sizeof("nokeep") - 1) == 0) //不保留 - pxe_keep = 0; - else if (grub_memcmp (arg, "unload", sizeof("unload") - 1) == 0) //卸载 - { - pxe_keep = 0; - pxe_unload (); - } - else if (grub_memcmp (arg, "detect", sizeof("detect") - 1) == 0) //探测 - { - unsigned long long blksize = 0; - /* pxe_detect should be done before any other command. 探测应该在任何其他命令之前完成。*/ - arg = skip_to (0, arg); - - if (*arg >= '0' && *arg <= '9') - { - if (! safe_parse_maxint (&arg, &blksize)) //块尺寸 - return 0; - arg = skip_to (0, arg); - if (*arg == 0) - arg = 0; - } else if (*arg == 0) - arg = 0; - return pxe_detect ((int)blksize, arg); //pxe探测 - } - #if 0 - #ifdef FSYS_IPXE - else if (has_ipxe && grub_memcmp (arg ,"type",sizeof("type") - 1) == 0) //设置ipxe类型 - { - arg = skip_to (0, arg); - switch(*arg) - { - case '0': - case '1': - def_pxe_type = *arg - '0'; - break; - default: - goto bad_argument; - } - } - #endif - #endif - else + efi_call_5 (b->create_event, //创建事件 + GRUB_EFI_EVT_NOTIFY_SIGNAL, //事件的类型 通知信号 + GRUB_EFI_TPL_CALLBACK, //事件的优先级 回调 + grub_efi_http_response_callback, //事件处理函数 响应回调 + NULL, //传递给事件处理函数的参数 + &response_token.event); //创建的事件 + + while (len) + { + //响应消息 + response_message.data.response = NULL; //响应消息.数据.响应 + response_message.header_count = 0; //响应消息.标头计数 + response_message.headers = NULL; //响应消息.标头 + response_message.body_length = len; //响应消息.体长 设置为654800,他实际读ff82,ffff,8e94等等 + response_message.body = (void *)(grub_size_t)buf; //响应消息.体 + //响应令牌 + response_token.message = &response_message; //响应令牌.消息 + response_token.status = GRUB_EFI_NOT_READY; //响应令牌.状态 还没准备好 + + response_callback_done = 0; //响应回调已完成=0 + + status = efi_call_2 (http->response, http, &response_token); //响应 + if (status != GRUB_EFI_SUCCESS) //失败 { -bad_argument: - errnum = ERR_BAD_ARGUMENT; + efi_call_1 (b->close_event, response_token.event); //关闭事件 + printf_errinfo ("Error! status=%d\n", (int)status); //错误!状态= return 0; } - return 1; -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//efinet.c -/* GUID. */ -struct grub_net_card *grub_net_cards = NULL; -static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID; //简单网络 -static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; -static struct grub_net_card_driver efidriver = - { - #if 0 - .name = "efinet", - .open = open_card, //打开 - .close = close_card, //关闭 - .send = send_card_buffer, //发送 - .recv = get_card_packet //接收 - #endif - }; + while (!response_callback_done) //等待回调完成 + efi_call_1(http->poll, http); //获得 + //修正下一次参数 + sum += response_message.body_length; //和 + buf += response_message.body_length; //缓存 + len -= response_message.body_length; //剩余尺寸 + } + efi_call_1 (b->close_event, response_token.event); //关闭事件 + return sum; //返回读尺寸 +} -//============================================================================================================================ -static void grub_efinet_findcards (void); static void -grub_efinet_findcards (void) //查找卡 +http_configure (void) //http配置 { - grub_efi_uintn_t num_handles; - grub_efi_handle_t *handles; - grub_efi_handle_t *handle; + grub_efi_http_config_data_t http_config; //HTTP配置数据 + grub_efi_httpv4_access_point_t httpv4_node; //HTTPv4访问点 + grub_efi_httpv6_access_point_t httpv6_node; //HTTPv6访问点 + grub_efi_status_t status; + grub_efi_http_t *http = net_devices->http; //HTTP入口 - /* Find handles which support the disk io interface. 查找支持磁盘io接口的句柄。 */ - handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &net_io_guid, - 0, &num_handles); //定位句柄 - if (! handles) //失败 - return; + grub_memset (&http_config, 0, sizeof(http_config)); //初始化HTTP配置数据 + http_config.http_version = GRUB_EFI_HTTPVERSION11; //HTTP配置数据.版本=11 + http_config.timeout_millisec = 5000; //HTTP配置数据.超时=5000毫秒 - for (handle = handles; num_handles--; handle++) - { - grub_efi_simple_network_t *net; //简单网络 - struct grub_net_card *card; //网卡 - grub_efi_device_path_t *dp, *parent = NULL, *child = NULL; //设备路径 - - /* EDK2 UEFI PXE driver creates IPv4 and IPv6 messaging devices as EDK2 UEFI PXE驱动程序将IPv4和IPv6消息设备创建为主MAC消息设备的子设备。 - children of main MAC messaging device. We only need one device with 我们只需要每个物理卡一个绑定SNP的设备,否则它们在轮询传入数据包时会相互竞争。 - bound SNP per physical card, otherwise they compete with each other - when polling for incoming packets. - */ - dp = grub_efi_get_device_path (*handle); //设备路径 - if (!dp) //失败 - continue; - - for (; ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp); dp = GRUB_EFI_NEXT_DEVICE_PATH (dp)) - { - parent = child; - child = dp; - } - if (child - && GRUB_EFI_DEVICE_PATH_TYPE (child) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE //并且是通讯设备路径 3 - && (GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE //并且是IPV4设备子路径 12 - || GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) // 或者是IPV6设备子路径 13 - && parent - && GRUB_EFI_DEVICE_PATH_TYPE (parent) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE //并且是通讯设备路径 3 - && GRUB_EFI_DEVICE_PATH_SUBTYPE (parent) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE) //并且是MAC地址设备子路径 11 - continue; - - net = grub_efi_open_protocol (*handle, &net_io_guid, - GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); //打开协议.通过句柄 - if (! net) //失败 - /* This should not happen... Why? 这不应该发生...为什么? */ - continue; - - if (net->mode->state == GRUB_EFI_NETWORK_STOPPED //如果网络停止 0 - && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS) //并且启动网络失败 - continue; - - if (net->mode->state == GRUB_EFI_NETWORK_STOPPED) //如果网络停止 0 - continue; - - if (net->mode->state == GRUB_EFI_NETWORK_STARTED //如果网络起动 1 - && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS) //并且网络初始化失败 - continue; - - card = grub_zalloc (sizeof (struct grub_net_card)); //分配卡缓存 - if (!card) //失败 - { - grub_free (handles); - return; - } - card->mtu = net->mode->max_packet_size; //最大包尺寸 5dc - card->txbufsize = ALIGN_UP (card->mtu, 64) + 256; //tx缓存尺寸 700 - card->txbuf = grub_zalloc (card->txbufsize); //分配tx缓存 101c14c0 - if (!card->txbuf) //失败 - { - grub_free (handles); - grub_free (card); - return; - } - card->txbusy = 0; //忙碌 0 - - card->rcvbufsize = ALIGN_UP (card->mtu, 64) + 256; //rcv缓存尺寸 700 - card->driver = &efidriver; //驱动器 10e66094 - card->flags = 0; //标记 0 - card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; //默认地址类型=以太网 0 - grub_memcpy (card->default_address.mac, //mac 101c1be4 - net->mode->current_address, //当前地址 111b3280 - sizeof (card->default_address.mac)); //尺寸 6 - card->efi_net = net; //简单网络 - card->efi_handle = *handle; //句柄 111bb290 - grub_net_cards = card; - grub_free (card); //释放 - } - grub_free (handles); //释放 + if (prefer_ip6) //如果首选ip6 + { + grub_efi_uintn_t sz; + grub_efi_ip6_config_manual_address_t manual_address;//ip6配置手动地址 + + http_config.local_address_is_ipv6 = 1; //HTTP配置数据.本地地址是ipv6 = 0 + sz = sizeof (manual_address); //ip6配置手动地址尺寸 + status = efi_call_4 (net_devices->ip6_config->get_data, net_devices->ip6_config, + GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, + &sz, &manual_address); //ip6配置获得手动地址 + + if (status == GRUB_EFI_NOT_FOUND) + { + printf_errinfo ("The MANUAL ADDRESS is not found\n"); + errnum = 0x1234; + return ; + } + + //手动界面将返回缓冲区太小!!! + if (status != GRUB_EFI_SUCCESS) + { + printf_errinfo ("??? %d\n",(int) status); + errnum = 0x1234; + return; + } + + grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address)); + httpv6_node.local_port = 0; + http_config.access_point.ipv6_node = &httpv6_node; + } + else //是ip4 + { + http_config.local_address_is_ipv6 = 0; //HTTP配置数据.本地地址是ipv6 = 0 + grub_memset (&httpv4_node, 0, sizeof(httpv4_node)); //HTTPv4访问点初始化 + httpv4_node.use_default_address = 1; //HTTPv4访问点. + + //在此处使用随机端口 + //请参阅edk2/NetworkPkg/TcpDxe/TcpDispatcher中的TcpBind().c + httpv4_node.local_port = 0; + http_config.access_point.ipv4_node = &httpv4_node; + } + + status = efi_call_2 (http->configure, http, &http_config); //配置 + + if (status == GRUB_EFI_ALREADY_STARTED) + { + return; + } + if (status != GRUB_EFI_SUCCESS) + { + printf_errinfo ("couldn't configure http protocol, reason: %d\n", (int)status); + errnum = 0x1234; + return ; + } } -static void grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, char **path); +static grub_err_t +efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size) //http请求 +{ + grub_efi_http_request_data_t request_data; + grub_efi_http_message_t request_message; + grub_efi_http_token_t request_token; + grub_efi_http_response_data_t response_data; + grub_efi_http_message_t response_message; + grub_efi_http_token_t response_token; + grub_efi_http_header_t request_headers[3]; + // grub_efi_http_header_t request_headers[4]; + + grub_efi_status_t status; + grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; + char url[128]; + + //请求标头 + request_headers[0].field_name = (grub_efi_char8_t *)"Host"; //请求标头.字段名称 主机,服务机 + request_headers[0].field_value = (grub_efi_char8_t *)server; //请求标头.字段值 "192.168.114.1" + request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; //请求标头.字段名称 接受 + request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; //请求标头.字段值 + request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; //请求标头.字段名称 用户代理 + request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; //请求标头.字段值 +// request_headers[3].field_name = (grub_efi_char8_t *)"Range"; //请求标头.字段名称 范围 +// request_headers[3].field_value = (grub_efi_char8_t *)"bytes=0-1023"; //请求标头.字段值 字节范围 + + { + grub_efi_char16_t *ucs2_url; //ucs2网址 + grub_size_t url_len, ucs2_url_len; //网址尺寸, ucs2网址尺寸 + const char *protocol = (use_https == 1) ? "https" : "http"; //协议 + + +// if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0) //字符串到ip6地址成立 +// url = grub_xasprintf ("%s://[%s]%s", protocol, server, name); //协议,服务器,名称 + if (is_ip6) //是ip6 + grub_sprintf (url, "%s://[%s]%s", protocol, server, name); //协议,服务器,名称 + else //ip4地址 +// url = grub_xasprintf ("%s://%s%s", protocol, server, name); + grub_sprintf (url, "%s://%s%s", protocol, server, name); + + url_len = grub_strlen (url); //网址尺寸 + ucs2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8; //ucs2网址尺寸 + ucs2_url = grub_zalloc ((ucs2_url_len + 1) * sizeof (ucs2_url[0])); + + if (!ucs2_url) + return errnum = 0x1234; + + ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */ + ucs2_url[ucs2_url_len] = 0; //结束符 +// grub_free (url); + request_data.url = ucs2_url; //请求信息.url + } + //请求数据.方法 + request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET; //头朝前?头:获得 + //请求信息 + request_message.data.request = &request_data; //请求信息.数据请求 + request_message.header_count = 3; //请求信息.标头计数 +// request_message.header_count = 4; //请求信息.标头计数 + request_message.headers = request_headers; //请求信息.标头 + request_message.body_length = 0; //请求信息.体尺寸 + request_message.body = NULL; //请求信息.体 + + //请求令牌 + request_token.event = NULL; //请求令牌.事件 + request_token.status = GRUB_EFI_NOT_READY; //请求令牌.状态 未准备好 + request_token.message = &request_message; //请求令牌.消息 + + request_callback_done = 0; //请求回调完成=0 + status = efi_call_5 (b->create_event, //创建事件 + GRUB_EFI_EVT_NOTIFY_SIGNAL, //事件的类型 通知信号 + GRUB_EFI_TPL_CALLBACK, //事件的优先级 回调 + grub_efi_http_request_callback, //事件处理函数 请求回调 + NULL, //传递给事件处理函数的参数 + &request_token.event); + if (status != GRUB_EFI_SUCCESS) //失败 + { + grub_free (request_data.url); + printf_errinfo ("Fail to create an event status=%x\n", status); + return (errnum = 0x1234); + } + + efi_call_1 (grub_efi_system_table->boot_services->stall, 50000); //延时50毫秒 + + status = efi_call_2 (http->request, http, &request_token); //请求 有时莫名其妙地死在这里,必须重新启动虚拟机!!!! + if (status != GRUB_EFI_SUCCESS) //失败 + { + efi_call_1 (b->close_event, request_token.event); //关闭事件 + grub_free (request_data.url); + printf_errinfo ("Fail to send a request status=%x\n", status); //12超时 f拒绝访问 + return (errnum = 0x1234); + } + /* TODO: Add Timeout */ + while (!request_callback_done) //等待请求回调完成 + efi_call_1(http->poll, http); //获得 + //响应数据 + response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS; //响应数据.状态代码 0=不受支持的状态 + //响应消息 + response_message.data.response = &response_data; //响应数据.数据响应 + //herader_count将由HTTP驱动程序在响应时更新 + response_message.header_count = 0; //响应数据.标头计数 + //标头将由驱动程序在响应时填充 + response_message.headers = NULL; //响应数据.标头 + //使用零BodyLength仅接收响应标头 + response_message.body_length = 0; //响应数据.体尺寸 + response_message.body = NULL; //响应数据.体 + //响应令牌.事件 + response_token.event = NULL; + + status = efi_call_5 (b->create_event, //创建事件 + GRUB_EFI_EVT_NOTIFY_SIGNAL, //事件的类型 通知信号 + GRUB_EFI_TPL_CALLBACK, //事件的优先级 回调 + grub_efi_http_response_callback, //事件处理函数 响应回调 + NULL, //传递给事件处理函数的参数 + &response_token.event); + if (status != GRUB_EFI_SUCCESS) + { + efi_call_1 (b->close_event, request_token.event); //关闭事件 + grub_free (request_data.url); + printf_errinfo ("Fail to create an event\n status=%x\n", status); + return (errnum = 0x1234); + } + //响应令牌 + response_token.status = GRUB_EFI_SUCCESS; //响应令牌.状态 成功 + response_token.message = &response_message; //响应令牌.消息 + + efi_call_1 (grub_efi_system_table->boot_services->stall, 50000); //延时50毫秒 + + //等待HTTP响应 + response_callback_done = 0; //响应回调完成=0 + status = efi_call_2 (http->response, http, &response_token); //响应 + if (status != GRUB_EFI_SUCCESS) + { + efi_call_1 (b->close_event, response_token.event); //关闭事件 + efi_call_1 (b->close_event, request_token.event); //关闭事件 + grub_free (request_data.url); + printf_errinfo ("Fail to receive a response! status=%x\n", status);//68, 69 + return (errnum = 0x1234); + } + + /* TODO: Add Timeout */ + while (!response_callback_done) //等待响应回调完成 + efi_call_1 (http->poll, http); //获得 + + //返回部分内容,是我们请求了范围,不是错误 + if (response_message.data.response->status_code == GRUB_EFI_HTTP_STATUS_206_PARTIAL_CONTENT && request_message.header_count == 4) + goto aaa; + + if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK) + { + grub_efi_http_status_code_t status_code = response_message.data.response->status_code; + + if (response_message.headers) + efi_call_1 (b->free_pool, response_message.headers); + efi_call_1 (b->close_event, response_token.event); //关闭事件 + efi_call_1 (b->close_event, request_token.event); //关闭事件 + grub_free (request_data.url); + if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND) //未找到 + { + printf_errinfo ("file `%s' not found\n", name); + return (errnum = 0x1234); + } + else + { + printf_errinfo ("unsupported uefi http status code %d\n", status_code); + return (errnum = 0x1234); + } + } + +aaa: + if (file_size) //获得文件尺寸 + { + int i; + /* parse the length of the file from the ContentLength header 从ContentLength标头解析文件的长度*/ + for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i) + { +//Connection close 连接: 关闭 +//Content-Type application/octet-stream 内容类型: 应用程序/八位字节流 +//Content-Length 6637568 内容尺寸: 6637568(ASCII码) +//Server Indy/9.00.10 服务器: Indy/9.00.10 +//Range 0-1023 范围: 0-1023字节 + if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length")) + { +// *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10); + safe_parse_maxint ((char**)&response_message.headers[i].field_value, &hex); + *file_size = hex; + break; + } + } + } + + if (response_message.headers) + efi_call_1 (b->free_pool, response_message.headers); + efi_call_1 (b->close_event, response_token.event); //关闭事件 + efi_call_1 (b->close_event, request_token.event); //关闭事件 + grub_free (request_data.url); + + return GRUB_ERR_NONE; +} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//net/efi/pxe.c static void -grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - char **path) //实际网络配置 +pxe_configure (void) //pxe配置 { - struct grub_net_card *card; //网卡 - grub_efi_device_path_t *dp; //设备路径 + grub_efi_pxe_t *pxe = (is_ip6) ? net_devices->ip6_pxe : net_devices->ip4_pxe; //首选ip6,则选择ip6_pxe,否则选择ip4_pxe + grub_efi_pxe_mode_t *mode = pxe->mode; - dp = grub_efi_get_device_path (hnd); //获得设备路径 - if (! dp) //失败 - return; + if (!mode->started) //如果未启动 + { + grub_efi_status_t status; + status = efi_call_2 (pxe->start, pxe, is_ip6); //启动 - FOR_NET_CARDS (card) //查找 define FOR_NET_CARDS(var) for (var = grub_net_cards; var; var = var->next) - { - grub_efi_device_path_t *cdp; - struct grub_efi_pxe_mode *pxe_mode; - if (card->driver != &efidriver) //不是efidriver - continue; - cdp = grub_efi_get_device_path (card->efi_handle); //获得设备路径 - if (! cdp) //失败 - continue; + if (status != GRUB_EFI_SUCCESS) //失败 + printf_debug ("Couldn't start PXE\n"); //无法启动PXE + } - if (grub_efi_compare_device_paths (dp, cdp) != 0) //比较设备路径 - { - grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp; - int match; - - /* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6 EDK2 UEFI PXE驱动程序创建类型为IPv4/IPv6的伪设备作为以太网卡的子代. - as children of Ethernet card and binds PXE and Load File protocols 并将PXE和加载文件协议与其绑定。 - to it. Loaded Image Device Path protocol will point to these pseudo 加载的图像设备路径协议将指向这些伪设备。 - devices. We skip them when enumerating cards, so here we need to 我们在枚举卡时会跳过它们,因此在这里我们需要找到匹配的MAC设备。 - find matching MAC device. - */ - ldp = grub_efi_find_last_device_path (dp); //查找最后设备路径 - if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE //如果不是通讯设备路径 3 - || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE //不是IPV4设备子路径 12 - && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) //不是IPV6设备子路径 13 - continue; - dup_dp = grub_efi_duplicate_device_path (dp); //复制设备路径 - if (!dup_dp) //失败 - continue; - dup_ldp = grub_efi_find_last_device_path (dup_dp); //查找最后设备路径 - dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; //设备路径节点的结束 0x7f - dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; //0xff - dup_ldp->length = sizeof (*dup_ldp); //尺寸 - match = grub_efi_compare_device_paths (dup_dp, cdp) == 0; //比较设备路径,返回真假 - grub_free (dup_dp); //释放 - if (!match) //如果假 - continue; - } - pxe_entry = grub_efi_open_protocol (hnd, &pxe_io_guid, - GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); //打开协议 - if (! pxe_entry) //失败 - continue; - pxe_mode = pxe_entry->mode; //模式 - discover_reply = (BOOTPLAYER *)((char *)&pxe_mode->dhcp_ack.dhcpv4); //引导播放器 + printf_debug ("PXE STARTED: %u\n", mode->started); //PXE已启动: + printf_debug ("PXE USING IPV6: %u\n", mode->using_ipv6); //使用IPV6的PXE: - pxe_yip = discover_reply->yip; //客户IP //02 01 06 00 - pxe_sip = discover_reply->sip; //服务器IP - pxe_gip = discover_reply->gip; //网关IP - pxe_mac_type = discover_reply->Hardware; //硬件类型 - pxe_mac_len = discover_reply->Hardlen; //硬件地址长度 - pxe_blksize = grub_net_cards->mtu; //最大块尺寸 - cur_pxe_type = PXE_FILE_TYPE_TFTP; //当前类型 - set_basedir((char*)discover_reply->bootfile); //设置基本目录(引导播放器->引导文件) - grub_memcpy ((char *)pxe_mac, (char *)&discover_reply->CAddr, pxe_mac_len); + if (mode->using_ipv6) //如果使用ipv6 + { + grub_efi_ip6_config_manual_address_t *manual_address; + manual_address = efi_ip6_config_manual_address (net_devices->ip6_config); //获得ip6配置手动地址 + + if (manual_address && + grub_memcmp ((const char *)manual_address->address, (const char *)mode->station_ip.v6, sizeof (manual_address->address)) != 0) //复制站ipv6作为手动地址成功 + { + grub_efi_status_t status; + grub_efi_pxe_ip_address_t station_ip; + + grub_memcpy (station_ip.v6.addr, manual_address->address, sizeof (station_ip.v6.addr)); + status = efi_call_3 (pxe->set_station_ip, pxe, (grub_u32_t *)(grub_size_t)&station_ip, NULL); //设置站ip + + if (status != GRUB_EFI_SUCCESS) + printf_debug ("Couldn't set station ip\n"); + grub_free (manual_address); + } + } + else + { + grub_efi_ip4_config2_manual_address_t *manual_address; + manual_address = efi_ip4_config_manual_address (net_devices->ip4_config); //获得ip4配置手动地址 + + if (manual_address && + grub_memcmp ((const char *)manual_address->address, (const char *)mode->station_ip.v4, sizeof (manual_address->address)) != 0) //复制站ipv4作为手动地址成功 + { + grub_efi_status_t status; + grub_efi_pxe_ip_address_t station_ip; + grub_efi_pxe_ip_address_t subnet_mask; + + grub_memcpy (station_ip.v4.addr, manual_address->address, sizeof (station_ip.v4.addr)); + grub_memcpy (subnet_mask.v4.addr, manual_address->subnet_mask, sizeof (subnet_mask.v4.addr)); + + status = efi_call_3 (pxe->set_station_ip, pxe, (grub_u32_t *)(grub_size_t)&station_ip, (grub_u32_t *)(grub_size_t)&subnet_mask);//设置站ip + + if (status != GRUB_EFI_SUCCESS) + printf_debug ("Couldn't set station ip\n"); + + grub_free (manual_address); + } + } #if 0 -#ifdef FSYS_IPXE - ipxe_init(); -#endif + if (mode->using_ipv6) + { + printf_debug ("PXE STATION IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", //PXE站IP: + mode->station_ip.v6.addr[0], + mode->station_ip.v6.addr[1], + mode->station_ip.v6.addr[2], + mode->station_ip.v6.addr[3], + mode->station_ip.v6.addr[4], + mode->station_ip.v6.addr[5], + mode->station_ip.v6.addr[6], + mode->station_ip.v6.addr[7], + mode->station_ip.v6.addr[8], + mode->station_ip.v6.addr[9], + mode->station_ip.v6.addr[10], + mode->station_ip.v6.addr[11], + mode->station_ip.v6.addr[12], + mode->station_ip.v6.addr[13], + mode->station_ip.v6.addr[14], + mode->station_ip.v6.addr[15]); + } + else + { + printf_debug ("PXE STATION IP: %d.%d.%d.%d\n", //PXE站IP: + mode->station_ip.v4.addr[0], + mode->station_ip.v4.addr[1], + mode->station_ip.v4.addr[2], + mode->station_ip.v4.addr[3]); + printf_debug ("PXE SUBNET MASK: %d.%d.%d.%d\n", //PXE子网掩码: + mode->subnet_mask.v4.addr[0], + mode->subnet_mask.v4.addr[1], + mode->subnet_mask.v4.addr[2], + mode->subnet_mask.v4.addr[3]); + } #endif - return; + /* TODO: Set The Station IP to the IP2 Config */ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//kern/misc.c + +union printf_arg +{ + /* Yes, type is also part of union as the moment we fill the value + we don't need to store its type anymore (when we'll need it, we'll + have format spec again. So save some space. */ + enum + { + INT, LONG, LONGLONG, + UNSIGNED_INT = 3, UNSIGNED_LONG, UNSIGNED_LONGLONG, + STRING + } type; + long long ll; +}; + +struct printf_args +{ + union printf_arg prealloc[32]; + union printf_arg *ptr; + grub_size_t count; +}; + +static int grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0, struct printf_args *args); +static void parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in); + +static inline void __attribute__ ((always_inline)) +write_char (char *str, grub_size_t *count, grub_size_t max_len, unsigned char ch) +{ + if (*count < max_len) + str[*count] = ch; + + (*count)++; +} + +static int +grub_isdigit (int c) +{ + return (c >= '0' && c <= '9'); +} + +static inline void +grub_reverse (char *str) +{ + char *p = str + grub_strlen (str) - 1; + + while (str < p) + { + char tmp; + + tmp = *str; + *str = *p; + *p = tmp; + str++; + p--; } } -void pxe_init (void); -void -pxe_init (void) +static inline char * +grub_lltoa (char *str, int c, unsigned long long n) +{ + unsigned base = ((c == 'x') || (c == 'X')) ? 16 : 10; + char *p; + + if ((long long) n < 0 && c == 'd') + { + n = (unsigned long long) (-((long long) n)); + *str++ = '-'; + } + + p = str; + + if (base == 16) + do + { + unsigned d = (unsigned) (n & 0xf); + *p++ = (d > 9) ? d + ((c == 'x') ? 'a' : 'A') - 10 : d + '0'; + } + while (n >>= 4); + else + /* BASE == 10 */ + do + { + grub_uint64_t m; +#if defined(__i386__) +// n = (unsigned long long)grub_divmod64 (~0ULL - n, 10, &m); + n = grub_divmod64 (n, 10, &m); +#else +// n = (unsigned long long)((~0ULL - n) / 10); + n = (unsigned long long)(n / 10); +#endif +// n = grub_divmod64 (n, 10, &m); + *p++ = m + '0'; + } + while (n); + + *p = 0; + grub_reverse (str); + return p; +} + +static void +free_printf_args (struct printf_args *args) { -// grub_efi_loaded_image_t *image = NULL; -// image = grub_efi_get_loaded_image (grub_efi_image_handle); //efi获得装载映像 - grub_efinet_findcards (); //查找卡 - grub_efi_net_config_real (image->device_handle, 0, 0); //实际网络配置 + if (args->ptr != args->prealloc) + grub_free (args->ptr); } +static int grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0, struct printf_args *args); +static int +grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0, + struct printf_args *args) +{ + char c; + grub_size_t n = 0; + grub_size_t count = 0; + const char *fmt; + fmt = fmt0; + + while ((c = *fmt++) != 0) + { + unsigned int format1 = 0; + unsigned int format2 = ~ 0U; + char zerofill = ' '; + char rightfill = 0; + grub_size_t curn; + + if (c != '%') + { + write_char (str, &count, max_len,c); + continue; + } + if (*fmt == '%') + { + write_char (str, &count, max_len, '%'); + fmt++; + continue; + } + + curn = n++; +rescan: + + if (*fmt =='-') + { + rightfill = 1; + fmt++; + } + /* Read formatting parameters. */ + if (grub_isdigit (*fmt)) + { + if (fmt[0] == '0') + zerofill = '0'; +// format1 = grub_strtoul (fmt, &fmt, 10); + safe_parse_maxint ((char**)&fmt, &hex); + format1 = hex; + } + if (*fmt == '.') + fmt++; + + if (grub_isdigit (*fmt)) +// format2 = grub_strtoul (fmt, &fmt, 10); + { + safe_parse_maxint ((char**)&fmt, &hex); + format2 = hex; + } + + if (*fmt == '*') + { + fmt++; + format1 = (unsigned long) args->ptr[curn].ll; + curn++; + } + + if (*fmt == '$') + { + curn = format1 - 1; + fmt++; + format1 = 0; + format2 = ~ 0U; + zerofill = ' '; + rightfill = 0; + goto rescan; + } + + c = *fmt++; + if (c == 'l') + c = *fmt++; + if (c == 'l') + c = *fmt++; + if (c == '%') + { + write_char (str, &count, max_len,c); + n--; + continue; + } + if (curn >= args->count) + continue; + + long long curarg = args->ptr[curn].ll; + switch (c) + { + case 'p': + write_char (str, &count, max_len, '0'); + write_char (str, &count, max_len, 'x'); + c = 'x'; + /* Fall through. */ + case 'x': + case 'X': + case 'u': + case 'd': + { + char tmp[32]; + const char *p = tmp; + grub_size_t len; + grub_size_t fill; + + len = grub_lltoa (tmp, c, curarg) - tmp; + fill = len < format1 ? format1 - len : 0; + if (! rightfill) + while (fill--) + write_char (str, &count, max_len, zerofill); + + while (*p) + write_char (str, &count, max_len, *p++); + + if (rightfill) + while (fill--) + write_char (str, &count, max_len, zerofill); + } + break; + case 'c': + write_char (str, &count, max_len,curarg & 0xff); + break; + case 'C': + { + grub_uint32_t code = curarg; + int shift; + unsigned mask; + + if (code <= 0x7f) + { + shift = 0; + mask = 0; + } + else if (code <= 0x7ff) + { + shift = 6; + mask = 0xc0; + } + else if (code <= 0xffff) + { + shift = 12; + mask = 0xe0; + } + else if (code <= 0x10ffff) + { + shift = 18; + mask = 0xf0; + } + else + { + code = '?'; + shift = 0; + mask = 0; + } + + write_char (str, &count, max_len,mask | (code >> shift)); + for (shift -= 6; shift >= 0; shift -= 6) + write_char (str, &count, max_len,0x80 | (0x3f & (code >> shift))); + } + break; + case 's': + { + grub_size_t len = 0; + grub_size_t fill; + const char *p = ((char *) (grub_addr_t) curarg) ? : "(null)"; + grub_size_t i; + + while (len < format2 && p[len]) + len++; + + fill = len < format1 ? format1 - len : 0; + + if (!rightfill) + while (fill--) + write_char (str, &count, max_len, zerofill); + + for (i = 0; i < len; i++) + write_char (str, &count, max_len,*p++); + + if (rightfill) + while (fill--) + write_char (str, &count, max_len, zerofill); + } + break; + default: + write_char (str, &count, max_len,c); + break; + } + } + if (count < max_len) + str[count] = '\0'; + else + str[max_len] = '\0'; + + return count; +} + +int grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list ap); +int +grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list ap) +{ + grub_size_t ret; + struct printf_args args; + + if (!n) + return 0; + + n--; + parse_printf_args (fmt, &args, ap); + ret = grub_vsnprintf_real (str, n, fmt, &args); + free_printf_args (&args); + + return ret < n ? ret : n; +} + +int grub_snprintf (char *str, grub_size_t n, const char *fmt, ...); +int +grub_snprintf (char *str, grub_size_t n, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start (ap, fmt); + ret = grub_vsnprintf (str, n, fmt, ap); + va_end (ap); + + return ret; +} + +#if 0 +//ASCII码转数字(源,返回结束地址,进制) 0/8/10/16 返回目的 +//如果源是十进制(31 33 00),base无论是0、10,都正确(d)。base是16,则错误(13)。 +//如果源是十六进制(30 78 31 33),base无论是0、16,都正确(13)。base是10,则错误(0)。 +unsigned long long grub_strtoull (const char * restrict str, const char ** const restrict end, int base); +unsigned long long +grub_strtoull (const char * restrict str, const char ** const restrict end, int base) +{ + unsigned long long num = 0; + int found = 0; + + //跳过空白 + // grub_isspace检查*str='\0' + while (grub_isspace (*str)) + str++; + + //如果未指定,请猜测基数。前缀“0x”表示16,前缀“0”表示8。 + if (str[0] == '0') + { + if (str[1] == 'x') + { + if (base == 0 || base == 16) + { + base = 16; //16进制 + str += 2; //移动到数值 + } + } + else if (base == 0 && str[1] >= '0' && str[1] <= '7') //8进制 + base = 8; + } + + if (base == 0) + base = 10; //10进制 + + while (*str) + { + unsigned long digit; + digit = grub_tolower (*str) - '0'; + if (digit > 9) + { + digit += '0' - 'a' + 10; + //digit<=9 检查以防止大于“9”但小于“a”的字符被读取为数字 + if (digit >= (unsigned long) base || digit <= 9) + break; + } + if (digit >= (unsigned long) base) + break; + + found = 1; + /* NUM * BASE + DIGIT > ~0ULL */ + num = num * base + digit; + str++; + } + + if (! found) + { + if (end) + *end = (char *) str; + printf_errinfo ("unrecognized number\n"); //无法识别的数字 + return 0; + } + + if (end) + *end = (char *) str; + + return num; +} + +unsigned long +grub_strtoul (const char * restrict str, const char ** const restrict end, int base) +{ + unsigned long long num; + + num = grub_strtoull (str, end, base); + + return (unsigned long) num; +} +#endif + +void * +grub_calloc (grub_size_t nmemb, grub_size_t size); +void * +grub_calloc (grub_size_t nmemb, grub_size_t size) //分配 +{ + void *ret; + grub_size_t sz = 0; + + if (grub_mul (nmemb, size, &sz)) + { + printf_errinfo ("overflow is detected"); + return NULL; + } + + ret = grub_memalign (0, sz); + if (!ret) + return NULL; + + grub_memset (ret, 0, sz); + return ret; +} + +static grub_err_t +parse_printf_arg_fmt (const char *fmt0, struct printf_args *args, + int fmt_check, grub_size_t max_args) +{ + const char *fmt; + char c; + grub_size_t n = 0; + + args->count = 0; + + COMPILE_TIME_ASSERT (sizeof (int) == sizeof (grub_uint32_t)); + COMPILE_TIME_ASSERT (sizeof (int) <= sizeof (long long)); + COMPILE_TIME_ASSERT (sizeof (long) <= sizeof (long long)); + COMPILE_TIME_ASSERT (sizeof (long long) == sizeof (void *) + || sizeof (int) == sizeof (void *)); + + fmt = fmt0; + while ((c = *fmt++) != 0) + { + if (c != '%') + continue; + + if (*fmt =='-') + fmt++; + + while (grub_isdigit (*fmt)) + fmt++; + + if (*fmt == '$') + { + if (fmt_check) + return printf_errinfo ("positional arguments are not supported"); + fmt++; + } + + if (*fmt =='-') + fmt++; + + while (grub_isdigit (*fmt)) + fmt++; + + if (*fmt =='.') + fmt++; + + while (grub_isdigit (*fmt)) + fmt++; + + if (*fmt == '*') + { + args->count++; + fmt++; + } + + c = *fmt++; + if (c == 'l') + c = *fmt++; + if (c == 'l') + c = *fmt++; + + switch (c) + { + case 'p': + case 'x': + case 'X': + case 'u': + case 'd': + case 'c': + case 'C': + case 's': + args->count++; + break; + case '%': + /* "%%" is the escape sequence to output "%". */ + break; + default: + if (fmt_check) + return printf_errinfo ("unexpected format"); + break; + } + } + + if (fmt_check && args->count > max_args) + return printf_errinfo ("too many arguments"); + + if (args->count <= ARRAY_SIZE (args->prealloc)) + args->ptr = args->prealloc; + else + { + args->ptr = grub_calloc (args->count, sizeof (args->ptr[0])); //分配 + if (!args->ptr) + { + if (fmt_check) + return 0; + + args->ptr = args->prealloc; + args->count = ARRAY_SIZE (args->prealloc); + } + } + + grub_memset (args->ptr, 0, args->count * sizeof (args->ptr[0])); + + fmt = fmt0; + n = 0; + while ((c = *fmt++) != 0) + { + int longfmt = 0; + grub_size_t curn; + const char *p; + + if (c != '%') + continue; + + curn = n++; + + if (*fmt =='-') + fmt++; + + p = fmt; + + while (grub_isdigit (*fmt)) + fmt++; + + if (*fmt == '$') + { +// curn = grub_strtoull (p, 0, 10) - 1; + safe_parse_maxint ((char**)&p, &hex); + curn = hex - 1; + fmt++; + } + + if (*fmt =='-') + fmt++; + + while (grub_isdigit (*fmt)) + fmt++; + + if (*fmt =='.') + fmt++; + + while (grub_isdigit (*fmt)) + fmt++; + + if (*fmt == '*') + { + fmt++; + args->ptr[curn].type = INT; + curn = n++; + } + + c = *fmt++; + if (c == '%') + { + n--; + continue; + } + if (c == 'l') + { + c = *fmt++; + longfmt = 1; + } + if (c == 'l') + { + c = *fmt++; + longfmt = 2; + } + if (curn >= args->count) + continue; + switch (c) + { + case 'x': + case 'X': + case 'u': + args->ptr[curn].type = UNSIGNED_INT + longfmt; + break; + case 'd': + args->ptr[curn].type = INT + longfmt; + break; + case 'p': + if (sizeof (void *) == sizeof (long long)) + args->ptr[curn].type = UNSIGNED_LONGLONG; + else + args->ptr[curn].type = UNSIGNED_INT; + break; + case 's': + args->ptr[curn].type = STRING; + break; + case 'C': + case 'c': + args->ptr[curn].type = INT; + break; + } + } + + return GRUB_ERR_NONE; +} + +static void +parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in) +{ + grub_size_t n; + + parse_printf_arg_fmt (fmt0, args, 0, 0); + + for (n = 0; n < args->count; n++) + switch (args->ptr[n].type) + { + case INT: + args->ptr[n].ll = va_arg (args_in, int); + break; + case LONG: + args->ptr[n].ll = va_arg (args_in, long); + break; + case UNSIGNED_INT: + args->ptr[n].ll = va_arg (args_in, unsigned int); + break; + case UNSIGNED_LONG: + args->ptr[n].ll = va_arg (args_in, unsigned long); + break; + case LONGLONG: + case UNSIGNED_LONGLONG: + args->ptr[n].ll = va_arg (args_in, long long); + break; + case STRING: + if (sizeof (void *) == sizeof (long long)) + args->ptr[n].ll = va_arg (args_in, long long); + else + args->ptr[n].ll = va_arg (args_in, unsigned int); + break; + } +} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//net/efi/net.c + +char *grub_strdup (const char *s); +char * +grub_strdup (const char *s) +{ + grub_size_t len; + char *p; + + if (!s) + return grub_zalloc (1); + + len = grub_strlen (s) + 1; + p = (char *) grub_malloc (len); + if (! p) + return 0; + + return grub_memcpy (p, s, len); +} + + +char *grub_strndup (const char *s, grub_size_t n); +char * +grub_strndup (const char *s, grub_size_t n) +{ + grub_size_t len; + char *p; + + len = grub_strlen (s); + if (len > n) + len = n; + p = (char *) grub_malloc (len + 1); + if (! p) + return 0; + + grub_memcpy (p, s, len); + p[len] = '\0'; + return p; +} + + +static void grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, char **path); +static void +grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + char **path) //网络配置实例 +{ + grub_efi_handle_t config_hnd; + struct grub_efi_net_device *netdev; + grub_efi_net_interface_t *inf; + + config_hnd = grub_efi_locate_device_path (&ip4_config_guid, grub_efi_get_device_path (hnd), NULL); //定位ip4设备路径 + if (!config_hnd) //失败 + return; + + for (netdev = net_devices; netdev; netdev = netdev->next) + if (netdev->handle == config_hnd) + break; + + if (!netdev) + return; + + if (!(inf = grub_efi_net_config_from_handle (hnd, netdev, device, path))) //从句柄配置网络 + return; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//net->efi->net.c + +char card_name[10]; +static void grub_efi_net_find_cards (void); +static void +grub_efi_net_find_cards (void) //网络查找卡 ok +{ + grub_efi_uintn_t num_handles; + grub_efi_handle_t *handles; + grub_efi_handle_t *handle; + int id; + + handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &ip4_config_guid, + 0, &num_handles); //定位ip4句柄 + if (!handles) + return; + + for (id = 0, handle = handles; num_handles--; handle++, id++) + { + grub_efi_device_path_t *dp; + grub_efi_ip4_config2_protocol_t *ip4_config; + grub_efi_ip6_config_protocol_t *ip6_config; + grub_efi_handle_t http_handle; + grub_efi_http_t *http; + grub_efi_handle_t dhcp4_handle; + grub_efi_dhcp4_protocol_t *dhcp4; + grub_efi_handle_t dhcp6_handle; + grub_efi_dhcp6_protocol_t *dhcp6; + struct grub_efi_net_device *d; + + dp = grub_efi_get_device_path (*handle); //获得设备路径 + if (!dp) + continue; + + ip4_config = grub_efi_open_protocol (*handle, &ip4_config_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); //打开ip4协议 + if (!ip4_config) //不支持ip4 + continue; + + ip6_config = grub_efi_open_protocol (*handle, &ip6_config_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); //打开ip6协议 + http_handle = grub_efi_service_binding (*handle, &http_service_binding_guid); //http服务绑定 + http = (http_handle) + ? grub_efi_open_protocol (http_handle, &http_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) //http服务绑定成功,打开http协议 + : NULL; + dhcp4_handle = grub_efi_service_binding (*handle, &dhcp4_service_binding_guid); //dhcp4服务绑定 + dhcp4 = (dhcp4_handle) + ? grub_efi_open_protocol (dhcp4_handle, &dhcp4_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) //dhcp4服务绑定成功,打开dhcp4协议 + : NULL; + dhcp6_handle = grub_efi_service_binding (*handle, &dhcp6_service_binding_guid); //dhcp6服务绑定 + dhcp6 = (dhcp6_handle) + ? grub_efi_open_protocol (dhcp6_handle, &dhcp6_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) //dhcp6服务绑定成功,打开dhcp6协议 + : NULL; + + d = grub_malloc (sizeof (*d)); //分配内存 + if (!d) //如果失败 + { + grub_free (handles); //释放 + while (net_devices) + { + d = net_devices->next; + grub_free (net_devices); + net_devices = d; + } + return; + } + //创建网络设备 + d->handle = *handle; //句柄 e5983a0 + d->ip4_config = ip4_config; //ip4配置 f54f578 + d->ip6_config = ip6_config; //ip6配置 f533f70 + d->http_handle = http_handle; //http句柄 f4fbd18 + d->http = http; //http入口 f4f2020 + d->dhcp4_handle = dhcp4_handle; //dhcp4句柄 f4f6e18 + d->dhcp4 = dhcp4; //dhcp4入口 f4f5420 + d->dhcp6_handle = dhcp6_handle; //dhcp6句柄 f50f798 + d->dhcp6 = dhcp6; //dhcp6入口 f4f5d40 + d->next = net_devices; //下一个 0 + grub_sprintf (card_name,"efinet%d", id); + d->card_name = card_name; //网卡名称 efinet0 + d->net_interfaces = NULL; //网络接口 + net_devices = d; //网络设备入口 e5982a0 + } + + grub_efi_net_add_pxebc_to_cards (); //将pxebc添加到卡中 + grub_free (handles); + set_ip_policy_to_static (); //将ip策略设置为静态 +} + +static void +grub_efi_net_add_pxebc_to_cards (void) //将pxebc添加到卡中 ok +{ + grub_efi_uintn_t num_handles; + grub_efi_handle_t *handles; + grub_efi_handle_t *handle; + int is_ip6_x; + + handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &pxe_io_guid, + 0, &num_handles); //定位pxe句柄 + if (!handles) //失败 + return; + + for (handle = handles; num_handles--; handle++) + { + grub_efi_device_path_t *dp, *ddp, *ldp; + struct grub_efi_net_device *d; + + + dp = grub_efi_get_device_path (*handle); //获得设备路径 + if (!dp) //失败继续 + continue; + + ddp = grub_efi_duplicate_device_path (dp); //重复设备路径 + ldp = grub_efi_find_last_device_path (ddp); //查找设备最后路径 + + if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE //消息传递设备路径类型 3 + && ldp->subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) //IPV4设备路径子类型 12 + { + is_ip6_x = 0; //不是ip6 + ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; + ldp->length = sizeof (*ldp); + } + else if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE //消息传递设备路径类型 3 + && ldp->subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) //IPV6设备路径子类型 13 + { + is_ip6_x = 1; //是ip6 + ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; + ldp->length = sizeof (*ldp); + } + + for (d = net_devices; d; d = d->next) + if (grub_efi_compare_device_paths (ddp, grub_efi_get_device_path (d->handle)) == 0) //比较设备路径,相等退出 + break; + + if (!d) //失败 + { + grub_free (ddp); + continue; + } + + pxe_entry = 0; + pxe_entry = grub_efi_open_protocol (*handle, &pxe_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); //打开pxe协议 + if (!pxe_entry) //失败 + { + grub_free (ddp); + continue; + } + + struct grub_efi_pxe_mode *pxe_mode; + pxe_mode = pxe_entry->mode; //模式 + discover_reply = (BOOTPLAYER *)((char *)&pxe_mode->dhcp_ack.dhcpv4); //引导播放器 + + pxe_sip = discover_reply->sip; //服务器IP + + if (is_ip6_x) //是ip6 + { + d->ip6_pxe_handle = *handle; //ip6_pxe句柄 + d->ip6_pxe = pxe_entry; //pxe入口 + } + else + { + d->ip4_pxe_handle = *handle; //ip4_pxe句柄 + d->ip4_pxe = pxe_entry; //pxe入口 + } + + grub_free (ddp); + } + + grub_free (handles); +} + +static void +set_ip_policy_to_static (void) //将ip策略设置为静态 ok +{ + struct grub_efi_net_device *dev; + + for (dev = net_devices; dev; dev = dev->next) + { + grub_efi_ip4_config2_policy_t ip4_policy = GRUB_EFI_IP4_CONFIG2_POLICY_STATIC; //静态 + + if (efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, + GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, //策略 + sizeof (ip4_policy), &ip4_policy) != GRUB_EFI_SUCCESS) + printf_debug ("could not set GRUB_EFI_IP4_CONFIG2_POLICY_STATIC on dev `%s'\n", dev->card_name); //无法在dev上设置GRUBEFI_IP4_CONFIG2_POLICY_STATIC + + if (dev->ip6_config) + { + grub_efi_ip6_config_policy_t ip6_policy = GRUB_EFI_IP6_CONFIG_POLICY_MANUAL; + + if (efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, + GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, + sizeof (ip6_policy), &ip6_policy) != GRUB_EFI_SUCCESS) + printf_debug ("could not set GRUB_EFI_IP6_CONFIG_POLICY_MANUAL on dev `%s'\n", dev->card_name); //无法在dev上设置GRUB_EFI_IP6_CONFIG_POLICY_MANUAL + } + } +} + +static grub_efi_handle_t +grub_efi_service_binding (grub_efi_handle_t dev, grub_efi_guid_t *service_binding_guid) //dev服务绑定 +{ + grub_efi_service_binding_t *service; + grub_efi_status_t status; + grub_efi_handle_t child_dev = NULL; + + service = grub_efi_open_protocol (dev, service_binding_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); //打开服务绑定协议 + if (!service) //失败 + { + printf_errinfo ("couldn't open efi service binding protocol\n"); //无法打开efi服务绑定协议 + return NULL; + } + + status = efi_call_2 (service->create_child, service, &child_dev); //服务->创建子项 + if (status != GRUB_EFI_SUCCESS) //失败 + { + printf_errinfo ("Failed to create child device of http service\n"); //无法创建http服务的子设备 + return NULL; + } + + return child_dev; //子设备 +} + +static int +grub_efi_net_parse_address (const char *address, + grub_efi_ip4_config2_manual_address_t *ip4, + grub_efi_ip6_config_manual_address_t *ip6, + int *has_cidr) //网络解析地址 +{ + const char *rest; + + if (grub_efi_string_to_ip4_address (address, &ip4->address, &rest)) //字符串到ip4地址 + { + is_ip6 = 0; + if (*rest == '/') + { + grub_uint32_t subnet_mask_size; + +// subnet_mask_size = grub_strtoul (rest + 1, &rest, 0); + safe_parse_maxint ((char**)&rest + 1, &hex); + subnet_mask_size = hex; + + if (!errnum && subnet_mask_size <= 32 && *rest == 0) + { + grub_uint32_t subnet_mask; + + subnet_mask = grub_cpu_to_be32 ((0xffffffffU << (32 - subnet_mask_size))); + grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); + if (has_cidr) + *has_cidr = 1; + return 0; + } + } + else if (*rest == 0) + { + grub_uint32_t subnet_mask = 0xffffffffU; + grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); + + if (has_cidr) + *has_cidr = 0; + return 0; + } + } + else if (grub_efi_string_to_ip6_address (address, &ip6->address, &rest)) + { + is_ip6 = 1; + if (*rest == '/') + { + grub_efi_uint8_t prefix_length; + +// prefix_length = grub_strtoul (rest + 1, &rest, 0); + safe_parse_maxint ((char**)&rest + 1, &hex); + prefix_length = hex; + if (!errnum && prefix_length <= 128 && *rest == 0) + { + ip6->prefix_length = prefix_length; + ip6->is_anycast = 0; + if (has_cidr) + *has_cidr = 1; + return 0; + } + } + else if (*rest == 0) + { + ip6->prefix_length = 128; + ip6->is_anycast = 0; + if (has_cidr) + *has_cidr = 0; + return 1; + } + } + + printf_errinfo ("unrecognised network address %s\n", address); + return 1; +} + +static grub_efi_net_interface_t * +match_route (const char *server) //匹配路线 +{ + grub_err_t err; + grub_efi_ip4_config2_manual_address_t ip4; + grub_efi_ip6_config_manual_address_t ip6; + grub_efi_net_interface_t *inf; + + err = grub_efi_net_parse_address (server, &ip4, &ip6, 0); + if (err) + return NULL; + + if (is_ip6) + { + struct grub_efi_net_device *dev; + grub_efi_net_ip_address_t addr; + + grub_memcpy (addr.ip6, ip6.address, sizeof(ip6.address)); + + for (dev = net_devices; dev; dev = dev->next) + if ((inf = efi_net_ip6_config->best_interface (dev, &addr))) +// if ((inf = grub_efi_ip6_interface_match (dev, &addr))) + return inf; + } + else + { + struct grub_efi_net_device *dev; + grub_efi_net_ip_address_t addr; + + grub_memcpy (addr.ip4, ip4.address, sizeof(ip4.address)); + for (dev = net_devices; dev; dev = dev->next) + { + if ((inf = efi_net_ip4_config->best_interface (dev, &addr))) //ip4接口匹配 + { + return inf; + } + } + } + + return 0; +} + +static grub_efi_handle_t +grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, + grub_efi_device_path_t **r_device_path) //定位设备路径 ok +{ + grub_efi_handle_t handle; + grub_efi_status_t status; + + status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path, + protocol, &device_path, &handle); + + if (status != GRUB_EFI_SUCCESS) + return 0; + + if (r_device_path) + *r_device_path = device_path; + + return handle; +} + +static void pxe_get_boot_location (const struct grub_net_bootp_packet *bp, char **device, char **path, int is_default); +static void +pxe_get_boot_location (const struct grub_net_bootp_packet *bp, + char **device, + char **path, + int is_default) //pxe获得引导位置 ok +{ +// char *server = grub_xasprintf ("%d.%d.%d.%d", //???? + char server[24]; + grub_sprintf (server, "%d.%d.%d.%d", + ((grub_uint8_t *) &bp->server_ip)[0], + ((grub_uint8_t *) &bp->server_ip)[1], + ((grub_uint8_t *) &bp->server_ip)[2], + ((grub_uint8_t *) &bp->server_ip)[3]); + +// *device = grub_xasprintf ("tftp,%s", server); + char str[24]; + grub_sprintf (str, "tftp,%s", server); + *device = str; + *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file)); + if (*path) + { + char *slash; + slash = grub_strrchr (*path, '/'); + if (slash) + *slash = 0; + else + **path = 0; + } + + if (is_default) + default_server = server; + else + grub_free (server); +} + +grub_efi_net_interface_t * grub_efi_net_create_interface (struct grub_efi_net_device *dev, const char *interface_name, grub_efi_net_ip_manual_address_t *net_ip, int has_subnet); +grub_efi_net_interface_t * +grub_efi_net_create_interface (struct grub_efi_net_device *dev, + const char *interface_name, + grub_efi_net_ip_manual_address_t *net_ip, + int has_subnet) //网络创建接口 ok +{ + grub_efi_net_interface_t *inf; + + for (inf = dev->net_interfaces; inf; inf = inf->next) + { + if (inf->prefer_ip6 == net_ip->is_ip6) + break; + } + + if (!inf) + { + inf = grub_malloc (sizeof(*inf)); + inf->name = grub_strdup (interface_name); + inf->prefer_ip6 = net_ip->is_ip6; + inf->dev = dev; + inf->next = dev->net_interfaces; + inf->ip_config = (net_ip->is_ip6) ? efi_net_ip6_config : efi_net_ip4_config ; + dev->net_interfaces = inf; + } + else + { + grub_free (inf->name); + inf->name = grub_strdup (interface_name); + } + + if (!efi_net_interface_set_address (inf, net_ip, has_subnet)) + { + printf_errinfo ("Set Address Failed\n"); + return NULL; + } + + return inf; +} + +struct grub_net_dhcp6_packet + { + grub_uint32_t message_type:8; + grub_uint32_t transaction_id:24; + grub_uint8_t dhcp_options[0]; + } GRUB_PACKED; + +struct grub_net_dhcp6_option { + grub_uint16_t code; + grub_uint16_t len; + grub_uint8_t data[0]; +} GRUB_PACKED; + +enum + { + GRUB_NET_DHCP6_OPTION_CLIENTID = 1, + GRUB_NET_DHCP6_OPTION_SERVERID = 2, + GRUB_NET_DHCP6_OPTION_IA_NA = 3, + GRUB_NET_DHCP6_OPTION_IAADDR = 5, + GRUB_NET_DHCP6_OPTION_ORO = 6, + GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8, + GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23, + GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59 + }; + +static int +url_parse_fields (const char *url, char **proto, char **host, char **path) //url解析字段 +{ + const char *p, *ps; + grub_size_t l; + + *proto = *host = *path = NULL; + ps = p = url; + + while ((p = grub_strchr (p, ':'))) + { + if (grub_strlen (p) < sizeof ("://") - 1) + break; + if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) + { + l = p - ps; + *proto = grub_malloc (l + 1); + if (!*proto) + return 0; + + grub_memcpy (*proto, ps, l); + (*proto)[l] = '\0'; + p += sizeof ("://") - 1; + break; + } + ++p; + } + + if (!*proto) + { + printf_errinfo ("url: %s is not valid, protocol not found\n", url); + return 0; + } + + ps = p; + p = grub_strchr (p, '/'); + + if (!p) + { + printf_errinfo ("url: %s is not valid, host/path not found\n", url); + grub_free (*proto); + *proto = NULL; + return 0; + } + + l = p - ps; + + if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') + { + *host = grub_malloc (l - 1); + if (!*host) + { + grub_free (*proto); + *proto = NULL; + return 0; + } + grub_memcpy (*host, ps + 1, l - 2); + (*host)[l - 2] = 0; + } + else + { + *host = grub_malloc (l + 1); + if (!*host) + { + grub_free (*proto); + *proto = NULL; + return 0; + } + grub_memcpy (*host, ps, l); + (*host)[l] = 0; + } + + *path = grub_strdup (p); + if (!*path) + { + grub_free (*host); + grub_free (*proto); + *host = NULL; + *proto = NULL; + return 0; + } + return 1; +} + +static void +url_get_boot_location (const char *url, char **device, char **path, int is_default) //url获得引导位置 +{ + char *protocol, *server, *file; + char *slash; + + if (!url_parse_fields (url, &protocol, &server, &file)) + return; + + if ((slash = grub_strrchr (file, '/'))) + *slash = 0; + else + *file = 0; + +// *device = grub_xasprintf ("%s,%s", protocol, server); + char str[24]; + grub_sprintf (str, "%s,%s", protocol, server); + *device = str; + *path = grub_strdup(file); + + if (is_default) + default_server = server; + else + grub_free (server); + + grub_free (protocol); + grub_free (file); +} + +static void +pxe_get_boot_location_v6 (const struct grub_net_dhcp6_packet *dp, + grub_size_t dhcp_size, + char **device, + char **path) //pxe获得引导位置v6 +{ + + struct grub_net_dhcp6_option *dhcp_opt; + grub_size_t dhcp_remain_size; + *device = *path = 0; + + if (dhcp_size < sizeof (*dp)) + { + printf_errinfo ("DHCPv6 packet size too small\n"); + return; + } + + dhcp_remain_size = dhcp_size - sizeof (*dp); + dhcp_opt = (struct grub_net_dhcp6_option *)dp->dhcp_options; + + while (dhcp_remain_size) + { + grub_uint16_t code = grub_be_to_cpu16 (dhcp_opt->code); + grub_uint16_t len = grub_be_to_cpu16 (dhcp_opt->len); + grub_uint16_t option_size = sizeof (*dhcp_opt) + len; + + if (dhcp_remain_size < option_size || code == 0) + break; + + if (code == GRUB_NET_DHCP6_OPTION_BOOTFILE_URL) + { + char *url = grub_malloc (len + 1); + + grub_memcpy (url, dhcp_opt->data, len); + url[len] = 0; + + url_get_boot_location ((const char *)url, device, path, 1); //url获得引导位置 + grub_free (url); + break; + } + + dhcp_remain_size -= option_size; + dhcp_opt = (struct grub_net_dhcp6_option *)((grub_uint8_t *)dhcp_opt + option_size); + } +} + + +static grub_efi_net_interface_t * +grub_efi_net_config_from_handle (grub_efi_handle_t *hnd, + struct grub_efi_net_device *netdev, + char **device, + char **path) //从句柄配置网络 ok +{ + if (hnd == netdev->ip4_pxe_handle) + pxe_entry = netdev->ip4_pxe; + else if (hnd == netdev->ip6_pxe_handle) + pxe_entry = netdev->ip6_pxe; + + if (pxe_entry->mode->using_ipv6) + { + grub_efi_net_ip_manual_address_t net_ip; + + pxe_get_boot_location_v6 ((const struct grub_net_dhcp6_packet *) &pxe_entry->mode->dhcp_ack, sizeof (pxe_entry->mode->dhcp_ack), device, path); //pxe获得引导位置v6 + + grub_memcpy (net_ip.ip6.address, pxe_entry->mode->station_ip.v6, sizeof(net_ip.ip6.address)); + net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; + net_ip.ip6.is_anycast = 0; + net_ip.is_ip6 = 1; + return (grub_efi_net_create_interface (netdev, netdev->card_name, &net_ip, 1)); + } + else + { + grub_efi_net_ip_manual_address_t net_ip; + + pxe_get_boot_location ((const struct grub_net_bootp_packet *) &pxe_entry->mode->dhcp_ack, device, path, 1); //pxe获得引导位置 ok + + grub_memcpy (net_ip.ip4.address, pxe_entry->mode->station_ip.v4, sizeof (net_ip.ip4.address)); + grub_memcpy (net_ip.ip4.subnet_mask, pxe_entry->mode->subnet_mask.v4, sizeof (net_ip.ip4.subnet_mask)); + net_ip.is_ip6 = 0; + + return (grub_efi_net_create_interface (netdev,netdev->card_name, &net_ip, 1)); //网络创建接口 ok + } + return 0; +} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//net/efi/ip4_config.c +char * +grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address) //硬件地址到字符串 +{ + char *hw_addr, *p; + grub_size_t sz, s, i; + + if (grub_mul (hw_address_size, sizeof ("XX:") - 1, &sz) || + grub_add (sz, 1, &sz)) + return NULL; + + hw_addr = grub_malloc (sz); + if (!hw_addr) + return NULL; + + p = hw_addr; + s = sz; + for (i = 0; i < hw_address_size; i++) + { + grub_snprintf (p, sz, "%02x:", hw_address[i]); + p += sizeof ("XX:") - 1; + s -= sizeof ("XX:") - 1; + } + + hw_addr[sz - 2] = '\0'; + return hw_addr; +} + +char * +grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address) //ip4地址到字符串 +{ + char *addr; + + addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX")); + if (!addr) + return NULL; + + /* FIXME: Use grub_xasprintf ? */ + grub_snprintf (addr, + sizeof ("XXX.XXX.XXX.XXX"), + "%u.%u.%u.%u", + (*address)[0], + (*address)[1], + (*address)[2], + (*address)[3]); + + return addr; +} + +int +grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) //字符串到ip4地址 +{ + grub_uint32_t newip = 0; + int i; + const char *ptr = val; + + for (i = 0; i < 4; i++) + { + unsigned long t; +// t = grub_strtoul (ptr, &ptr, 0); + safe_parse_maxint ((char**)&ptr, &hex); + t = hex; + + if (errnum) + { + errnum = GRUB_ERR_NONE; + return 0; + } + if (*ptr != '.' && i == 0) + { + /* XXX: t is in host byte order */ + newip = t; + break; + } + if (t & ~0xff) + return 0; + newip <<= 8; + newip |= t; + if (i != 3 && *ptr != '.') + return 0; + ptr++; + } + + newip = grub_cpu_to_be32 (newip); + grub_memcpy (address, &newip, sizeof(*address)); + if (rest) + *rest = (ptr - 1); + return 1; +} + +//被grub_efi_ip4_interface_name,grub_efi_ip4_interface_hw_address,grub_efi_ip4_interface_route_table,grub_efi_ip4_interface_match调用 +static grub_efi_ip4_config2_interface_info_t * +efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config) //ip4配置接口信息 +{ + grub_efi_uintn_t sz; + grub_efi_status_t status; + grub_efi_ip4_config2_interface_info_t *interface_info; + + sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); + interface_info = grub_malloc (sz); + if (!interface_info) + return NULL; + + status = efi_call_4 (ip4_config->get_data, ip4_config, + GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, + &sz, interface_info); + + if (status == GRUB_EFI_BUFFER_TOO_SMALL) + { + grub_free (interface_info); + interface_info = grub_malloc (sz); + status = efi_call_4 (ip4_config->get_data, ip4_config, + GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, + &sz, interface_info); + } + + if (status != GRUB_EFI_SUCCESS) + { + grub_free (interface_info); + return NULL; + } + + return interface_info; +} + +static grub_efi_ip4_config2_manual_address_t * +efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) //ip4配置手动地址 +{ + grub_efi_uintn_t sz; + grub_efi_status_t status; + grub_efi_ip4_config2_manual_address_t *manual_address; + + sz = sizeof (*manual_address); + manual_address = grub_malloc (sz); + if (!manual_address) + return NULL; + + status = efi_call_4 (ip4_config->get_data, ip4_config, + GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, + &sz, manual_address); + + if (status != GRUB_EFI_SUCCESS) + { + grub_free (manual_address); + return NULL; + } + + return manual_address; +} + +char * +grub_efi_ip4_interface_name (struct grub_efi_net_device *dev) //ip4接口名称 +{ + grub_efi_ip4_config2_interface_info_t *interface_info; + char *name; + + interface_info = efi_ip4_config_interface_info (dev->ip4_config); //ip4配置接口信息 + + if (!interface_info) + return NULL; + + name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE + * GRUB_MAX_UTF8_PER_UTF16 + 1); + *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, + GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; + grub_free (interface_info); + return name; +} + +static char * +grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev) //ip4接口硬件地址 +{ + grub_efi_ip4_config2_interface_info_t *interface_info; + char *hw_addr; + + interface_info = efi_ip4_config_interface_info (dev->ip4_config); //ip4配置接口信息 + + if (!interface_info) + return NULL; + + hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); //硬件地址到字符串 + grub_free (interface_info); + + return hw_addr; +} + +static char * +grub_efi_ip4_interface_address (struct grub_efi_net_device *dev) //ip4接口地址 +{ + grub_efi_ip4_config2_manual_address_t *manual_address; + char *addr; + + manual_address = efi_ip4_config_manual_address (dev->ip4_config); //ip4配置手动地址 + + if (!manual_address) + return NULL; + + addr = grub_efi_ip4_address_to_string (&manual_address->address); //ip4地址到字符串 + grub_free (manual_address); + return addr; +} + +static int +address_mask_size (grub_efi_ipv4_address_t *address) //地址掩码尺寸 +{ + grub_uint8_t i; + grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address)); + + if (u32_addr == 0) + return 0; + + for (i = 0; i < 32 ; ++i) + { + if (u32_addr == ((0xffffffff >> i) << i)) + return (32 - i); + } + + return -1; +} + +static char ** +grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) //ip4接口路由表 +{ + grub_efi_ip4_config2_interface_info_t *interface_info; + char **ret; + int id; + grub_size_t i, nmemb; + + interface_info = efi_ip4_config_interface_info (dev->ip4_config); //ip4配置接口信息 + if (!interface_info) + return NULL; + + if (grub_add (interface_info->route_table_size, 1, &nmemb)) + { + errnum = GRUB_ERR_OUT_OF_RANGE; + return NULL; + } + + ret = grub_calloc (nmemb, sizeof (*ret)); + if (!ret) + { + grub_free (interface_info); + return NULL; + } + + id = 0; + for (i = 0; i < interface_info->route_table_size; i++) + { + char *subnet, *gateway, *mask; + grub_uint32_t u32_subnet, u32_gateway; + int mask_size; + grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; + grub_efi_net_interface_t *inf; + char *interface_name = NULL; + + for (inf = dev->net_interfaces; inf; inf = inf->next) + if (!inf->prefer_ip6) + interface_name = inf->name; + + u32_gateway = grub_get_unaligned32 (&route_table->gateway_address); + gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address); //ip4地址到字符串 + u32_subnet = grub_get_unaligned32 (&route_table->subnet_address); + subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address); //ip4地址到字符串 + mask_size = address_mask_size (&route_table->subnet_mask); //地址掩码尺寸 + mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask); //ip4地址到字符串 + if (u32_subnet && !u32_gateway && interface_name) +// ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name); + grub_sprintf (ret[id++], "%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name); + else if (u32_subnet && u32_gateway) +// ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); + grub_sprintf (ret[id++], "%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); + else if (!u32_subnet && u32_gateway) +// ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); + grub_sprintf (ret[id++], "%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); + grub_free (subnet); + grub_free (gateway); + grub_free (mask); + } + + ret[id] = NULL; + grub_free (interface_info); + return ret; +} + +static grub_efi_net_interface_t * +grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) //ip4接口匹配 +{ + grub_efi_ip4_config2_interface_info_t *interface_info; + grub_efi_net_interface_t *inf; + int i; + grub_efi_ipv4_address_t *address = &ip_address->ip4; + + interface_info = efi_ip4_config_interface_info (dev->ip4_config); //ip4配置接口信息 + if (!interface_info) + return NULL; + + for (i = 0; i < (int)interface_info->route_table_size; i++) + { + grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; + grub_uint32_t u32_address, u32_mask, u32_subnet; + + u32_address = grub_get_unaligned32 (address); + u32_subnet = grub_get_unaligned32 (route_table->subnet_address); + u32_mask = grub_get_unaligned32 (route_table->subnet_mask); + /* SKIP Default GATEWAY */ + if (!u32_subnet && !u32_mask) + continue; + + if ((u32_address & u32_mask) == u32_subnet) + { + for (inf = dev->net_interfaces; inf; inf = inf->next) + if (!inf->prefer_ip6) + { + grub_free (interface_info); + return inf; + } + } + } + + grub_free (interface_info); + return NULL; +} + +static int +grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev, + grub_efi_net_ip_manual_address_t *net_ip, + int with_subnet) //接口设置手动地址 +{ + grub_efi_status_t status; + grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4; + + if (!with_subnet) + { + grub_efi_ip4_config2_manual_address_t *manual_address = + efi_ip4_config_manual_address (dev->ip4_config); //ip4配置手动地址 + + if (manual_address) + { + grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask)); + grub_free (manual_address); + } + else + { + /* XXX: */ + address->subnet_mask[0] = 0xff; + address->subnet_mask[1] = 0xff; + address->subnet_mask[2] = 0xff; + address->subnet_mask[3] = 0; + } + } + + status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, + GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, + sizeof(*address), address); + if (status != GRUB_EFI_SUCCESS) + return 0; + + return 1; +} + +static int +grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev, + grub_efi_net_ip_address_t *address) //ip4接口设置网关 +{ + grub_efi_status_t status; + + status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, + GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, + sizeof (address->ip4), &address->ip4); + + if (status != GRUB_EFI_SUCCESS) + return 0; + return 1; +} + +/* FIXME: Multiple DNS */ +static int +grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev, + grub_efi_net_ip_address_t *address) //ip4接口设置dns +{ + grub_efi_status_t status; + + status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, + GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, + sizeof (address->ip4), &address->ip4); + + if (status != GRUB_EFI_SUCCESS) + return 0; + return 1; +} + +grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t) + { + .get_hw_address = grub_efi_ip4_interface_hw_address, //获得_ip4接口硬件地址 + .get_address = grub_efi_ip4_interface_address, //获得_ip4接口地址 + .get_route_table = grub_efi_ip4_interface_route_table, //获得_ip4路由表 + .best_interface = grub_efi_ip4_interface_match, //最佳接口_ip4接口匹配 + .set_address = grub_efi_ip4_interface_set_manual_address, //设置_地址 + .set_gateway = grub_efi_ip4_interface_set_gateway, //设置_网关 + .set_dns = grub_efi_ip4_interface_set_dns //设置_dns + }; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//net/efi/ip6_config.c +char * +grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address) //ip6地址到字符串 +{ + char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")); + char *p; + int i; + int squash; + + if (!str) + return NULL; + + p = str; + squash = 0; + for (i = 0; i < 8; ++i) + { + grub_uint16_t addr; + + if (i == 7) + squash = 2; + + addr = grub_get_unaligned16 (address->addr + i * 2); + if (grub_be_to_cpu16 (addr)) + { + char buf[sizeof ("XXXX")]; + if (i > 0) + *p++ = ':'; + grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr)); + grub_strcpy (p, buf); + p += grub_strlen (buf); + + if (squash == 1) + squash = 2; + } + else + { + if (squash == 0) + { + *p++ = ':'; + squash = 1; + } + else if (squash == 2) + { + *p++ = ':'; + *p++ = '0'; + } + } + } + *p = '\0'; + + return str; +} + +int +grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest) //字符串到ip6地址 +{ + grub_uint16_t newip[8]; + const char *ptr = val; + int word, quaddot = -1; + int bracketed = 0; + + if (ptr[0] == '[') + { + bracketed = 1; + ptr++; + } + + if (ptr[0] == ':' && ptr[1] != ':') + return 0; + if (ptr[0] == ':') + ptr++; + + for (word = 0; word < 8; word++) + { + unsigned long t; + if (*ptr == ':') + { + quaddot = word; + word--; + ptr++; + continue; + } +// t = grub_strtoul (ptr, &ptr, 16); + safe_parse_maxint ((char**)&ptr, &hex); + t = hex; + if (t & ~0xffff) + return 0; + newip[word] = grub_cpu_to_be16 (t); + + if (*ptr != ':') + break; + ptr++; + } + + if (quaddot == -1 && word < 7) + return 0; + if (quaddot != -1) + { + grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], + (word - quaddot + 1) * sizeof (newip[0])); + grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); + } + grub_memcpy (address, newip, 16); + if (bracketed && *ptr == ']') + { + ptr++; + } + if (rest) + *rest = ptr; + + return 1; +} + +static grub_efi_ip6_config_interface_info_t * +efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config) //ip6配置接口信息 +{ + grub_efi_uintn_t sz; + grub_efi_status_t status; + grub_efi_ip6_config_interface_info_t *interface_info; + + sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); + interface_info = grub_malloc (sz); + + status = efi_call_4 (ip6_config->get_data, ip6_config, + GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, + &sz, interface_info); + + if (status == GRUB_EFI_BUFFER_TOO_SMALL) + { + grub_free (interface_info); + interface_info = grub_malloc (sz); + status = efi_call_4 (ip6_config->get_data, ip6_config, + GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, + &sz, interface_info); + } + + if (status != GRUB_EFI_SUCCESS) + { + grub_free (interface_info); + return NULL; + } + + return interface_info; +} + +static grub_efi_ip6_config_manual_address_t * +efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) //ip6配置手动地址 +{ + grub_efi_uintn_t sz; + grub_efi_status_t status; + grub_efi_ip6_config_manual_address_t *manual_address; + + sz = sizeof (*manual_address); + manual_address = grub_malloc (sz); + if (!manual_address) + return NULL; + + status = efi_call_4 (ip6_config->get_data, ip6_config, + GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, + &sz, manual_address); + + if (status != GRUB_EFI_SUCCESS) + { + grub_free (manual_address); + return NULL; + } + + return manual_address; +} + +char * +grub_efi_ip6_interface_name (struct grub_efi_net_device *dev) //ip6接口名称 +{ + grub_efi_ip6_config_interface_info_t *interface_info; + char *name; + + interface_info = efi_ip6_config_interface_info (dev->ip6_config); //ip6配置接口信息 + + if (!interface_info) + return NULL; + + name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE + * GRUB_MAX_UTF8_PER_UTF16 + 1); + *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, + GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; + grub_free (interface_info); + return name; +} + +static char * +grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev) //ip6接口硬件地址 +{ + grub_efi_ip6_config_interface_info_t *interface_info; + char *hw_addr; + + interface_info = efi_ip6_config_interface_info (dev->ip6_config); //ip6配置接口信息 + + if (!interface_info) + return NULL; + + hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); + grub_free (interface_info); + + return hw_addr; +} + +static char * +grub_efi_ip6_interface_address (struct grub_efi_net_device *dev) //ip6接口地址 +{ + grub_efi_ip6_config_manual_address_t *manual_address; + char *addr; + + manual_address = efi_ip6_config_manual_address (dev->ip6_config); //ip6配置手动地址 + + if (!manual_address) + return NULL; + + addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address); //ip6地址到字符串 + grub_free (manual_address); + return addr; +} + +static char ** +grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) //ip6接口路由表 +{ + grub_efi_ip6_config_interface_info_t *interface_info; + char **ret; + int id; + grub_size_t i, nmemb; + + interface_info = efi_ip6_config_interface_info (dev->ip6_config); //ip6配置接口信息 + if (!interface_info) + return NULL; + + if (grub_add (interface_info->route_count, 1, &nmemb)) + { + errnum = GRUB_ERR_OUT_OF_RANGE; + return NULL; + } + + ret = grub_calloc (nmemb, sizeof (*ret)); + if (!ret) + { + grub_free (interface_info); + return NULL; + } + + id = 0; + for (i = 0; i < interface_info->route_count ; i++) + { + char *gateway, *destination; + grub_uint64_t u64_gateway[2]; + grub_uint64_t u64_destination[2]; + grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; + grub_efi_net_interface_t *inf; + char *interface_name = NULL; + + gateway = grub_efi_ip6_address_to_string (&route_table->gateway); //ip6地址到字符串 + destination = grub_efi_ip6_address_to_string (&route_table->destination); //ip6地址到字符串 + + u64_gateway[0] = grub_get_unaligned64 (route_table->gateway.addr); + u64_gateway[1] = grub_get_unaligned64 (route_table->gateway.addr + 8); + u64_destination[0] = grub_get_unaligned64 (route_table->destination.addr); + u64_destination[1] = grub_get_unaligned64 (route_table->destination.addr + 8); + + for (inf = dev->net_interfaces; inf; inf = inf->next) + if (inf->prefer_ip6) + interface_name = inf->name; + + if ((!u64_gateway[0] && !u64_gateway[1]) + && (u64_destination[0] || u64_destination[1])) + { + if (interface_name) + { + if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL) + && (!u64_destination[1]) + && (route_table->prefix_length == 64)) +// ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); + grub_sprintf (ret[id++], "%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); + else +// ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); + grub_sprintf (ret[id++], "%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); + } + } + else if ((u64_gateway[0] || u64_gateway[1]) + && (u64_destination[0] || u64_destination[1])) +// ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); + grub_sprintf (ret[id++], "%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); + else if ((u64_gateway[0] || u64_gateway[1]) + && (!u64_destination[0] && !u64_destination[1])) +// ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); + grub_sprintf (ret[id++], "%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); + + grub_free (gateway); + grub_free (destination); + } + + ret[id] = NULL; + grub_free (interface_info); + return ret; +} + +static grub_efi_net_interface_t * +grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) //ip6接口匹配 +{ + grub_efi_ip6_config_interface_info_t *interface_info; + grub_efi_net_interface_t *inf; + int i; + grub_efi_ipv6_address_t *address = &ip_address->ip6; + + interface_info = efi_ip6_config_interface_info (dev->ip6_config); //ip6配置接口信息 + + if (!interface_info) + return NULL; + + for (i = 0; i < (int)interface_info->route_count ; i++) + { + grub_uint64_t u64_addr[2]; + grub_uint64_t u64_subnet[2]; + grub_uint64_t u64_mask[2]; + + grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; + + /* SKIP Default GATEWAY */ + if (route_table->prefix_length == 0) + continue; + + u64_addr[0] = grub_get_unaligned64 (address); + u64_addr[1] = grub_get_unaligned64 (address + 4); + u64_subnet[0] = grub_get_unaligned64 (route_table->destination.addr); + u64_subnet[1] = grub_get_unaligned64 (route_table->destination.addr + 8); + u64_mask[0] = (route_table->prefix_length <= 64) ? + 0xffffffffffffffffULL << (64 - route_table->prefix_length) : + 0xffffffffffffffffULL; + u64_mask[1] = (route_table->prefix_length <= 64) ? + 0 : + 0xffffffffffffffffULL << (128 - route_table->prefix_length); + + if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0]) + && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1])) + { + for (inf = dev->net_interfaces; inf; inf = inf->next) + if (inf->prefer_ip6) + { + grub_free (interface_info); + return inf; + } + } + } + + grub_free (interface_info); + return NULL; +} + +static int +grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev, + grub_efi_net_ip_manual_address_t *net_ip, + int with_subnet) //ip6接口设置手动地址 +{ + grub_efi_status_t status; + grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6; + + if (!with_subnet) + { + grub_efi_ip6_config_manual_address_t *manual_address = + efi_ip6_config_manual_address (dev->ip6_config); //ip6配置手动地址 + + if (manual_address) + { + address->prefix_length = manual_address->prefix_length; + grub_free (manual_address); + } + else + { + /* XXX: */ + address->prefix_length = 64; + } + } + + status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, + GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, + sizeof(*address), address); + + if (status != GRUB_EFI_SUCCESS) + return 0; + + return 1; +} + +static int +grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev, + grub_efi_net_ip_address_t *address) //ip6接口设置网关 +{ + grub_efi_status_t status; + + status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, + GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, + sizeof (address->ip6), &address->ip6); + + if (status != GRUB_EFI_SUCCESS) + return 0; + return 1; +} + +static int +grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev, + grub_efi_net_ip_address_t *address) //ip6接口设置dns +{ + + grub_efi_status_t status; + + status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, + GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, + sizeof (address->ip6), &address->ip6); + + if (status != GRUB_EFI_SUCCESS) + return 0; + return 1; +} + +grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t) + { + .get_hw_address = grub_efi_ip6_interface_hw_address, //ip6接口硬件地址 + .get_address = grub_efi_ip6_interface_address, //ip6接口地址 + .get_route_table = grub_efi_ip6_interface_route_table, //ip6接口路由表 + .best_interface = grub_efi_ip6_interface_match, //ip6接口匹配 + .set_address = grub_efi_ip6_interface_set_manual_address, //ip6接口设置手动地址 + .set_gateway = grub_efi_ip6_interface_set_gateway, //ip6接口设置网关 + .set_dns = grub_efi_ip6_interface_set_dns //ip6接口设置dns + }; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void pxe_init (void); +void +pxe_init (void) +{ +// debug = 3; + char *device = 0; + char *path = 0; + + grub_efi_net_find_cards (); //ok + grub_efi_net_config_real (image->device_handle, &device, &path); //实际网络配置 net/efi/net.c +} + +#endif //ifdef FSYS_PXE diff --git a/stage2/graphics.c b/stage2/graphics.c index f8d2206..5b51685 100644 --- a/stage2/graphics.c +++ b/stage2/graphics.c @@ -1843,7 +1843,7 @@ static int read_image() grub_close(); return splashimage_loaded & 0xf; } - +#if 0 /* Convert a character which is a hex digit to the appropriate integer */ int hex (int v); int @@ -1859,7 +1859,7 @@ hex (int v) v += 9; return v & 0xf; } - +#endif /* scroll the screen */ //void bios_scroll_up(); diff --git a/stage2/pxe.h b/stage2/pxe.h index 6f1b69a..8cafd79 100644 --- a/stage2/pxe.h +++ b/stage2/pxe.h @@ -190,11 +190,11 @@ typedef struct { -typedef enum grub_network_level_protocol_id +typedef enum grub_network_level_protocol_id //网络级协议id { - GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV, - GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4, - GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6 + GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV, //DHCP_RECV + GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4, //IPV4 + GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6 //IPV6 } grub_network_level_protocol_id_t; typedef struct grub_net_network_level_netaddress @@ -328,16 +328,18 @@ typedef struct { } PACKED PXENV_UNLOAD_STACK_t; //卸载堆栈 typedef struct { - int (*open)(const char *name); //打开 tftp_open ipxe_open - grub_u32_t (*getsize)(void); //获得尺寸 tftp_get_size ipxe_get_size - grub_u32_t (*readblk)(grub_u32_t buf,grub_u32_t num); //读 tftp_read_blk ipxe_read_blk - void (*close)(void); //关闭 tftp_close ipxe_close - void (*unload)(void); //卸载 tftp_unload ipxe_unload + int (*open)(void); //打开 tftp_open ipxe_open +// grub_u32_t (*getsize)(void); //获得尺寸 tftp_get_size ipxe_get_size +// grub_u32_t (*readblk)(grub_u32_t buf,grub_u32_t num); //读 tftp_read_blk ipxe_read_blk + grub_size_t (*read)(char *buf,grub_u64_t num); //读 +// void (*close)(void); //关闭 tftp_close ipxe_close +// void (*unload)(void); //卸载 tftp_unload ipxe_unload } s_PXE_FILE_FUNC; //pxe文件功能 extern s_PXE_FILE_FUNC *pxe_file_func[2]; extern unsigned int pxe_blksize; #define PXE_FILE_TYPE_TFTP 0 -#define PXE_FILE_TYPE_IPXE 1 +#define PXE_FILE_TYPE_HTTP 1 +//#define PXE_FILE_TYPE_IPXE 1 ///////////////////////////////////////////////////////////////////////// extern struct grub_net_card *grub_net_cards; #define FOR_NET_CARDS(var) for (var = grub_net_cards; var; var = var->next) diff --git a/stage2/shared.h b/stage2/shared.h index 08e0c77..d7e2714 100644 --- a/stage2/shared.h +++ b/stage2/shared.h @@ -849,7 +849,7 @@ extern unsigned char num_wide; extern unsigned int font_spacing; extern unsigned int line_spacing; extern void rectangle(int left, int top, int length, int width, int line); -extern int hex (int v); +//extern int hex (int v); extern unsigned int splashimage_loaded; extern unsigned int X_offset,Y_offset; extern int console_color[]; @@ -1402,6 +1402,8 @@ extern unsigned int hotkey_color; extern int font_func (char *arg, int flags); extern char embed_font_path[64]; extern char *embed_font; +extern unsigned long long ext_data_0; +extern unsigned long long ext_data_1; #ifdef SUPPORT_GRAPHICS extern unsigned int current_x_resolution; @@ -1458,9 +1460,12 @@ extern void defer(unsigned short millisecond); extern unsigned short beep_duration; extern unsigned long long initrd_start_sector; extern int map_func (char *arg, int flags); +extern unsigned long long* map_start_sector; +extern unsigned long long* map_num_sectors; extern unsigned int ext_num; extern unsigned int ext_start_lba; extern unsigned int ext_total_sectors; +//extern int query_block_entries; //#define DEBUG_SLEEP {debug_sleep(debug_boot,__LINE__,__FILE__);} //extern inline void debug_sleep(int debug_boot, int line, char *file); @@ -1658,7 +1663,7 @@ extern unsigned int udf_BytePerSector; */ //extern char *end_of_low_16bit_code; -extern struct multiboot_info mbi; +//extern struct multiboot_info mbi; extern unsigned int saved_drive; extern unsigned int saved_partition; extern char saved_dir[256]; @@ -1702,7 +1707,7 @@ extern int displaymem_func (char *arg, int flags); * Error variables. */ -extern grub_error_t errnum; +extern grub_error_t errnum; //设置错误号=0x1234,大于MAX_ERR_NUM,不打印err_list[errnum],错误信息由相应程序处理。设置错误号,可以避免死机。 extern char *err_list[]; /* Simplify declaration of entry_addr. */ @@ -2246,6 +2251,9 @@ extern unsigned int pxe_restart_config; extern char *efi_pxe_buf; //2023-11-28 extern unsigned int saved_pxe_ip; extern unsigned char saved_pxe_mac[6]; +extern grub_u32_t cur_pxe_type; +extern grub_u32_t pxe_http_type; +extern int map_pd; #ifdef FSYS_PXE @@ -2880,7 +2888,7 @@ typedef enum grub_efi_reset_type grub_efi_reset_type_t; #define GRUB_EFI_NOT_FOUND GRUB_EFI_ERROR_CODE (14) //没有找到 #define GRUB_EFI_ACCESS_DENIED GRUB_EFI_ERROR_CODE (15) //拒绝访问 #define GRUB_EFI_NO_RESPONSE GRUB_EFI_ERROR_CODE (16) //没有反应 -#define GRUB_EFI_NO_MAPPING GRUB_EFI_ERROR_CODE (17) //没有映射 +#define GRUB_EFI_NO_MAPPING GRUB_EFI_ERROR_CODE (17) //没有映射 到设备的映射不存在 #define GRUB_EFI_TIMEOUT GRUB_EFI_ERROR_CODE (18) //超时 #define GRUB_EFI_NOT_STARTED GRUB_EFI_ERROR_CODE (19) //没有开始 #define GRUB_EFI_ALREADY_STARTED GRUB_EFI_ERROR_CODE (20) //已经开始 @@ -2891,6 +2899,12 @@ typedef enum grub_efi_reset_type grub_efi_reset_type_t; #define GRUB_EFI_INCOMPATIBLE_VERSION GRUB_EFI_ERROR_CODE (25)//不兼容的版本 #define GRUB_EFI_SECURITY_VIOLATION GRUB_EFI_ERROR_CODE (26) //安全违规 #define GRUB_EFI_CRC_ERROR GRUB_EFI_ERROR_CODE (27) //CRC错误 +#define GRUB_EFI_END_OF_MEDIA GRUB_EFI_ERROR_CODE (28) //已到达媒体的开始或结束 +#define GRUB_EFI_END_OF_FILE GRUB_EFI_ERROR_CODE (31) //已到达文件的末尾 +#define GRUB_EFI_INVALID_LANGUAGE GRUB_EFI_ERROR_CODE (32) //指定的语言无效 +#define GRUB_EFI_COMPROMISED_DATA GRUB_EFI_ERROR_CODE (33) //数据的安全状态未知或已损坏,必须更新或替换数据才能恢复有效的安全状态。 +#define GRUB_EFI_IP_ADDRESS_CONFLICT GRUB_EFI_ERROR_CODE (34) //存在地址冲突地址分配 +#define GRUB_EFI_HTTP_ERROR GRUB_EFI_ERROR_CODE (35) //网络操作过程中发生HTTP错误 #define GRUB_EFI_WARN_UNKNOWN_GLYPH GRUB_EFI_WARNING_CODE (1) //警告 未知字形 #define GRUB_EFI_WARN_DELETE_FAILURE GRUB_EFI_WARNING_CODE (2) //警告 删除失败 @@ -3171,8 +3185,8 @@ typedef struct grub_efi_infiniband_device_path grub_efi_infiniband_device_path_t struct grub_efi_mac_address_device_path //MAC地址设备路径 { grub_efi_device_path_t header; - grub_efi_mac_address_t mac_address; - unsigned char if_type; + grub_efi_mac_address_t mac_address; //mac地址 + unsigned char if_type; //网络接口类型(即802.3、FDDI) See RFC 3232 } __attribute__ ((packed)); typedef struct grub_efi_mac_address_device_path grub_efi_mac_address_device_path_t; //IPV4设备路径子类型 @@ -3180,15 +3194,15 @@ typedef struct grub_efi_mac_address_device_path grub_efi_mac_address_device_path struct grub_efi_ipv4_device_path //ipv4设备路径 { - grub_efi_device_path_t header; - grub_efi_ipv4_address_t local_ip_address; - grub_efi_ipv4_address_t remote_ip_address; - grub_efi_uint16_t local_port; - grub_efi_uint16_t remote_port; - grub_efi_uint16_t protocol; - grub_efi_uint8_t static_ip_address; - grub_efi_ipv4_address_t gateway_ip_address; - grub_efi_ipv4_address_t subnet_mask; + grub_efi_device_path_t header; //标头 + grub_efi_ipv4_address_t local_ip_address; //本地ip地址 + grub_efi_ipv4_address_t remote_ip_address; //远程ip地址 + grub_efi_uint16_t local_port; //本地端口 + grub_efi_uint16_t remote_port; //远程端口 + grub_efi_uint16_t protocol; //网络协议(即UDP、TCP) + grub_efi_uint8_t static_ip_address; //静态ip地址 0x00-源IP地址是通过DHCP分配的;0x01-源IP地址被静态绑定 + grub_efi_ipv4_address_t gateway_ip_address; //网关ip地址 + grub_efi_ipv4_address_t subnet_mask; //子网掩码 } GRUB_PACKED; typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t; //IPV6设备路径子类型 @@ -3196,15 +3210,15 @@ typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t; struct grub_efi_ipv6_device_path //ipv6设备路径 { - grub_efi_device_path_t header; - grub_efi_ipv6_address_t local_ip_address; - grub_efi_ipv6_address_t remote_ip_address; - grub_efi_uint16_t local_port; - grub_efi_uint16_t remote_port; - grub_efi_uint16_t protocol; - grub_efi_uint8_t static_ip_address; - grub_efi_uint8_t prefix_length; - grub_efi_ipv6_address_t gateway_ip_address; + grub_efi_device_path_t header; //标头 + grub_efi_ipv6_address_t local_ip_address; //本地ip地址 + grub_efi_ipv6_address_t remote_ip_address; //远程ip地址 + grub_efi_uint16_t local_port; //本地端口 + grub_efi_uint16_t remote_port; //远程端口 + grub_efi_uint16_t protocol; //网络协议(即UDP、TCP) + grub_efi_uint8_t static_ip_address; //静态ip地址 0x00-本地IP地址已手动配置;0x01-本地IP地址是通过IPv6无状态自动配置分配的;0x02-本地IP地址是通过IPv6状态配置分配的 + grub_efi_uint8_t prefix_length; //前缀长度 + grub_efi_ipv6_address_t gateway_ip_address; //网关ip地址 } GRUB_PACKED; typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t; //UART设备路径子类型 @@ -3749,13 +3763,14 @@ struct grub_efi_boot_services //引导服务 grub_efi_handle_t driver_image_handle, //从控制器手柄上断开的驱动程序。如果DriverImageHandle为空,则当前管理ControllerHandle的所有驱动程序都与ControllerHandle断开连接。 grub_efi_handle_t child_handle); //要摧毁子级的句柄。如果child_handle为空,则在驱动程序与controllerhandle断开连接之前,controllerhandle的所有子级都将被销毁。 + //打开协议 grub_efi_status_t EFIAPI - (*open_protocol) (grub_efi_handle_t handle, - grub_efi_guid_t *protocol, - void **protocol_interface, - grub_efi_handle_t agent_handle, - grub_efi_handle_t controller_handle, - grub_efi_uint32_t attributes); //打开协议 + (*open_protocol) (grub_efi_handle_t handle, //句柄 + grub_efi_guid_t *protocol, //协议guid + void **protocol_interface, //协议接口 + grub_efi_handle_t agent_handle, //代理句柄 + grub_efi_handle_t controller_handle, //控制句柄 + grub_efi_uint32_t attributes); //属性 grub_efi_status_t EFIAPI (*close_protocol) (grub_efi_handle_t handle, @@ -4092,9 +4107,9 @@ typedef struct grub_efi_pxe_dhcpv4_packet //引导播放器 备注: 在 ipxe->b struct grub_efi_pxe_dhcpv6_packet { - grub_efi_uint32_t message_type:8; - grub_efi_uint32_t transaction_id:24; - grub_efi_uint8_t dhcp_options[1024]; + grub_efi_uint32_t message_type:8; //消息类型 + grub_efi_uint32_t transaction_id:24; //交易id + grub_efi_uint8_t dhcp_options[1024]; //dhcp选项 } GRUB_PACKED; typedef struct grub_efi_pxe_dhcpv6_packet grub_efi_pxe_dhcpv6_packet_t; @@ -6424,7 +6439,7 @@ struct grub_net_card //网卡 void *data; //数据指针 int data_num; //数据号 }; -}; +} GRUB_PACKED; #define GRUB_NET_BOOTP_MAC_ADDR_LEN 16 typedef grub_uint8_t grub_net_bootp_mac_addr_t[GRUB_NET_BOOTP_MAC_ADDR_LEN]; @@ -6810,7 +6825,8 @@ struct grub_efi_dhcp6_protocol { grub_efi_uint32_t *option_count, grub_efi_dhcp6_packet_option_t *packet_option_list[]); }; -//====================================================================================================================== +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//http.c #define EFIHTTP_WAIT_TIME 10000 // 10000ms = 10s #define EFIHTTP_RX_BUF_LEN 10240 @@ -6832,30 +6848,30 @@ typedef enum { // EFI_HTTPv4_ACCESS_POINT HTTPv4访问点 //****************************************** typedef struct { - grub_efi_boolean_t use_default_address; //使用默认地址 - grub_efi_ipv4_address_t local_address; //本地地址 - grub_efi_ipv4_address_t local_subnet; //本地子网 - grub_efi_uint16_t local_port; //本地端口 + grub_efi_boolean_t use_default_address; //使用默认地址 设置为TRUE可指示EFI HTTP实例在该实例建立的每个TCP连接中使用默认地址信息。此外,当设置为TRUE时,LocalAddress和LocalSubnet将被忽略 + grub_efi_ipv4_address_t local_address; //本地地址 如果UseDefaultAddress设置为FALSE,则定义此实例打开的每个TCP连接中要使用的本地IP地址。 + grub_efi_ipv4_address_t local_subnet; //本地子网 如果UseDefaultAddress设置为FALSE,则定义此实例打开的每个TCP连接中要使用的本地子网。 + grub_efi_uint16_t local_port; //本地端口 这定义了此实例打开的每个TCP连接中要使用的本地端口。 } grub_efi_httpv4_access_point_t; //****************************************** // EFI_HTTPv6_ACCESS_POINT HTTPv6访问点 //****************************************** typedef struct { - grub_efi_ipv6_address_t local_address; //本地地址 - grub_efi_uint16_t local_port; //本地端口 + grub_efi_ipv6_address_t local_address; //本地地址 要在此实例打开的每个TCP连接中使用的本地IP地址。 + grub_efi_uint16_t local_port; //本地端口 要在此实例打开的每个TCP连接中使用的本地端口。 } grub_efi_httpv6_access_point_t; //****************************************** // EFI_HTTP_CONFIG_DATA HTTP配置数据 //****************************************** typedef struct { - grub_efi_http_version_t http_version; //HTTP版本 - grub_efi_uint32_t timeout_millisec; //超时毫秒 - grub_efi_boolean_t local_address_is_ipv6; //本地地址是ipv6 + grub_efi_http_version_t http_version; //HTTP版本 此实例将支持的HTTP版本 + grub_efi_uint32_t timeout_millisec; //超时(毫秒) 阻止请求时超时(以毫秒为单位) + grub_efi_boolean_t local_address_is_ipv6; //本地地址是ipv6 定义此实例使用的EFI DNS和TCP协议的行为。如果为FALSE,此实例将使用EFI_DNSO_PROTOCOLEFI_TCP4_协议。如果为TRUE,则此实例将使用EFI_DNS6-PROTOCOL和EFI_TCP6-PROTOCOL。 union { - grub_efi_httpv4_access_point_t *ipv4_node; //ipv4节点 - grub_efi_httpv6_access_point_t *ipv6_node; //ipv6节点 + grub_efi_httpv4_access_point_t *ipv4_node; //ipv4节点 当LocalAddressIsIPv6为FALSE时,这将指向本地底层TCP协议使用的地址、子网和端口。 + grub_efi_httpv6_access_point_t *ipv6_node; //ipv6节点 当LocalAddressIsIPv6为TRUE时,它指向底层TCP协议使用的本地IPv6地址和端口。 } access_point; //切入点 } grub_efi_http_config_data_t; @@ -6863,27 +6879,27 @@ typedef struct { // EFI_HTTP_METHOD HTTP方法 //****************************************** typedef enum { - GRUB_EFI_HTTPMETHODGET, //HTTP方法 获得 - GRUB_EFI_HTTPMETHODPOST, //HTTP方法 开机自检 - GRUB_EFI_HTTPMETHODPATCH, //HTTP方法 补丁 - GRUB_EFI_HTTPMETHODOPTIONS, //HTTP方法 选项 - GRUB_EFI_HTTPMETHODCONNECT, //HTTP方法 连接 - GRUB_EFI_HTTPMETHODHEAD, //HTTP方法 头 - GRUB_EFI_HTTPMETHODPUT, //HTTP方法 放置 - GRUB_EFI_HTTPMETHODDELETE, //HTTP方法 删除 - GRUB_EFI_HTTPMETHODTRACE, //HTTP方法 跟踪 + GRUB_EFI_HTTPMETHODGET, //HTTP方法 获得 请求指定的页面信息,并返回实体主体。 + GRUB_EFI_HTTPMETHODPOST, //HTTP方法 发布 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。 + GRUB_EFI_HTTPMETHODPATCH, //HTTP方法 修补 是对 PUT 方法的补充,用来对已知资源进行局部更新 。 + GRUB_EFI_HTTPMETHODOPTIONS, //HTTP方法 选择 允许客户端查看服务器的性能。 + GRUB_EFI_HTTPMETHODCONNECT, //HTTP方法 连接 HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。 + GRUB_EFI_HTTPMETHODHEAD, //HTTP方法 头部 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头 + GRUB_EFI_HTTPMETHODPUT, //HTTP方法 安置 从客户端向服务器传送的数据取代指定的文档的内容。 + GRUB_EFI_HTTPMETHODDELETE, //HTTP方法 删除 请求服务器删除指定的页面。 + GRUB_EFI_HTTPMETHODTRACE, //HTTP方法 跟踪 回显服务器收到的请求,主要用于测试或诊断。 } grub_efi_http_method_t; //****************************************** // EFI_HTTP_REQUEST_DATA HTTP请求数据 //****************************************** typedef struct { - grub_efi_http_method_t method; //方法 - grub_efi_char16_t *url; //网址 + grub_efi_http_method_t method; //方法 此HTTP请求的HTTP方法(例如GET、POST)。 + grub_efi_char16_t *url; //网址 远程主机的URI。根据此字段中的信息,HTTP实例将能够确定是使用HTTP还是HTTPS,还将能够确定要使用的端口号。如果没有指定端口号,则假定为端口80(HTTP)。有关URI语法的更多详细信息,请参阅RFC 3986。 } grub_efi_http_request_data_t; typedef enum { - GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0, //不支持 + GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0, //不受支持的状态 GRUB_EFI_HTTP_STATUS_100_CONTINUE, //继续 GRUB_EFI_HTTP_STATUS_101_SWITCHING_PROTOCOLS, //交换协议 GRUB_EFI_HTTP_STATUS_200_OK, //ok @@ -6930,65 +6946,149 @@ typedef enum { // EFI_HTTP_RESPONSE_DATA HTTP响应数据 //****************************************** typedef struct { - grub_efi_http_status_code_t status_code; //状态码 + grub_efi_http_status_code_t status_code; //状态码 远程主机返回的响应状态代码。 } grub_efi_http_response_data_t; //****************************************** // EFI_HTTP_HEADER HTTP头 //****************************************** typedef struct { - grub_efi_char8_t *field_name; //领域名称 - grub_efi_char8_t *field_value; //领域值 + grub_efi_char8_t *field_name; //字段名称 以Null结尾的字符串,用于描述字段名称。有关字段名称的详细信息,请参阅RFC 2616第14节。 + grub_efi_char8_t *field_value; //字段值 以Null结尾的字符串,用于描述相应的字段值。有关字段值的详细信息,请参阅RFC 2616第14节。 } grub_efi_http_header_t; //****************************************** // EFI_HTTP_MESSAGE HTTP消息 //****************************************** +//HTTP驱动程序将根据中包含的信息准备一个请求字符串,并将其排队到要发送到远程主机的底层TCP实例。 +//通常,结构中的所有字段都包含内容(当HTTP方法不是POST或PUT时,Body和BodyLength除外),但有一种特殊情况当使用PUT或POST发送大量数据时。 +//根据数据的大小,它可能不是能够存储在连续的内存块中,因此需要以块的形式提供数据。在这个情况下,如果Body不为NULL,BodyLength为非零, +//并且所有其他字段都为NULL或0,则HTTP驱动程序将对要发送到成功发送令牌的最后一个远程主机的数据进行排队。如果之前没有令牌发送成功, +//此函数将返回。 +//HTTP驱动程序应关闭现有的(如果有的话)基础TCP实例并创建新的TCP实例如果请求URL中的主机名与以前对request()的调用不同。 +//这与RFC 2616建议HTTP客户端应尝试维护开放的TCP连接客户端和主机之间。 typedef struct { union { - grub_efi_http_request_data_t *request; //请求 - grub_efi_http_response_data_t *response; //响应 + grub_efi_http_request_data_t *request; //请求 当令牌用于发送HTTP请求时,request是指向包含URL和HTTP方法等数据的存储的指针。 + grub_efi_http_response_data_t *response; //响应 当用于等待响应时,response指向包含HTTP响应状态代码的存储。 } data; //数据 - grub_efi_uint32_t header_count; //标题计数 - grub_efi_http_header_t *headers; //标头 - grub_efi_uint32_t body_length; //体长 - void *body; //体 + grub_efi_uint32_t header_count; //标题计数 标头列表中的HTTP标头结构数。根据请求,此计数由调用者提供。响应时,此计数由HTTP驱动程序提供。 + grub_efi_http_header_t *headers; //标头 包含HTTP标头列表的数组。根据请求,此数组由调用方填充。响应时,此数组由HTTP驱动程序分配和填充。调用方负责在请求和响应时释放此内存。 + grub_efi_uint32_t body_length; //体长 HTTP正文的长度(以字节为单位)。这可以是零,具体取决于HttpMethod类型。 + void *body; //体 与HTTP请求或响应关联的正文。这可以是NULL,具体取决于HttpMethod类型。 } grub_efi_http_message_t; //****************************************** // EFI_HTTP_TOKEN HTTP令牌 //****************************************** typedef struct { - grub_efi_event_t event; //事件 - grub_efi_status_t status; //状态 - grub_efi_http_message_t *message; //信息 + grub_efi_event_t event; //事件 EFI HTTP协议驱动程序更新Status字段后,将发出此事件的信号。事件的类型必须是EFI_NOTIFY_SIGNAL。事件的任务优先级(TPL)必须低于或等于TPL_CALLBACK。 + grub_efi_status_t status; //状态 如果HTTP请求为成功发送或发生意外错误: +//EFI_SUCCESS:HTTP请求已成功发送到远程主机。 +//EFI_HTTP_ERROR:响应消息成功收到,但包含HTTP错误。响应状态代码为在Token中返回。 +//EFI_ABORTED:调用方取消了HTTP请求,并且从传输队列中删除。 +//EFI_TIMEOUT:HTTP请求在到达之前超时远程主机。 +//EFI_DEVICE_ERROR:意外的系统或网络错误发生。 + grub_efi_http_message_t *message; //信息 指向包含HTTP消息数据的存储的指针。 } grub_efi_http_token_t; struct grub_efi_http { //获得模式数据 +//获取当前操作状态。返回当前HTTP子实例的操作参数。 grub_efi_status_t - (*get_mode_data) (struct grub_efi_http *this, - grub_efi_http_config_data_t *http_config_data); + (*get_mode_data) (struct grub_efi_http *this, //指向EFI_HTTP_PROTOCOL实例的指针。 + grub_efi_http_config_data_t *http_config_data); //指向此HTTP实例的操作参数的缓冲区的指针。调用方负责为HttpConfigData和HttpConfigData->AccessPoint分配内存。IPv6节点/IPv4节点。事实上,建议分配足够的内存来记录IPv6Node,因为它足够大,可以满足所有可能性。 //配置 +//初始化、更改或重置EFI HTTP协议实例中的操作设置 +//Configure()函数执行以下操作: +//•当HttpConfigData不为NULL时,通过配置超时、本地地址、端口等初始化此EFI HTTP实例。 +//•当HttpConfigData为NULL时,通过关闭与远程主机的所有活动连接、取消所有异步令牌以及在不通知适当主机的情况下刷新请求和响应缓冲区来重置此EFI HTTP实例。。 +//在Configure()函数执行并成功返回之前,此实例无法执行其他EFI HTTP函数。 grub_efi_status_t - (*configure) (struct grub_efi_http *this, - grub_efi_http_config_data_t *http_config_data); //配置数据 + (*configure) (struct grub_efi_http *this, //指向EFI_HTTP_PROTOCOL实例的指针。 + grub_efi_http_config_data_t *http_config_data); //配置数据 指向用于配置实例的配置数据的指针。 //请求 +//将请求令牌排入传输队列。此功能是非阻塞操作。 +//Request()函数将HTTP请求排队到此HTTP实例,类似于EFI TCP驱动程序中的Transmit()函数。当HTTP请求成功发送时,或者出现错误时,将更新令牌中的Status,并发出Event信号。 grub_efi_status_t - (*request) (struct grub_efi_http *this, - grub_efi_http_token_t *token); //令牌 + (*request) (struct grub_efi_http *this, //指向EFI_HTTP_PROTOCOL实例的指针。 + grub_efi_http_token_t *token); //令牌 指向包含HTTP请求令牌的存储的指针。 //取消 +//中止挂起的请求或响应操作。 +//Cancel()函数中止挂起的HTTP请求或响应事务。如果取消时Token不为NULL并且处于发送或接收队列中,则其Token->Status将设置为EFI_ABORTED,然后Token->Event将发出信号。如果令牌不在其中一个队列中,这通常意味着异步操作已经完成,则返回EFI_not_FOUND。如果Token为NULL,则Request()或Response()发出的所有异步令牌都将中止。 grub_efi_status_t - (*cancel) (struct grub_efi_http *this, - grub_efi_http_token_t *token); //令牌 + (*cancel) (struct grub_efi_http *this, //指向EFI_HTTP_PROTOCOL实例的指针。 + grub_efi_http_token_t *token); //令牌 指向包含HTTP请求或响应令牌的存储。 //响应 +//将响应令牌排入接收队列。此功能是非阻塞操作。 +//Response() 函数将对此HTTP实例的HTTP响应排队,类似于EFI TCP驱动程序中的Receive()函数。当成功接收到HTTP响应时,或者如果出现错误,将更新令牌中的Status,并发出Event信号。 +//HTTP驱动程序将接收令牌排入底层TCP实例的队列。当在中接收到数据时底层TCP实例,数据将被解析,令牌将被填充响应数据。 +//如果从远程主机接收的数据包含不完整或无效的HTTP标头,即HTTP驱动程序将继续(异步)等待从远程主机发送更多数据,然后再发出信号令牌中的事件。 +//调用方负责为Body分配缓冲区并在BodyLength中指定大小。如果远程主机提供一个包含内容正文的响应,最多BodyLength字节将从接收缓冲区复制到正文中, +//并且BodyLength将根据接收到的字节数进行更新并复制到Body。这允许客户端将大文件分块下载,而不是下载到一个文件中连续的内存块。 +//类似于HTTP请求,如果Body不为NULL并且BodyLength为非零并且所有其他字段都为NULL或0,则HTTP驱动程序将接收令牌排队到底层TCP实例。 +//如果数据到达接收缓冲区,则最多BodyLength字节的数据将被复制到Body。HTTP然后,驱动程序将用接收并复制到Body的字节数更新BodyLength。 +//如果HTTP驱动程序与响应URL中指定的主机没有打开的底层TCP连接,response()将返回EFI_ACCESS_DENIED。这与RFC 2616的建议一致,即HTTP客户端应尝试维护客户端和主机之间的开放TCP连接。 grub_efi_status_t - (*response) (struct grub_efi_http *this, - grub_efi_http_token_t *token); //令牌 + (*response) (struct grub_efi_http *this, //指向EFI_HTTP_PROTOCOL实例的指针。 + grub_efi_http_token_t *token); //令牌 指向包含HTTP响应令牌的存储的指针。有关EFI_HTTP_TOKEN的定义,请参阅Request()函数。 //获得 +//轮询以接收传入的HTTP响应并发送传出的HTTP请求。 +//轮询传入的数据包并处理传出的数据包。 +//网络驱动程序和应用程序可以使用Poll()函数来增加数据包在通信设备之间移动的速率,以及发送和接收队列。 +//在某些系统中,中的周期性计时器事件受管网络驱动程序可能不会轮询底层通信设备足够快以发送和/或接收所有数据分组,而不会丢失传入分组或丢弃传出分组。 +//驱动程序和应用程序正在经历数据包丢失,应尝试更频繁地调用Poll()函数。 grub_efi_status_t - (*poll) (struct grub_efi_http *this); + (*poll) (struct grub_efi_http *this); //指向EFI_HTTP_PROTOCOL实例的指针。 }; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* +//EFI_HTTP_UTILITIES_PROTOCOL EFI HTTP实用程序协议接口 +//协议GUID +#define EFI_HTTP_UTILITIES_PROTOCOL_GUID \ +{ 0x3E35C163, 0x4074, 0x45DD,\ + { 0x43, 0x1E, 0x23, 0x98, 0x9D, 0xD8, 0x6B, 0x32 }} + +//协议接口结构 +//EFI HTTP实用程序协议设计用于EFI驱动程序和应用程序解析字节流中的HTTP头。该驱动程序既不依赖于网络连接,也不依赖于底层网络基础设施的存在。 +typedef struct _EFI_HTTP_UTILITIES_PROTOCOL { + EFI_HTTP_UTILS_BUILD Build; //创建 基于种子标头、要删除的字段和要附加的字段的组合创建HTTP标头。 + EFI_HTTP_UTILS_PARSE Parse; //解析 解析HTTP头并生成一个键/值对数组。 +} EFI_HTTP_UTILITIES_PROTOCOL; + +//EFI_HTTP_UTILITIES_PROTOCOL.Build() //创建 +//提供在原始HTTP消息中添加、删除或替换HTTP标头的功能 +//Build()函数用于通过提供添加、删除或替换HTTP标头的功能来管理HTTP消息的标头部分。 +//EFI协议 +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_UTILS_BUILD) ( + IN EFI_HTTP_UTILITIES_PROTOCOL *This, //指向EFI_HTTP_UTILITIES_PROTOCOL实例的指针。 + IN UINTN SeedMessageSize //种子消息尺寸 初始HTTP标头的大小。这可以是零。 + IN VOID *SeedMessage, OPTIONAL //种子消息 要用作构建新HTTP标头的基础的初始HTTP标头。如果为NULL,则忽略SeedMessageSize。 + IN UINTN DeleteCount //删除计数 DeleteList中终止为null的HTTP标头字段名的数目。 + IN CHAR8 *DeleteList[], OPTIONAL //删除列表 要从SeedMessage中删除的以null结尾的HTTP标头字段名称的列表。此列表中只有字段名,因为字段值与此操作无关。 + IN UINTN AppendCount //附加计数 AppendList中的标头字段数。 + IN EFI_HTTP_HEADER *AppendList[], OPTIONAL //附加列表 用于填充NewMessage的HTTP标头的列表。如果SeedMessage不为NULL,则AppendList将被附加到NewMessage中的SeedMessage的现有列表中 + OUT UINTN *NewMessageSize, //新消息尺寸 指向NewMessage中标头字段数的指针。 + OUT VOID **NewMessage, //新建消息 指向基于的新HTTP标头列表的指针 +); + +//EFI_HTTP_UTILITIES_PROTOCOL.Parse() //解析 +//将HTTP标头解析为键/值对数组。 +//Parse()函数用于将存储在HttpHeader中的数据转换为与其对应值配对的字段列表。 +//EFI Protocol +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_UTILS_PARSE) ( + IN EFI_HTTP_PROTOCOL *This, //指向EFI_HTTP_UTILITIES_PROTOCOL实例的指针。 + IN CHAR8 *HttpMessage, //Http消息 包含未格式化的原始HTTP标头字符串 + IN UINTN HttpMessageSize, //Http消息尺寸 HTTP标头的尺寸 + OUT EFI_HTTP_HEADER **HeaderFields, //标题字段 键/值头对的数组 + OUT UINTN *FieldCount //字段计数 HeaderFields中的标头数。 +); +*/ + typedef struct grub_efi_http grub_efi_http_t; //协议接口结构 typedef struct grub_efi_net_interface grub_efi_net_interface_t; @@ -6999,7 +7099,7 @@ typedef struct grub_efi_net_ip_manual_address grub_efi_net_ip_manual_address_t; struct grub_efi_net_interface //网络接口 { char *name; //名称 - int prefer_ip6; //是ip6 + int prefer_ip6; //首选ip6 struct grub_efi_net_device *dev; //网络设备 struct grub_efi_net_io *io; //网络io grub_efi_net_ip_config_t *ip_config; //ip配置 @@ -7014,6 +7114,12 @@ struct grub_efi_net_interface //网络接口 #define efi_net_interface_set_gateway(inf, addr) inf->ip_config->set_gateway (inf->dev, addr) #define efi_net_interface_set_dns(inf, addr) inf->ip_config->set_dns (inf->dev, addr) +#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6) +#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type) +#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz) +#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file) +#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__) + struct grub_efi_net_ip_config { char * (*get_hw_address) (struct grub_efi_net_device *dev); @@ -7247,5 +7353,180 @@ enum GRUB_ACPI_EXTOPCODE_BANK_FIELD_OP = 0x87, }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//grub/charse.h +#define GRUB_MAX_UTF8_PER_UTF16 4 +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//grub/compiler.h + +/* GCC version checking borrowed from glibc. */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define GNUC_PREREQ(maj,min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +# define GNUC_PREREQ(maj,min) 0 +#endif + +/* Does this compiler support compile-time error attributes? */ +#if GNUC_PREREQ(4,3) +# define ATTRIBUTE_ERROR(msg) \ + __attribute__ ((__error__ (msg))) +#else +# define ATTRIBUTE_ERROR(msg) __attribute__ ((noreturn)) +#endif + +#if GNUC_PREREQ(4,4) +# define GNU_PRINTF gnu_printf +#else +# define GNU_PRINTF printf +#endif + +#if GNUC_PREREQ(3,4) +# define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) +#else +# define WARN_UNUSED_RESULT +#endif + +#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) +# define CLANG_PREREQ(maj,min) \ + ((__clang_major__ > (maj)) || \ + (__clang_major__ == (maj) && __clang_minor__ >= (min))) +#else +# define CLANG_PREREQ(maj,min) 0 +#endif + +#define UNUSED __attribute__((__unused__)) +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//grub/safemath.h + +/* These appear in gcc 5.1 and clang 3.8. */ +#if GNUC_PREREQ(5, 1) || CLANG_PREREQ(3, 8) + +#define grub_add(a, b, res) __builtin_add_overflow(a, b, res) +#define grub_sub(a, b, res) __builtin_sub_overflow(a, b, res) +#define grub_mul(a, b, res) __builtin_mul_overflow(a, b, res) + +#else +/* + * Copyright 2020 Rasmus Villemoes + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +/* + * The code used in this header was taken from linux kernel commit + * f0907827a8a9152aedac2833ed1b674a7b2a44f2 + * Rasmus Villemoes , the original author of the + * patch, was contacted directly, confirmed his authorship of the code, and + * gave his permission on treating that dual license as MIT and including into + * GRUB2 sources + */ + +#include +#define is_signed_type(type) (((type)(-1)) < (type)1) +#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type))) +#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T))) +#define type_min(T) ((T)((T)-type_max(T)-(T)1)) + +#define __unsigned_add_overflow(a, b, d) ({ \ + typeof(+(a)) __a = (a); \ + typeof(+(b)) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a + __b; \ + *__d < __a; \ +}) +#define __unsigned_sub_overflow(a, b, d) ({ \ + typeof(+(a)) __a = (a); \ + typeof(+(b)) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a - __b; \ + __a < __b; \ +}) +#define __unsigned_mul_overflow(a, b, d) ({ \ + typeof(+(a)) __a = (a); \ + typeof(+(b)) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a * __b; \ + __builtin_constant_p(__b) ? \ + __b > 0 && __a > type_max(typeof(__a)) / __b :\ + __a > 0 && __b > type_max(typeof(__b)) / __a; \ +}) + +#define __signed_add_overflow(a, b, d) ({ \ + typeof(+(a)) __a = (a); \ + typeof(+(b)) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (grub_uint64_t)__a + (grub_uint64_t)__b; \ + (((~(__a ^ __b)) & (*__d ^ __a)) \ + & type_min(typeof(__a))) != 0; \ +}) + +#define __signed_sub_overflow(a, b, d) ({ \ + typeof(+(a)) __a = (a); \ + typeof(+(b)) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (grub_uint64_t)__a - (grub_uint64_t)__b; \ + ((((__a ^ __b)) & (*__d ^ __a)) \ + & type_min(typeof(__a))) != 0; \ +}) + +#define __signed_mul_overflow(a, b, d) ({ \ + typeof(+(a)) __a = (a); \ + typeof(+(b)) __b = (b); \ + typeof(d) __d = (d); \ + typeof(+(a)) __tmax = type_max(typeof(+(a))); \ + typeof(+(a)) __tmin = type_min(typeof(+(a))); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (grub_uint64_t)__a * (grub_uint64_t)__b; \ + (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) ||\ + (__b < (typeof(__b))-1 && \ + (__a > __tmin/__b || __a < __tmax/__b)) || \ + (__b == (typeof(__b))-1 && __a == __tmin); \ +}) + +#define grub_add(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(+(a))), \ + __signed_add_overflow(a, b, d), \ + __unsigned_add_overflow(a, b, d)) + +#define grub_sub(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(+(a))), \ + __signed_sub_overflow(a, b, d), \ + __unsigned_sub_overflow(a, b, d)) + +#define grub_mul(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(+(a))), \ + __signed_mul_overflow(a, b, d), \ + __unsigned_mul_overflow(a, b, d)) + +#endif +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #endif /* ! ASM_FILE */ #endif /* ! GRUB_SHARED_HEADER */