This week, I updated the firmware on the Minnowboard Turbot to the latest release, and struggled with creating a UEFI application using standard ‘C’ functions.
I subscribe to the @Minnowboard Twitter feed, and received a notice from @Intel_Brian that a new version of the firmware was available for download, and that it came highly recommended. So, as I last did in Episode 4, I downloaded the full source tree and built the v0.95 image via the detailed instructions available with the release.
This time, I decided to build a Release version of the firmware, rather than the Debug version. The Debug version was quite interesting to work with, because it streamed out the BIOS printf messages to the CoolTerm application on my Mac via the Minnowboard serial port. It was enlightening to look at some of these messages and trace them back to the source code, and see what it was doing at various stages of the boot process. But, the Debug image takes a lot longer to boot (55 seconds, as opposed to a few seconds for the Release version), so in the interest of saving time, since I was rebooting the platform a lot, I tried the Release version.
Alas, I found out that the default build options of the Build_IFWI.bat command running under the Developer Command Prompt for VS2013 yielded a build without the necessary symbols and source links. So, when I fired up SourcePoint to continue my explorations, all I could see was assembly code. This wouldn’t allow me to continue my learnings about the UEFI internals, so I fell back again to building a Debug version and reflashing the Minnowboard with this release.
In Episode 11, I built and ran a simple UEFI “Hello World” shell script. And in Episode 12, I undertook the more complicated development of a real UEFI application. The latter is a precursor for building more sophisticated tools like drivers. But it involves a more complicated build process and requires a deeper understanding of the source tree file structure. Nonetheless, I succeeded in creating a simple “Hello World” application using the built-in UEFI “print” function, which is like “printf” in that it outputs the string to the standard console device.
The Harnessing the UEFI Shell book that I purchased refers to writing UEFI applications using standard ‘C’ member functions. It seemed to be a simple matter of doing for example a #include <stdio.h> at the front end of the code, and then feeling free to use the standard ‘C’ functions that I’m familiar with. Now, that seemed like a good prospect for learning something new: I could develop a few more sophisticated applications using the built-in ‘C’ functions I’m comfortable with, and then graduate later to a deeper understanding of the UEFI-specific functions. My new MyHelloWorld2.c application using this approach looked like this:
main(int arg, char **argv)
Looks familiar, right?
And the setup file for this application, MyHelloWorld2.inf, looks like:
# .inf file for MyHelloWorld2
INF_VERSION = 0x00010005
BASE_NAME = MyHelloWorld2
FILE_GUID = 721f92fb-43f7-49b4-9a2a-142eac0d49ac
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
# The following information is for reference only and not required by the build.
VALID_ARCHITECTURES = X64
Alas (and I realize this is the second “alas” within this article), after numerous attempts, I never could get this to successfully compile, always getting errors of the type Error 4000: Instance of library class [LibCType] is not found:
I suspect that I’m missing something out of the .dsc file that’s part of the build, but I’m not sure at the moment. I’ll return to this in a future exploration. Any ideas on how to proceed would be appreciated!
And now, a word from our sponsor: do you want to learn more about debugging UEFI applications? Check out this whitepaper here: UEFI Framework Debugging (note: requires registration).