- Use cases
- Implemenation Status
- Source Code
- Goal
- Approach
- Riding the UEFI Shell
- HELLO is now WELCOME:
Howto build hello.c using commandline and Visual Studio 2022
- Known bugs
- Revision history
The toro C Library is a monolithic Standard C Library for UEFI x86-64 target platform for Microsoft Visual Studio 2022.
toro C Library is the successor of "torito C Library". "torito C Library" is discontinued with version 20210820/R166. The main difference is, that toro C Library is build using the Visual Studio 2022 build environment, while "torito C Library" uses an UEFI EDK2 2016 build environment.
Additions of a C Library function set won't be done for "torito C Library" but for its grownup version toro C Library only.
toro C Library is an implementation targeting the ANSI/ISO C Standard Library compatibility to create applications for different operating systems using design –and debug– infrastructure provided by Microsoft Visual Studio 2022 VS2022.
- create menu driven applications for the UEFI shell execution environment
- easily port existing Standard C programs to the UEFI shell execution environment, e.g. the ACPI reference implementation
- easily reimplement MSDOS programs for the UEFI shell execution environment
- quickly implement simple CLI tools for the UEFI shell execution environment
The toro C Library is designed to enable the developer to create Standard C programs for UEFI Shell, Windows NT and Linux (in future releases) running in x86-64 mode. Standard C compliant source code shall be easily portable to operating systems supported by toro C Library.
The toro C Library shall provide full library compatibility with
- ANSI X3.159-1989 ("ANSI C")
- ISO/IEC 9899 First edition 1990-12-15 ("C90")
- ISO/IEC 9899 First edition 1990-12-15, Amendment 1, 1995-04-01 ("C95")
Extensions to these standards (ISO 9899:1999 etc.), secure / bounds checking interface functions xyz_s()
from ISO 9899:2011, Annex K, POSIX functions or Microsoft specific add-ons will be implemented on demand into toro C Library.
Be aware, that functions like ,
a very famous stricmp()
(case sensitive string handling), itoa()
(integer to string conversion)kbhit()
(check for keystroke at console0),
fopen()-mode-strings like and "rt"
, "wt"
(textmode read/write, just use "r"
, "w"
instead), but not specified by ANSI X3.159-1989 or ISO/IEC 9899:1990, and therefore currently not available in the toro C Library, but will be implemented on demand.open()
(POSIX) are provided in various C-Library-implementations
As long as the developer moves within these standards1 and does not use
any OS-specific interface or platform dependent idiosyncrasy, the created
executable shall be producible merely by linking the object modules against toro C Library
and choosing the OS-dependent /ENTRY:_cdeCRT0OSNAME
, e.g. _cdeCRT0UefiShell
or _cdeCRT0WinNT
.
The C-Standards mentioned above leave some freedom for a particular library implementation; this affects return values that provide flags beside beeing only 'nonzero' as specified or different handling of text vs. binary mode for file operations.
C-Library vendors usually describe their own specific details, but not the Standard C requirements. Using and relying on such implementation-specific details makes the source code non-portable to other C-Libraries, e.g. GLIBC.
The toro C Library is intended to be identical in all aspects to functions specified in ANSI C, C90 and C95 provided in LIBCMT.LIB that comes with VS2022. (It is assumed, that LIBCMT.LIB of VS2022 is compliant to aforementioned standards.)
Microsoft C Language Reference
Doing so, the development of toro C Library itself is unburdened from the exegesis of the specifications mentioned above and the creation of the required header files -- the header files delivered with VS2022 are utilized instead.
The developer using toro C Library benefits from this approach because the experience remains unchanged using the VS2022 environment.
With the disappearance of MSDOS as a simple, single threaded, unprotected operating system with full hardware access to user programs on upcoming personal computer models the UEFI shell was intended to be the successor of MSDOS.
But the lack of an established, well known programming interface (as is the Standard C library) makes it cumbersome to get started on UEFI Shell programming.
The sole purpose of toro C Library for WinNT is to validate the C library compatibility on a Windows-x64-Platform. Usually testprograms are linked once against the original LIBCMT.LIB and then against toro C Library for WinNT to be able to compare program behavior in Windows.4 Most of all bugs and pitfalls can be found quickly, debugged easily and fixed soon, in the build and debug environment of Visual Studio.
It is considered the only effective way to reach the ANSI C compatibility and strive for a faultless implementation within a reasonable amount of time, because by far most parts of each single function test can be run through, debugged and tested natively on the (Windows) development machine. Only final tests need to be run on the UEFI Shell target. This proceeding can be reached only by the OSIF (Operating System Interface) architecture of the library.
//
// WELCOME.c
//
#include <stdio.h>
int main(int argc, char **argv){
printf("WELCOME, to ANSI C\n");
return 0;
}
WELCOME.c can be translated in the VS2022 64Bit command line environment by running the build.bat script below:
@echo off
echo Compiling the C source...
cl /nologo /c /GS- /D_NO_CRT_STDIO_INLINE /D_CRT_SECURE_NO_WARNINGS WELCOME.c
echo Linking the .OBJ to UEFI SHELL Executable WELCOME.EFI
link /nologo /NODEFAULTLIB /ENTRY:_cdeCRT0UefiShell /OUT:welcome.efi /SUBSYSTEM:EFI_APPLICATION WELCOME.obj toroC64.lib
echo Linking the .OBJ to Windows NT Executable WELCOME.EXE
link /nologo /NODEFAULTLIB /ENTRY:_cdeCRT0WinNT /OUT:welcome.exe /SUBSYSTEM:CONSOLE WELCOME.obj toroC64.lib KERNEL32.LIB
With just one additional link-step in the above script, without re-compiling, a Windows NT executable could be created.
If you prefer to use state-of-the-art build environment Visual Studio 2022, please follow the step-by-step-configuration HowTo-configure-VS2022-to-build-.EFI-executables
To run Visual Studio 2022 .EFI samples, check out Visual-ANSI-C-for-UEFI-Shell.
- printf()-family's format specifiers e,f,g2 not yet implemented
- scanf()-family's format specifiers
[],p,e,f,g2,C,S not yet implemented - 20181129:
file operations does not yet support drive mappings and path - 20180107:
strtol()'s/strtoul()'s base parameter accepts only 0d, 8d, 10d, 16d. Letters a�z or A�Z representing digits in the range [10, 36] are not (yet) supported. - <time.h>: UTC-only support. No Daylightsaving, no timezones.
- <locale.h>: C-locale-only support
- <math.h> not yet implemented2
- 20191017:
CTRL-C interception not yet implemented - 20191017:
toro C Library based progams use ASCII console interface only, not UCS-2!ASCII is written tostdout
andstderr
ASCII is read fromstdin
pay attention when dealing with>
,<
,|
and>a
,<a
,|a
shell operators
- improve C++ support for
CDE.H
- enable mixed C/C++ applications based toro C Library using
CDE.H
- enable mixed C/C++ applications based toro C Library using
- fixe SMM issues:
- fix
CdePkg
-based SMM drivers hangs on startup. - fix
CdeServicesSmm.c
failed to build
NOTE: The improvement above doesn't change ANSI-C related behaviour of previous library versions
- fix
- fixed EDK2
DEBUG
trace macro won't crash anymore with UEFI specific (non-ANSI-C) format specifiers: %g, %t and %r
NOTE: The improvement above doesn't change ANSI-C related behaviour of previous library versions
- add timeout detection for disabled COM1/UART at I/O 3F8h used for debug traces.
NOTE: Disabled I/O devices usually do not respond to I/O cycles.
Internally this is done by ignoring the chipselect for that particular I/O address range, e.g. 3F8h .. 3FFh for COM1.
FFh is driven to the data bus when reading registers of those disabled devices.
On special implementations hardware designers chose a different approach to disabled devices:
- address decoding is kept enabled
- internal clock line is stopped or decoupled from internal circuitry
The disadvantage of this aproach is, that status registers are still visible but not updated anymore.
- add ACPI timer based synchronization for toro C Library Shell programs.
NOTE: On recent Intel platforms the previously used legacy timer's (i8254) input clock frequency is
clocked down to an unspecified frequency with setup default
Enable 8254 Clock Gate
. Additionally the I/O latency to access i8254 ports is increased with setup defaultLegacy IO Low Latency
that lowers i8254 based timing precision.
So i8254 gets unusable for UEFI Shell programs on new platforms. - improve synchronization error correction for i8254 based POST drivers (with
Enable 8254 Clock Gate := disable
,Legacy IO Low Latency := enable
)
- fixed: libxlsxwriter based UEFI and Windows applications create .XLSX that can't be opened with Microsoft Excel 2016. Office 365 online (https://www.microsoft365.com) and offline didn't fail.
- fixed:
_strefieerror()
to return error correct string when running in pre-memory PEI
- improve debug trace CDETRACE() configuration switches
#define CDEDBG STDOUT
– traces directed to stdout#define CDEDBG STDERR
– traces directed to stderr#define CDEDBG STDDBG
– traces directed to CDE debug channel, normally COM1, I/O 0x3F8 115200,8,n,1CDEDBG
undefined – UEFI Shell/post DRIVERS: STDDBG, Windows NT: STDOUT
-
add
CDE
(C Development Environment)-interface for native Tianocore UEFI SHELLUEFISHELLDRV
.
Enable Toro-C-Library–DXE
function set atCRT0()
and full Toro-C-Library–SHELL
function set with availability of theEfiShellProtocol
/EFI_SHELL_PROTOCOL_GUID
:
https://github.com/KilianKegel/Visual-TORO-C-LIBRARY-for-UEFI/tree/main/toroCLibrary/OSInterface/UEFISHELLDRVThis is the foundation of an ANSI-C-API-extended "CDE UEFI SHELL"
-
prepare
system()
ANSI-C-API call for MSDOS drive name support (A:, B:, C: ...) coming soon for Visual-UEFI-SHELL -
update
MdePkg
to version edk2-stable202308 -
improve
CDEABI
(C Development Environment Application Binary Interface)- force all
Core
and operating system interfaceosif
modules to uses exclusively ANSI-C-API onCDEABI
to avoid collision with EDK2StdLibC
and relatives
primarily remainingerrno()
,setjmp()
,longjmp()
,strlen()
,strcpy()
,strcmp()
,wcslen()
,wcscpy()
,wcscmp()
- force all
-
improve
freopen()
to set redirection flagO_CDEREDIR
to speed up character transission to file -
fix
fscanf()
: assignment suppression indicated by a "*": https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=295 -
fix
raise()
-
INTERN:
- add:
size_t _cdeInt2EfiStatus(int intstatus)
- add:
int _cdeEfiStatus2Int(size_t Status)
- move selected file functions to
CdeAppIf
driver side.
This allows future/upcoming code size reduced shell application type. - preliminary: LINUX-OSIF buildable, ALPHA
- preliminary:
osifCdeUefiShellAppEntryPoint()
,osifCdeUefiShellAppCRT0Service()
for future/upcoming shell application type that doesn't include entireCdeAppIf
machine code to each .EFI application, but shareCdeAppIf
provided by a CDE UEFI SHELL. This allows code size reduced applications.
- add:
- add Standard C95 Library functions:
- add Microsoft C Library functions from
mbctype.h
: - fixed:
printf()
/wprintf()
-family handling of wide characters > value 255 - adjust internal
invalid_parameter_handler()
to suppress additional debug/file information - fixed:
wcsxfrm()
/strxfrm()
addinvalid_parameter_handler()
support as original Microsoft C Library
- fixed: in the pre-Memory-Discovered PEI (Pre Efi Initialization) POST x86-32
Standard C function
localeconv()
crashed the platform.
NOTE: All x86-64 operation modes (UEFI Shell, UEFI SMM, UEFI DXE, Windows NT) and post-Memory-Discovered PEI (Pre Efi Initialization) x86-32 was not affected by that bug.
NOTE: This release 20230409 doesn't change UEFI Shell programs behavior
The improvements provided here only affects PEI drivers, based on toro C Library/CdePkg listed below:
-
add Memory Discovered handling for PEIM (Pre-EFI Initialization Module)
- restart memory management when switching from CAR (Cash As RAM) to permanent memory
- reassign
CDE_SERVICES
pointer when switching from CAR (Cash As RAM) to permanent memory
-
support of multi-invocation of
CdePkg
-based PEIM-
NOTE: Each
CdePkg
-based PEIM needs a small, read-/writeable, dedicated static duration to provide Standard C Library compliance (e.g. to holdatexit()
-registered function pointers, the internalstrtok()
pointer, therand()
next, the jump buffer, the I/O buffer forstdin
,stdout
andstderr
...).Internally this is provided in the HOB storage area and holds a
CDE_APP_IF
protocol registered with the driver specificgEfiCallerIdGuid
. HOB storage is available early in POST in PEI (Pre-EFI Initialization).Once a PEIM is started multiple times, only the first instance static duration will be reinitialized with current
EFI_PEI_FILE_HANDLE
,EFI_PEI_SERVICES
and the currentCDE_SERVICES
pointer.This proceeding prevents
LocatePpi()
to return an invalid pointer to the first instance, while a second instance is currently active.
-
-
improve
CDEABI
(C Development Environment Application Binary Interface), used as collision avoidance with EDK2StdLibC
and relatives
NOTE: In real-world UEFI implementations various components provide "reduced"(mildly put) Standard C Interface just fitting the requirements of that particular package (CryptoPkg
,RedfishPkg
).To avoid symbol double definitions at link time or link order failures with EDK2
StdLibC
,CDEABI
:- provides Standard C Functions in their
__declspec(dllimport)
incarnation only - except for Microsoft compiler intrinsics
__cdecl memset()
and__cdecl memcmp()
that are paired with the its__declsspec(dllimport)
counterpart in the same COMDAT (same .OBJ module)
- provides Standard C Functions in their
- fixed
strtok()
,wcstok()
-
introduce
CDEABI
, an additional application binary interface ABI to ease coexistance ofCdePkg
based BIOS drivers with incomplete tianocore EDK2C Library
fragmentsNOTE:
CDEABI
uses the Microsoft DLL interface__declspec(dllimport)
for EDK2-built drivers . Technically this uses indirect function calls on machine code level. -
promote
CDETRACE()
, remove former, alternate trace method (CDEMOFINE()
) completely
- fixed
strftime()
parameter:%I
,%m
,%x
- add Microsoft/POSIX C Library functions:
_isatty()
- imitate funny/buggy Microsoft behaviour for
fopen()
withfmode
parameterw+
ora
:
function terminates successfully witherrno
set to 22,Invalid argument
- imitate funny/buggy Microsoft behaviour for
_fileno()
with invalid filepointer:
MSFT:_fileno(-1)
just crashes by an invalid memory access
This behaviour is imitated by anexit(3)
invocation - fixed application crash at termination when a redirected I/O stream
STDERR
is reopened withreopen()
- improve existing invalidate parameter handling; enable file name string, function name string, line number string and expression string
at RELEASE runtime
NOTE: Microsoft enables this feature only when using DEBUG version of LIBCMT.LIB.
- add O_TEMPORARY support to Microsoft/POSIX _open()
- fixed "fall time bug" (autumn). Broken time calculation on two digit month number (Oct, Nov, Dec).
- add Standard C90 Library functions:
wcstoul()
wcstol()
- add Standard C99 Library functions:
strtoull()
strtoll()
strtoimax()
strtoumax()
wcstoull()
wcstoll()
wcstoimax()
wcstoumax()
- add Microsoft/POSIX C Library functions:
_ultow()
_ultoa()
_ui64tow()
_ui64toa()
_ltow()
_ltoa()
_itow()
_itoa()
_i64tow()
_i64toa()
- implement full
__chkstk()
for Windows 32Bit: https://docs.microsoft.com/en-us/windows/win32/devnotes/-win32-chkstk - fixed stdout/stderr redirection
>
and>>
didn't work anymore (since20220501
) - fixed
"a"
/O_APPEND
append file open attribute didn't work anymore (since20220501
) - fixed
ftell()
/fgetpos()
reports wrong offset after writing to"a"
/O_APPEND
opened files
- fixed:
free()
and C++ operatordelete()
crash to freeNULL
pointer
- add C++ minimum support
void* operator new(size_t size)
void* operator new[](size_t size)
void operator delete[](void* ptr)
void operator delete(void* ptr, unsigned __int64 size)
- add Microsoft/POSIX C Library functions:
_open()
_close()
_read()
_write()
_fdopen()
_fileno()
_wfopen()
_fseeki64()
_ftelli64()
- fixed
errno
values for file position functions with negative offsets (fsetpos()
,fseek()
) - fixed UEFI BUG: gap of non-initialized disk space
File positioning bug, if data written behind EOF, data range between old EOF and new data contains medium data / garbage, instead of 0 - simplify
CDETRACE()
implemantation, improve portability of thatCdePkg
specific debug macro - add
_strefierror()
: rename Toro-C-Library UEFI-specific functionstrefierror()
to ANSI C naming convention compatible_strefierror()
- implement full
__chkstk()
for Windows 64Bit: https://docs.microsoft.com/en-us/windows/win32/devnotes/-win32-chkstk - partially implementation of the %G
fprintf()
– format specifier for Visual-LIBXLSXWRITER-for-UEFI-Shell - fixed
fread()
end-of-file indicator not set correctly when EOF is reached within a buffer instead of reading of 0 bytes from the mass storage device - changed exit code of the
abort()
function from 3 to 0xC0000409 - fixed: reassigned (by running
freopen()
) filepointers tostdout
/stderr
are not flushed at exit CdePkg
– SMM Driver: Erroneous message shown at startup:FATAL ERROR : CdeServices SMM not available
- add Standard C Library functions:
strcoll()
strxfrm()
fgetwc()
fputwc()
fputws()
fwide()
fwprintf()
fwscanf()
getwc()
getwchar()
putwc()
putwchar()
swscanf()
ungetwc()
vfwscanf()
vswscanf()
wcscoll()
wcsxfrm()
btowc()
- fix "BINARY MODE" for wide printf()/scanf() family functions
- imitate funny Microsoft behaviour when replacing and pushing back -ungetc()- a character by CTRL-Z to a stream (in that case the stream is not terminated)
- fix fscanf() family return value for "event of an early matching failure" http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf#page=299
- introduce
CDETRACE()
debug/trace macro that is parameter checked at build time - improve
wmain()
support; now selected at build time by choosing the CRT0 entry point name_cdeCRT0UefiShellW()
_cdeCRT0WinNTW()
NOTE: The*env
pointer is not passed towmain()
- fixed: UEFI Shell overwrites the last line of text of a previously terminated application with its prompt
- add: fgetws()
- add
wmain()
support
ATTENTION: The presence ofmain()
is not detected at build time anymore, but at runtime.
- add Microsoft specific
fopen()
mode string modifier"t"
for text mode- NOTE:
"t"
modifier is not defined by ANSI/ISO C, because binary/text mode differentiation is done by"w"
modifier only.
- NOTE:
- fix
fclose()
bug in UEFI shell returns an error, when closing a read only file
-
add Microsoft C Library functions for UEFIShell 64Bit applications only
_mkdir()
_stat64i32()
that is the Microsoft version of POSIXstat()
add POSIX C Library functions
strnlen()
,wcsnlen()
- initial version of TORO C LIBRARY (
toroC64.lib
andtoroC32.lib
) - TORITO C LIBRARY is discontinued from now on
- add Microsoft C Library functions for UEFIShell applications only
getc()
_findfirst()
_findnext()
_findclose()
- add Standard C Library functions
mblen()
mbstowcs()
mbtowc()
wcstombs()
wctomb()
wctob()
wmemchr()
vfwprintf()
- fixed time calibration issue on AMD (Ryzen7, A6)
- on AMD systems the RTC device sporadically loses the PF (periodic interrupt) flag from RTC register 0x0C
- instead PIT 8254 timer seems to be reliable on AMD and Intel platforms
- fixed bugs related to length modifiers for string format specifiers
wprintf()
with%ls
,%hs
and Microsoft specific%S
printf()
with%ls
,%hs
and Microsoft specific%S
- the string
(null)
was reported wrongly in wide format onNULL
pointer (e.g.wprintf()
or%ls
modifier)
- fixed "" at end of commandline not detected by command line parser
- fixed improved stability of TSC based TIME.H functions, improved TSC calibration
- force minimum ShellProtocol version to v2.2
- fixed Torito C Library for NT redirects STDOUT to file always beginning to file begin, instead of file end That overwrites a logfile used for multiple redirected traces
- add VS2019/16.4.4 support
- update copyright
- improve C++ global object initialization (introduced in 20181129/R116) to have full
ANSI C library function set available during invocation of global constructors before main()
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/initterm-initterm-e?view=vs-2017
https://github.com/KilianKegel/Visual-ANSI-C-for-UEFI-Shell/blob/master/welcome10/welcome10.cpp - increase number of possible ATEXIT() registrations to 32 + 4 to allow 4 additional C++ destructor registrations
- fixed Torito C library CRT0 for Windows NT data corruption may crash the application
- fixed functions snprintf() and vsnprintf() return value:
number of characters that would have been written had n been sufficiently large
- add missing intrinsic functions _difftime64() and _gmtime64() required by Microsoft Compiler
- fixed mktime() to crash with invalid time/date before 01/01/1970 00:00:00
- add CTRL-C support
NOTE: CTRL-C is implemented on Signal handling<signal.h>
interface and can be catched and supressed by the application. https://github.com/KilianKegel/Visual-ANSI-C-for-UEFI-Shell/blob/master/welcome9/welcome9.c - fixed system() library function does not workaround completely fully the EfiShellProtocol->Execute() bug to display the drive mappings, when multipartition ("BLK10") mass storage device is attached
- implement UEFI Shell compatibility mode for STDOUT and STDERR to allow I/O redirection
>a
for ASCII and>
for UCS-2/UTF16 - add build switch
char _gSTDOUTMode = 1; /* 0 == UEFI Shell default, 1 == ASCII only */
to force TORITO C backward compatibility ( ASCII mode only ) - autodetect I/O redirection UTF16 vs. ASCII
- update copyright
- add VS2019 compatibility, remove library dependancy from compiler version
- fixed: scanf() related functions fails to terminate tokens, e.g. sscanf("123:456","%d:%d",&n1,&n2)
- fixed: qsort() fails if number of elements (nmemb) is 0
- add _wassert() required by newer assert-macro implementations
-
fixed single '\r', ASCII 0x0D, carriage return, that appears w/o '\n', ASCII 0x0A, line feed in a file, opened in text mode, is handled wrongly.
NOTE: ftell(), fgetpos(), fsetpos() in textmode is implemented differently. Unable to reimplement LIBCMT.lib bugs, when '\n' or Ctrl-Z is present in the text file
fposbug.c
- add getenv()
- add rename()
- add <locale.h> related: setlocale(), localeconv() - supporting C-locale only
- add missing memchr() from string.h
- add <wctype.h> related functions: iswalnum(), iswalpha(), iswblank(), iswcntrl(), iswctype(), iswdigit(), iswgraph(), iswlower(), iswprint(), iswpunct(), iswspace(), iswupper(), iswxdigit(), towctrans(), towlower(), towupper(), wctrans(), wctype()
- add _initterm support, methods called internally during the initialization of a C++ program, according to https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/initterm-initterm-e?view=vs-2017
- add drive and path support to fopen()
- add %[] scanset format specifier to scanf-family
- add %p pointer format specifier to scanf-family
- fixed token count bug in scanf-family
- add VS2017/15.8 support (Just My Code)
- add system() library function
- improved stability of memory management
- add qsort(), vsscanf()
- fixed calloc()
- added WELCOME.c sample
- added BUILD.BAT sample
- add signal(), raise() and abort() functions3
- fixed argc/argv handling according to https://msdn.microsoft.com/en-us/library/a1y7w461.aspx
- added getchar(), remove(), tmpfile(), tmpnam()
- fixed: strol() and stroul() doesn't support base 2..36 required by the Standard C Library
- fixed: time() function N/A in Windows build
- fixed: time base in Windows build is QPC now, not TSC.
- fixed: gets() functions fails with lines starting with '\n'
- initial revision