Added special files /dev/serial and /dev/diskX

merge-requests/1/head
bzt 3 years ago
parent 495cceb264
commit 10a2921883

@ -133,7 +133,6 @@ Because UEFI has no concept of device files nor of symlinks, dirent fields are l
| free | as usual |
| abort | as usual |
| exit | as usual |
| exit_bs | leave this entire UEFI bullshit behind (exit Boot Services) |
| mbtowc | as usual (UTF-8 char to wchar_t) |
| wctomb | as usual (wchar_t to UTF-8 char) |
| mbstowcs | as usual (UTF-8 string to wchar_t string) |
@ -143,11 +142,6 @@ Because UEFI has no concept of device files nor of symlinks, dirent fields are l
| getenv | pretty UEFI specific |
| setenv | pretty UEFI specific |
```c
int exit_bs()
```
Exit Boot Services. Returns 0 on success.
```c
uint8_t *getenv(wchar_t *name, uintn_t *len);
```
@ -181,6 +175,12 @@ Sets an environment variable by `name` with `data` of length `len`. On success r
| getchar | as usual, waits for a key, blocking, stdin only (no redirects) |
| getchar_ifany | non-blocking, returns 0 if there was no key press, UNICODE otherwise |
| putchar | as usual, stdout only (no redirects) |
| exit_bs | leave this entire UEFI bullshit behind (exit Boot Services) |
```c
int exit_bs()
```
Exit Boot Services. Returns 0 on success.
File open modes: `L"r"` read, `L"w"` write, `L"a"` append. Because of UEFI peculiarities, `L"wd"` creates directory.
@ -192,6 +192,18 @@ defined otherwise), except for the variants which have a maxlen argument. For co
`efi_physical_address_t` as argument, and it dumps memory, 16 bytes or one line at once. With the padding
modifier you can dump more lines, for example `%5D` gives you 5 lines (80 dumped bytes).
Special "device files" you can open:
| Name | Description |
|---------------------|----------------------------------------------------|
| `/dev/stdin` | returns ST->ConIn |
| `/dev/stdout` | returns ST->ConOut, fprintf |
| `/dev/stderr` | returns ST->StdErr, fprintf |
| `/dev/serial(baud)` | returns Serial IO protocol, fread, fwrite, fprintf |
| `/dev/disk(n)` | returns Block IO protocol, fread, fwrite |
With disk devices, `fread` and `fwrite` arguments look like this: fread(ptr, buffer size, lba number, stream).
### string.h
| Function | Description |

