EDK2 Stable202311来了

去年11月份 edk2 202311正式发布在:

https://github.com/tianocore/edk2/releases/tag/edk2-stable202311

从 History 来看,解决了不少Bug:

和之前类似,这里放上一个完整版,补全了所有的三方库,大小是136MB 左右。

链接:

https://pan.baidu.com/s/1eFC1XwfNTKj7hs_JRRieuw?pwd=LABZ

提取码: LABZ

个人建议:除非有特别明确的目的,否则没有必要追求最新的版本, 所谓 “小车能跑只管推”。

Step to UEFI (285)Cpp UEFI 000 实验环境的搭建

在之前的文章中【参考1】介绍了一个基于 Visual C++非常简单的 UEFI 开发框架。偶然的机会发现使用这个架构可以方便的实现C++ 的编写。于是,从这里开始,介绍如何使用这个框架学习简单的C++知识。

这次首先介绍实验环境的配置。在 C:\BuildBs\CppStudy\ 下创建 CPP 目录,其中放置测试使用到的文件:

其中 gfx.cpp 是源代码,g1.bat 是用于编译的批处理,这里直接使用批处理来进行编译,其中写入的都是绝对路径,这样更加直观容易理解发生了生么。

编译方法是打开 VS2019 X86 Command窗口(必须使用X64 窗口),在目录下运行 g1.bat 之后就会生成Cpp1.efi 的文件。

将这个文件拷贝到 Emulator 目录下就可以在模拟器中测试了。模拟器是来自EDk202308,有兴趣的朋友可以自行编译生成或者使用其他编译器。

之后进入 Emulator 运行 WinHost.exe ,即可运行 cpp1.efi 进行测试。

上述文件打包为一个文件有兴趣的朋友可以使用这个环境进行实验。

特别需要注意的是:在这一套环境中,当需要使用gSystemTable->ConOut->OutputString() 的时候,需要使用 u”XXX” 来定义字符串,这个是因为在 basic_types.h 中使用了如下定义:

using CHAR16 = char16_t;

这个对于我们编写代码影响不大,字符串使用 u作为前缀即可。

参考:

1. https://www.lab-z.com/sus/ 一个非常简单的UEFI Application开发框架

EasyX 生成计时器的视频

前一段想在一个视频中增加一个计时器的画面,然后忽然发现视频编辑工具并没有直接提供这样的功能。通常建议的手段是:直接插入其他计时器的视频。最简单的做法是在手机上安装一个秒表之类的软件,然后通过内置的录屏功能得到需要的视频。只是这样方法很难获得需要的背景颜色和文字颜色。

正好最近研究了 EasyX 的使用,于是通过编程生成图片,然后使用FFMpeg 把图片粘成视频。

这次测试的代码如下:

#include <graphics.h>
#include <time.h>
#include <conio.h>
#include <stdio.h>

#define WINWIDTH   1920
#define WINHEIGHT  1080

// 一秒25帧,一共1分钟
#define TOTALTIME  60*25

int main()
{
	TCHAR FilenameBuffer[256];
	
	// 初始化图形模式
	initgraph(WINWIDTH, WINHEIGHT);
	settextcolor(RED);
	settextstyle(500, 0, _T("Consolas"));

	for (int i = 0; i < TOTALTIME; i++) {
		BeginBatchDraw();
		cleardevice();
		swprintf(FilenameBuffer, sizeof(FilenameBuffer), L"%02d:%03d", i / 24, (i * 1000 / 24)%1000);
		
		outtextxy(20, 20, FilenameBuffer);
		EndBatchDraw();

		swprintf(FilenameBuffer,sizeof(FilenameBuffer), L"%05d.png", i);
		printf("%ls\n", FilenameBuffer);
		saveimage(FilenameBuffer);
		//Sleep(20);
	}

	// 按任意键退出
	_getch();

	// 关闭图形模式
	closegraph();
	return 0;
}

用于生成视频的命令如下:

ffmpeg -r 25 -i %05d.png -b:v 4M output2.mp4

最终的结果可以在B站看到

【EasyX 生成1分钟计时器视频】

使用 EasyX 生成动画的方法

第一步:编写代码,在代码中需要将每一帧保存为图片格式。比如,下面是一个在圆中绘制另外一个圆的程序:

