UEFI开发学习22 – 退出码
简介
退出码(Exit Code),也可以当作是程序的返回值。在C语言中,主函数main可以写成void类型,可以不用返回任何值,但这样程序运行后,父级进程无法获得该程序的任何状态,对于一些有先后执行顺序的程序来说,这样是很危险的,因为如果前一个没执行成功,又继续执行后面的程序,可能会导致系统崩溃。所以有些编译器会检查main的类型,如果是void,则会编译报错。
在使用C库的EFI APP中,虽然也可以使用void类型的main,但并不推荐这么做,最好养成一个好习惯,使用具有返回值的类型。
而在标准UEFI的入口函数中,其类型定义是EFI_STATUS,即函数最后必须返回一个值。该值返回后,可以被父级程序捕捉到,或保存在控制台的lasterror环境变量中,脚本同样能获取该值,这样便可以检验程序的运行状态,进行一些错误处理。
APP错误处理
上一篇文章中,写了如何运行一个 EFI APP ,那如何判断该 APP 的是否正常执行呢?方法就是获取它的exit code,下面还是以上篇文章的代码为例,用StartEfi.efi启动一个Helloworld.efi,Helloworld.efi 结束后,StartEfi.efi 打印 Helloworld.efi 的Status,如下:
// Helloworld.efi #include <Uefi.h> #include <Library/UefiLib.h> #include <Library/UefiBootServicesTableLib.h> EFI_STATUS EFIAPI UefiMain ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { Print(L"Hello world!\n\r"); return EFI_NOT_FOUND; }
// StartEfi.efi #include <Uefi.h> #include <Library/UefiLib.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiRuntimeServicesTableLib.h> #include <Library/DebugLib.h> #include <Library/DevicePathLib.h> #include <Protocol/LoadedImage.h> EFI_STATUS EFIAPI UefiMain ( IN EFI_HANDLE MyImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINTN Index; UINTN NoHandles; EFI_HANDLE * Buffer; EFI_DEVICE_PATH_PROTOCOL * DevicePath; EFI_HANDLE ImageHandle; CHAR16 * EfiImageName = L"\\HelloWorld.efi"; Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &NoHandles, &Buffer); if (EFI_ERROR(Status)) { Print(L"Unsupported\n\r"); return 0; } for (Index = 0; Index < NoHandles; Index ++){ DevicePath = FileDevicePath (Buffer[Index], EfiImageName); Status = gBS->LoadImage ( FALSE, gImageHandle, DevicePath, NULL, 0, &ImageHandle ); if (EFI_ERROR (Status)) { Print(L"Load Image error %r %x\n\r", Status, gImageHandle); continue; } Status = gBS->StartImage (ImageHandle, NULL, NULL); if (Status == EFI_SUCCESS) { Print (L"Program run successfully!\n\r", Status); } else if (Status == EFI_INVALID_PARAMETER) { Print (L"Program can not start!\n\r"); } else if (Status == EFI_SECURITY_VIOLATION) { Print (L"Program can not start!\n\r"); } else { Print(L"Program exit with an error status: %r\n\r", Status); break; } } return Status; }
执行结果如下:
控制台错误处理
控制台错误处理一般指的是在nsh脚本中通过判断环境变量lasterror进行的。我们可以进行如下实验:
1. 打开EFI shell,先输出lasterror的状态
2. 随意输入一串字符,然后回车,会提示无法识别的命令,此时再打印lasterror的状态
可看到,出错后lasterror变量会被置为非0值,该值对应于EFI_STATUS所定义的错误代码,部分如下:
下面是一个nsh脚本,运行上例HelloWorld.efi,然后输出运行结果:
@echo -off HelloWorld.efi if %lasterror% == 0 then echo Program run successfully! else echo Program exit with an error: %lasterror% endif
扩展
退出码不单单在EFI中用到,大多数的程序都是有这种机制的。比如在Windows中,在控制台执行一个命令,或运行一个程序,其退出码会写在errorlevel变量中,那我们就可以根据它来判断脚本后续的执行流程。一个简单的例子,如用脚本调用FPT刷BIOS,刷完后执行reset。
FPTW64.EXE -F xxx.rom IF %errorlevel% == 0 ( FPTW64.EXE -Greset )
实例代码
https://gitee.com/ay123net/uefistudy
版权声明:
作者:bin
链接:https://ay123.net/mystudy/uefi/1491/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论