@ -31,6 +31,9 @@
#include <uefi.h>
static efi_file_handle_t *__root_dir = NULL;
static efi_serial_io_protocol_t *__ser = NULL;
static efi_block_io_t **__blk_devs = NULL;
static uintn_t __blk_ndevs = 0;
void __stdio_seterrno(efi_status_t status)
{
@ -45,14 +48,34 @@ void __stdio_seterrno(efi_status_t status)
int fclose (FILE *__stream)
{
efi_status_t status = __stream->Close(__stream);
efi_status_t status = EFI_SUCCESS;
uintn_t i;
if(__stream == stdin || __stream == stdout || __stream == stderr || (__ser && __stream == (FILE*)__ser)) {
free(__stream);
return 1;
}
for(i = 0; i < __blk_ndevs; i++)
if(__stream == (FILE*)__blk_devs[i]) {
free(__stream);
return 1;
}
status = __stream->Close(__stream);
free(__stream);
return !EFI_ERROR(status);
}
int fflush (FILE *__stream)
{
efi_status_t status = __stream->Flush(__stream);
efi_status_t status = EFI_SUCCESS;
uintn_t i;
if(__stream == stdin || __stream == stdout || __stream == stderr || (__ser && __stream == (FILE*)__ser)) {
return 1;
}
for(i = 0; i < __blk_ndevs; i++)
if(__stream == (FILE*)__blk_devs[i]) {
return 1;
}
status = __stream->Flush(__stream);
return !EFI_ERROR(status);
}
@ -61,12 +84,17 @@ int __remove (const wchar_t *__filename, int isdir)
efi_status_t status;
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
efi_file_info_t info;
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t);
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), i;
FILE *f = fopen(__filename, L"r");
if(f == stdin || f == stdout || f == stderr) {
if(f == stdin || f == stdout || f == stderr || (__ser && f == (FILE*)__ser)) {
errno = EBADF;
return -1;
return 1;
}
for(i = 0; i < __blk_ndevs; i++)
if(f == (FILE*)__blk_devs[i]) {
errno = EBADF;
return 1;
}
if(isdir != -1) {
status = f->GetInfo(f, &infGuid, &fsiz, &info);
if(EFI_ERROR(status)) goto err;
@ -103,7 +131,7 @@ FILE *fopen (const wchar_t *__filename, const wchar_t *__modes)
efi_simple_file_system_protocol_t *sfs = NULL;
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
efi_file_info_t info;
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t);
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), par, i;
if(!__filename || !*__filename || !__modes || !*__modes) {
errno = EINVAL;
@ -122,6 +150,46 @@ FILE *fopen (const wchar_t *__filename, const wchar_t *__modes)
if(__modes[0] == L'r') { errno = EPERM; return NULL; }
return stderr;
}
if(!memcmp(__filename, L"/dev/serial", 22)) {
par = atol(__filename + 11);
if(!__ser) {
efi_guid_t serGuid = EFI_SERIAL_IO_PROTOCOL_GUID;
status = BS->LocateProtocol(&serGuid, NULL, (void**)&__ser);
if(EFI_ERROR(status) || !__ser) { errno = ENOENT; return NULL; }
}
__ser->SetAttributes(__ser, par > 9600 ? par : 115200, 0, 1000, NoParity, 8, OneStopBit);
return (FILE*)__ser;
}
if(!memcmp(__filename, L"/dev/disk", 18)) {
par = atol(__filename + 9);
if(!__blk_ndevs) {
efi_guid_t bioGuid = EFI_BLOCK_IO_PROTOCOL_GUID;
efi_handle_t *handles = NULL;
uintn_t handle_size = 0;
do {
handle_size += 16;
handles = realloc(handles, handle_size);
status = BS->LocateHandle(ByProtocol, &bioGuid, NULL, handle_size, handles);
} while(status == EFI_BUFFER_TOO_SMALL);
if(!EFI_ERROR(status) && handles) {
handle_size /= (uintn_t)sizeof(efi_handle_t);
__blk_devs = (efi_block_io_t**)malloc(handle_size * sizeof(efi_block_io_t*));
if(__blk_devs) {
for(i = __blk_ndevs = 0; i < handle_size; i++)
if(!EFI_ERROR(BS->HandleProtocol(handles[i], &bioGuid, (void **) &__blk_devs[__blk_ndevs])) &&
__blk_devs[__blk_ndevs] && __blk_devs[__blk_ndevs]->Media &&
__blk_devs[__blk_ndevs]->Media->BlockSize > 0)
__blk_ndevs++;
} else
__blk_ndevs = 0;
free(handles);
}
}
if(par >= 0 && par < __blk_ndevs)
return (FILE*)__blk_devs[par];
errno = ENOENT;
return NULL;
}
if(!__root_dir && LIP) {
status = BS->HandleProtocol(LIP->DeviceHandle, &sfsGuid, (void **)&sfs);
if(!EFI_ERROR(status))
@ -155,13 +223,27 @@ err: __stdio_seterrno(status);
size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream)
{
uintn_t bs = __size * __n;
uintn_t bs = __size * __n, i;
efi_status_t status;
if(__stream == stdin || __stream == stdout || __stream == stderr) {
errno = ESPIPE;
return 0;
}
status = __stream->Read(__stream, &bs, __ptr);
if(__ser && __stream == (FILE*)__ser) {
status = __ser->Read(__ser, &bs, __ptr);
} else {
for(i = 0; i < __blk_ndevs; i++)
if(__stream == (FILE*)__blk_devs[i]) {
status = __blk_devs[i]->ReadBlocks(__blk_devs[i], __blk_devs[i]->Media->MediaId, __n, __size, __ptr);
if(EFI_ERROR(status)) {
__stdio_seterrno(status);
return 0;
}
return ((__size + __blk_devs[i]->Media->BlockSize - 1) / __blk_devs[i]->Media->BlockSize) *
__blk_devs[i]->Media->BlockSize;
}
status = __stream->Read(__stream, &bs, __ptr);
}
if(EFI_ERROR(status)) {
__stdio_seterrno(status);
return 0;
@ -171,13 +253,27 @@ size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream)
size_t fwrite (const void *__ptr, size_t __size, size_t __n, FILE *__stream)
{
uintn_t bs = __size * __n;
uintn_t bs = __size * __n, i;
efi_status_t status;
if(__stream == stdin || __stream == stdout || __stream == stderr) {
errno = ESPIPE;
return 0;
}
status = __stream->Write(__stream, &bs, (void *)__ptr);
if(__ser && __stream == (FILE*)__ser) {
status = __ser->Write(__ser, &bs, (void*)__ptr);
} else {
for(i = 0; i < __blk_ndevs; i++)
if(__stream == (FILE*)__blk_devs[i]) {
status = __blk_devs[i]->WriteBlocks(__blk_devs[i], __blk_devs[i]->Media->MediaId, __n, __size, (void*)__ptr);
if(EFI_ERROR(status)) {
__stdio_seterrno(status);
return 0;
}
return ((__size + __blk_devs[i]->Media->BlockSize - 1) / __blk_devs[i]->Media->BlockSize) *
__blk_devs[i]->Media->BlockSize;
}
status = __stream->Write(__stream, &bs, (void *)__ptr);
}
if(EFI_ERROR(status)) {
__stdio_seterrno(status);
return 0;
@ -191,11 +287,20 @@ int fseek (FILE *__stream, long int __off, int __whence)
efi_status_t status;
efi_guid_t infoGuid = EFI_FILE_INFO_GUID;
efi_file_info_t *info;
uintn_t infosiz = sizeof(efi_file_info_t) + 16;
uintn_t infosiz = sizeof(efi_file_info_t) + 16, i;
if(__stream == stdin || __stream == stdout || __stream == stderr) {
errno = ESPIPE;
return -1;
}
if(__ser && __stream == (FILE*)__ser) {
errno = EBADF;
return -1;
}
for(i = 0; i < __blk_ndevs; i++)
if(__stream == (FILE*)__blk_devs[i]) {
errno = EBADF;
return -1;
}
switch(__whence) {
case SEEK_END:
status = __stream->GetInfo(__stream, &infoGuid, &infosiz, info);
@ -221,11 +326,21 @@ int fseek (FILE *__stream, long int __off, int __whence)
long int ftell (FILE *__stream)
{
uint64_t off = 0;
uintn_t i;
efi_status_t status;
if(__stream == stdin || __stream == stdout || __stream == stderr) {
errno = ESPIPE;
return -1;
}
if(__ser && __stream == (FILE*)__ser) {
errno = EBADF;
return -1;
}
for(i = 0; i < __blk_ndevs; i++)
if(__stream == (FILE*)__blk_devs[i]) {
errno = EBADF;
return -1;
}
status = __stream->GetPosition(__stream, &off);
return EFI_ERROR(status) ? -1 : (long int)off;
}
@ -235,13 +350,22 @@ int feof (FILE *__stream)
uint64_t off = 0;
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
efi_file_info_t info;
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t);
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), i;
efi_status_t status;
int ret;
if(__stream == stdin || __stream == stdout || __stream == stderr) {
errno = ESPIPE;
return 0;
}
if(__ser && __stream == (FILE*)__ser) {
errno = EBADF;
return 0;
}
for(i = 0; i < __blk_ndevs; i++)
if(__stream == (FILE*)__blk_devs[i]) {
errno = EBADF;
return 0;
}
status = __stream->GetPosition(__stream, &off);
if(EFI_ERROR(status)) {
err: __stdio_seterrno(status);
@ -487,16 +611,23 @@ int printf(const wchar_t* fmt, ...)
int vfprintf (FILE *__stream, const wchar_t *__format, __builtin_va_list args)
{
wchar_t dst[BUFSIZ];
uintn_t ret;
uintn_t ret, bs, i;
if(__stream == stdin) return 0;
ret = vsnprintf(dst, sizeof(dst), __format, args);
if(ret < 1) return 0;
for(i = 0; i < __blk_ndevs; i++)
if(__stream == (FILE*)__blk_devs[i]) {
errno = EBADF;
return -1;
}
if(__stream == stdout)
ST->ConOut->OutputString(ST->ConOut, (wchar_t*)&dst);
else if(__stream == stderr)
ST->StdErr->OutputString(ST->StdErr, (wchar_t*)&dst);
else if(__ser && __stream == (FILE*)__ser)
__ser->Write(__ser, &ret, (void*)&dst);
else
__stream->Write(__stream, &ret, (wchar_t*)&dst);
__stream->Write(__stream, &ret, (void*)&dst);
return ret;
}
@ -534,3 +665,22 @@ int putchar (int __c)
ST->ConOut->OutputString(ST->ConOut, (__c == L'\n' ? (wchar_t*)L"\r\n" : (wchar_t*)&tmp));
return (int)tmp[0];
}
int exit_bs()
{
efi_status_t status;
efi_memory_descriptor_t *memory_map = NULL;
uintn_t cnt = 3, memory_map_size=0, map_key=0, desc_size=0, i;
if(__blk_devs) {
free(__blk_devs);
__blk_devs = NULL;
__blk_ndevs = 0;
}
while(cnt--) {
status = BS->GetMemoryMap(&memory_map_size, memory_map, &map_key, &desc_size, NULL);
if (status!=EFI_BUFFER_TOO_SMALL) break;
status = BS->ExitBootServices(IM, map_key);
if(!EFI_ERROR(status)) return 0;
}
return (int)(status & 0xffff);
}

@ -120,21 +120,6 @@ void exit (int __status)
BS->Exit(IM, !__status ? 0 : (__status < 0 ? EFIERR(-__status) : EFIERR(__status)), 0, NULL);
}
int exit_bs()
{
efi_status_t status;
efi_memory_descriptor_t *memory_map = NULL;
uintn_t cnt = 3, memory_map_size=0, map_key=0, desc_size=0;
while(cnt--) {
status = BS->GetMemoryMap(&memory_map_size, memory_map, &map_key, &desc_size, NULL);
if (status!=EFI_BUFFER_TOO_SMALL) break;
status = BS->ExitBootServices(IM, map_key);
if(!EFI_ERROR(status)) return 0;
}
return (int)(status & 0xffff);
}
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, __compar_fn_t cmp)
{
uint64_t s=0, e=nmemb, m;

@ -1011,7 +1011,7 @@ typedef struct {
efi_serial_io_mode_t *Mode;
} efi_serial_io_protocol_t;
/*** Block IO Protocol (not used, but could be useful to have) ***/
/*** Block IO Protocol ***/
#ifndef EFI_BLOCK_IO_PROTOCOL_GUID
#define EFI_BLOCK_IO_PROTOCOL_GUID { 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} }

Loading…
Cancel
Save