#include <graphics.h>
#include <time.h>
#include <conio.h>
#include <stdio.h>

#define WINWIDTH  1200
#define WINHEIGHT  600
#define RADIUS	  280

int main()
{
	TCHAR FilenameBuffer[256];
	
	// 初始化图形模式
	initgraph(WINWIDTH, WINHEIGHT);
	//getimage(pImage,0,0, WINWIDTH-1, WINHEIGHT-1);
	setfillcolor(RED);
	fillcircle(WINWIDTH/2, WINHEIGHT/2,RADIUS);
	setfillcolor(GREEN);
	
	for (int i = 1; i < 1001; i++) {
		BeginBatchDraw();
		fillpie(
			(WINWIDTH - RADIUS)/2, 
			(WINHEIGHT - RADIUS)/2, 
			(WINWIDTH + RADIUS)/2, 
			(WINHEIGHT + RADIUS)/2, 
			0, 3.14*2/1000*i);
		EndBatchDraw();

		swprintf(FilenameBuffer,sizeof(FilenameBuffer), L"%05d.jpg", i);
		printf("%ls\n", FilenameBuffer);
		saveimage(FilenameBuffer);
	}

	// 按任意键退出
	_getch();

	// 关闭图形模式
	closegraph();
	return 0;
}

运行这个程序之后,你会在目录下找到 00000.jpg 到 01000.jpg 文件

第二步,使用 FFMPEG 将这些文件“粘”成一个视频。在 https://github.com/BtbN/FFmpeg-Builds/releases 下载编译好的 FFMPEG 工具(对应 ffmpeg-master-latest-win64-gpl 这个名称的文件)。

使用的命令是:

ffmpeg -r 25 -i %05d.jpg -b:v 4M output2.mp4

其中 -r 25表示1秒25帧, -b:v 4M 设定输出视频码率。具体请根据需要酌情修改。

最终就可以生成一个40秒的视频:

最终制作的视频可以在 B站看到:

【EasyX 制作动画视频的例子】

Step to UEFI (284)最小的UEFI Application编译环境

前面介绍过一个最小的 UEFI Application编译器【参考1】,美中不足的是它还要依赖于 EDK2 的环境。这次介绍如何从 EDK2 中抽取所需的最小文件,从而实现一个最简单的编译环境。换句话说,之前介绍的是一个最小的用于生成 UEFI Application的编译器,这次介绍的是编译器和编译所需的环境。

实现的方法很简单:研究上一次的编译命令

x86_64-win32-tcc -I MdePkg/Include hello.c  -Wl,-subsystem=efiapp -nostdlib -o labz1.efi -DMDE_CPU_EBC

可以看到,指定了MdePkg/Include作为Include 路径,因此,只要我们将这个路径下依赖的文件提取出来即可。

最终实验发现提取如下的文件和目录就够了:

运行命令,编译之(需要注意使用 cmd 窗口):

生成文件labz1.efi, 模拟器测试工作正常:

整个环境只有200KB 左右。有兴趣的朋友可以自行研究。

同样的我们可以直接在 Visual C++ X64窗口中使用下面的命令编译:

cl -I MdePkg/Include hello.c
link.exe /ENTRY:_start /SUBSYSTEM:EFI_APPLICATION /LIBPATH:MdePkg/Include /NODEFAULTLIB /nologo /OUT:YourApp.efi hello.obj

同样可以正常运行:

参考:

1. https://www.lab-z.com/stu279tcc/ 介绍一个最小的UEFI Application 编译器

如何下载 Windows 11 指定版本

如果你只是想下载安装最新的 Windows 11 ,可以到 https://msdn.itellyou.cn/ 进行下载。但是如果你想获得一个指定的版本或者说不是正是发布的版本,上面的网站未必能够找到。这次推荐的使用 https://uupdump.net/ 这个网站。

以获得 Windows 11 22621.1250版本为例,介绍使用方法:

1.打开网站搜索 “22621 1250”

2.在搜索的结果中选择你需要的版本,比如:Windows 11 Insider Preview 10.0.22621.1250 (ni_release) amd64

3.点击链接进入下载界面,首先选择语言版本,通常推荐选择英语(美国)版本用于测试。因为很多测试工具是基于英文开发。比如,测试使用的工具可能会在设备管理器中搜索驱动名称,而驱动名称的英文和中文可能是不一样的。因此,如果你使用中文版本,可能会出现设备明明存在,但是工具却无法找到。

4.接着选择 SKU ,通常推荐使用专业版

5.为了便于分发和使用,推荐“下载并转化为 ISO 镜像文件”

6.点击“创建下载包”之后可以得到“22621.1250_amd64_en-us_professional_60821a74_convert.zip”这个文件,解压之后文件如下:

7.这些是下载镜像的脚本,以管理员权限打开cmd窗口后,运行“uup_download_windows.cmd”即可启动下载(特别注意:脚本不支持 Windows 7)。速度主要取决于你的网络情况。比如,我下载 22621 这个版本,最终的 ISO 是 5.9G,花费了2个小时。完成之后的界面如下:

8. 可以看到最终下载得到了一个 ISO 文件:22621.1250.230124-1741.NI_RELEASE_SVC_BETAFLT_PROD1_CLIENTPRO_OEMRET_X64FRE_EN-US.iso 这就是我们需要的 Windows 版本。

之后,就可以使用这个镜像进行系统的安装了。

Step to UEFI (283)QEMU下面的 LVGL 测试

LVGL(Light and Versatile Graphics Library,轻巧而多功能的图形库)是一个免费的开放源代码图形库,它提供创建具有易于使用的图形元素,精美的视觉效果和低内存占用的嵌入式GUI所需的一切。LVGL的项目作者是来自匈牙利首都布达佩斯的 Gábor Kiss-Vámosi 。Kiss 在2016年将其并发布在 GitHub 上。

当时叫 LittlevGL而不是LVGL,后来作者统一修改为 LVGL 甚至连仓库地址都改了。 像一般的开源项目的那样,它是作为一个人的项目开始的。 从那时起,陆续有近 100 名贡献者参与了项目开发,使得 LVGL 逐渐成为最受欢迎的嵌入式图形库之一。【参考1】

https://ay123.net/mystudy/845/ 由Bin Porting 到了UEFI上。他在 https://github.com/mxmks/LVGLUEFIRWNothing/tree/main 提供了完整的代码。这次就以这套代码为例进行测试。

需要注意的是:如果你在 EDK2 的 Emulator上测试,需要调整分辨率大于等于1024×768【参考2】. 如果你在 QEMU 上测试,那么需要使用如下命令打开USB 鼠标支持(默认情况下是支持 PS2 鼠标的,但是我测试没有成功):

qemu-system-x86_64 -bios ovmf.fd  -net none -hda fat:rw:c:\temp\ov -usb -device usb-mouse

之后,在 QEMU 中加载 USB 驱动(MdeModulePkg\Bus\Usb\UsbBusDxe\UsbBusDxe)和USB Mouse 驱动(MdeModulePkg\Bus\Usb\UsbMouseDxe\UsbMouseDxe)。

有兴趣的朋友不妨自行实验。

本问题提到的 USB 驱动和 USB Mouse 驱动可以通过 EDK2 编译获得,也可以在这里下载:

参考:

1. https://www.xpstem.com/article/10465

2.

ch569 上手测试

为了玩转 Ch569 ,需要准备如下硬件和软件:

硬件要求:

1.官方的 Ch569 开发板,官方买到的是两块插接在一起的,大多数情况下我们的实验都只使用到一块。

CH559 开发板

CH559 开发板

2.USB 3.0 A-A 线一根

软件要求(都可以在官网下载到):

1.项目管理和编译工具:MounRiver

2.官方 Demo: CH569EVT

3.烧写软件:WCHISPTool

安装完成CH569 后,以\CH569EVT\EVT\EXAM\USBSS\USBD\CH372Device为例。这个代码能够将Ch569模拟为Ch372设备。

编译之后的得到编译后的文件位于: obj\CH372Device.hex。

Ch569开发板的烧写方式是将HD0 Pin 接地然后再上电。设备管理器中会出现 “USB Module”这个设备:

之后我们打开WCHISP 工具,如果没有出现下图左侧的界面,那么需要点击右侧“Dedicated MCUs”按钮。

之后在上面的 Object File1 中选择上面提到的 CH372Device.hex 文件,最后点击 Download 即可。

烧录完成后,可以通过 EVT\EXAM\USBSS\USBD\CH372-HSPIDataTransDemo.zip 中的程序进行测试。这个程序会对设备进行一个速度读写测试,在我电脑上测试结果如下:

这个程序测试的是对一个端点写入,然后从另外的端口读取出来。

Step to UEFI (282)如何修改 Emulator 的分辨率

在测试一些简单的 UEFI Application 时,EDK2 自带的Emulator 还是非常方便的。这次介绍的就是如何修改 Emulator的默认分辨率。

首先,使用 build -a X64 -p EmulatorPkg\EmulatorPkg.dsc -t VS2019 编译 Emulator

接下来运行 Build\EmulatorX64\DEBUG_VS2019\X64 中的 WinHost.exe,在 Shell 中运行【参考1】提供的 Application 检查当前的分辨率,可以看到默认为 800×600。

接下来修改分辨率,在 \EmulatorPkg\EmulatorPkg.dsc 中指定分辨率为 1024×768:

[PcdsDynamicDefault.common.DEFAULT]
  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|0
  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|0
  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|0
  #LABZ_Start
  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution|1024
  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution|768
  #LABZ_End
[PcdsDynamicHii.common.DEFAULT]
  gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn|L"Setup"|gEmuSystemConfigGuid|0x0|80
  gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow|L"Setup"|gEmuSystemConfigGuid|0x4|25
  gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L"Timeout"|gEfiGlobalVariableGuid|0x0|10

重新编译 Emulator后再次运行,可以看到分辨率已经修改为我们指定的。

参考:

1.https://www.lab-z.com/stu233sp/ 屏幕分辨率研究

2.http://lab-z.com/stu282/ 如何修改 Emulator 的分辨率

Step to UEFI (281)Emulator Debug Message 的输出

几年之前,研究过 EDK2 的调试信息输出的问题【参考1】【参考2】。最近偶然之间发现目前的 EDK2 的 EmulatorPkg 生成的 WinHost.exe 无法使用“>>”进行输出重定向。这次针对这个问题进行研究。

首先说说具体的现象。使用 winhost >> out.txt 命令,尝试抓取Debug 信息,仍然能在屏幕上看到 Debug 信息:

打开 out.txt 可以看到抓到了部分的信息:

根据之前的知识,我们在 EmulatorPkg 中搜索 STD_OUTPUT_HANDLE,可以找到三个位置:

1. \EmulatorPkg\Win\Host\WinHost.c 中的SecPrint() 函数,我们在其中加入   strcat(Buffer,”DBG0″)

2. \EmulatorPkg\Win\Host\WinThunk.c 中的SecWriteStdErr() 函数,我们加入

  NumberOfBytes=NumberOfBytes+4;

  strcat(Buffer,”DBG1″);

3. \EmulatorPkg\Win\Host\WinThunk.c中的SecWriteStdOut() 函数,我们加入

  NumberOfBytes=NumberOfBytes+4;

  strcat(Buffer,”DBG2″);

再次进行测试,在 OUT.TXT 中可以看到:

对应的屏幕可以看到如下输出:

所以,问题在于:

  1. WriteFile ( GetStdHandle (STD_OUTPUT_HANDLE),…….) 能够重定向到文件中
  2. WriteFile ( GetStdHandle (STD_ERROR_HANDLE),…….) 无法定向到文件中

如果将上面的2中的STD_ERROR_HANDLE,修改为STD_OUTPUT_HANDLE,即可重定向到文件中。

当然,遇到 Windows 相关问题,还是需要请教天杀,对此他给出了Microsoft的资料【参考3】,如果我们不想修改代码,那么可以直接使用下面的方式重定向到文件中:

WinHost 2 >>OUT.txt

有兴趣的朋友不妨自己动手试试。

参考:

  1. http://www.lab-z.com/stu82/  NT32Pkg的Debug Message 
  2. http://www.lab-z.com/stu130nt32/ NT32 模拟器中的 Debug Message 输出
  3. https://learn.microsoft.com/zh-cn/troubleshoot/developer/visualstudio/cpp/language-compilers/redirecting-error-command-prompt