I'm writing an application that works from efi environment (f.e. can be run from EFI shell).
My problem is that I cannot create any file on my machine's volume. I tested it on WMVare and on real machines with ntfs and even on mac with hfs+ (got drivers frim http://efi.akeo.ie/). I can read everything, but when I try to write I got error code 8 (EFI_WRITE_PROTECTED).
Is there any way to avoid this protection? Maybe I should go deeper and work with block devices instead of file systems (don't really want to do this)?
My code. Driver Loading (I think it works fine, just for the case):
Print(L"\nLoading NTFS Driver... ");
Status = BS->LocateHandleBuffer(ByProtocol, &FileSystemProtocol, NULL, &NumHandles, &Handle);
if (EFI_ERROR(Status))
{
PrintStatusError(Status, L"\n Failed to list file systems");
goto exit;
}
for (i = 0; i < NumHandles; i++)
{
// Look for our NTFS driver. Note: the path MUST be specified using backslashes!
DevicePath = FileDevicePath(Handle[i], DriverPath);
if (DevicePath == NULL)
continue;
// Attempt to load the driver. If that fails, it means we weren't on the right partition
Status = BS->LoadImage(FALSE, ImageHandle, DevicePath, NULL, 0, &DriverHandle);
SafeFree(DevicePath);
if (EFI_ERROR(Status))
continue;
// Load was a success - attempt to start the driver
Status = BS->StartImage(DriverHandle, NULL, NULL);
if (EFI_ERROR(Status))
{
PrintStatusError(Status, L"\n Driver did not start");
goto exit;
}
Print(L"LOADED");
break;
}
SafeFree(Handle);
if (i >= NumHandles)
{
Print(L"\n Failed to locate driver. Please check that '%s' exists on the FAT partition", DriverPath);
Status = EFI_NOT_FOUND;
goto exit;
}
File reading/writing:
// Now enumerate all disk handles again
Status = BS->LocateHandleBuffer(ByProtocol, &DiskIoProtocol, NULL, &NumHandles, &Handle);
if (EFI_ERROR(Status))
{
PrintStatusError(Status, L"\n Failed to list disks");
goto exit;
}
// Go through the partitions and find the NTFS one
for (i = 0; i < NumHandles; i++)
{
dev_path = DevicePathFromHandle(Handle[i]);
Print(L"\nVolume [%d]: ", i);
// Calling ConnectController() on a handle starts all the drivers that can service it
Status = BS->ConnectController(Handle[i], NULL, NULL, TRUE);
if (Status == EFI_SUCCESS)
{
Print(L"Driver connected! ");
}
// Open the the volume
Status = BS->HandleProtocol(Handle[i], &FileSystemProtocol, (VOID**)&Volume);
if (EFI_ERROR(Status))
{
PrintStatusError(Status, L"\n Could not find volume");
continue;
}
// Open the root directory
Root = NULL;
Status = Volume->OpenVolume(Volume, &Root);
if ((EFI_ERROR(Status)) || (Root == NULL))
{
PrintStatusError(Status, L"\n Could not open Root directory");
continue;
}
Status = Root->Open(Root, &FileHandle, L"bb.txt", EFI_FILE_MODE_READ, 0);
Print(L"\n Read %d", Status);
if (Status == EFI_SUCCESS)
{
UINTN fsize = 5;
char fdata[5];
Status = FileHandle->Read(FileHandle, &fsize, fdata);
fdata[4] = 0;
Print(L" %d [%x%x%x%x] ", Status, fdata[0], fdata[1], fdata[2], fdata[3]);
FileHandle->Close(FileHandle);
}
Status = Root->Open(Root, &FileHandle, L"aa.txt", EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
Print(L" Create %d", Status);
if (Status == EFI_SUCCESS)
{
UINTN fsize = 4;
Status = FileHandle->Write(FileHandle, &fsize, file_content);
Print(L" Wr %d", Status);
Status = FileHandle->Flush(FileHandle);
Print(L" Fl %d", Status);
Status = FileHandle->Close(FileHandle);
Print(L" Cl %d", Status);
}
}
<---------------- after a bit of investigation ------------------------>
It turned out that the only thing we can do with machine's file system is to change existing file content. Seems like it is the only possible way without monthes of research. But still, its not easy to do:
I have "EFI_FILE *fileHandle" variable and can read mine pre-created file. How to find corresponding LBA (or offset for DiskIO)?
I looked to EFI sources (from AMI bios sources) and found that there are hidden data placed right after EFI_FILE struct:
typedef struct _FILE_HANDLE_INSTANCE {
EFI_FILE_PROTOCOL FileHandle; // Should be the first entry in the structure
EFI_STATUS HandleInstanceStatus;
FILE_HANDLE *pFH;
UINT64 OpenMode; // Open Modes
UINT64 Position; //
UINT32 CurrentCluster; // will point to sector number where the position is pointing currently
UINT32 CurrentClusterOffset; // will point to sector number where the position is pointing currently
BOOLEAN MEDIA_NOT_VALID; // Will be true if for any reason current instances cannot use the volume Eg: Change in Media
DLINK ViFILink; // This link is for the DLIST OpenFIs in the VOLUME_INFO
} FILE_HANDLE_INSTANCE;
And they operate with it like this:
void example_read_inside_efi(EFI_FILE *FileHandle, ...)
{
FILE_HANDLE_INSTANCE *fhi = (FILE_HANDLE_INSTANCE *)FileHandle;
...
But when I try to read that struct, it don't seem that this struct has right field values (f.e. FILE_HANDLE pointer is not valid). I don't know what to do with this next. Have no ideas..
So, the question is: how can i find corresponding LBA (or offset for diskIO) if I have valid EFI_FILE pointer?
Related
I'm working on a embedded linux system (yocto based) and I'm trying to simply get a list of the camera USB video devices (webcams) numbers with the related connected usb port from a C program.
I'm able to get the devices list with vendor ID and connected port doing this:
void usbdevs()
{
libusb_device*** list=NULL;
libusb_context *context = NULL;
ssize_t count;
uint8_t port;
char ncameras=0;
libusb_init(&context);
count = libusb_get_device_list(context,&list);
for(int i=0; i < MAX_NUM_CAMS; i++)
usb_dev_list[i]=0;
for (size_t idx = 0; idx < count; ++idx) {
libusb_device *device = list[idx];
struct libusb_device_descriptor desc = {0};
libusb_get_device_descriptor(device, &desc);
port = libusb_get_port_number(device);
printf("Vendor:Device = %04x:%04x Port: %d\n", desc.idVendor, desc.idProduct,port);
}
libusb_free_device_list(list, count);
libusb_exit(context);
}
What I need now is to know (from the C application) what v4l2 device number is related to the usb camera port, eg. I've got two webcam (same vendor ID) connected which appear as /dev/video0 and /dev/video1 respectively and I can get the connected port for each one using the above code, but, how can I know which ports are connected each one?
I tried to get information from the devices using ioctl calls as it is recommended in this question but when I run the code:
int checkvideodev()
{
int fd;
struct video_capability video_cap;
struct video_window video_win;
struct video_picture video_pic;
if((fd = open("/dev/video0", O_RDONLY)) == -1){
perror("cam_info: Can't open device");
return 1;
}
if(xioctl(fd, VIDIOCGCAP, &video_cap) == -1)
perror("cam_info: Can't get capabilities");
else {
printf("Name:\t\t '%s'\n", video_cap.name);
printf("Minimum size:\t%d x %d\n", video_cap.minwidth, video_cap.minheight);
printf("Maximum size:\t%d x %d\n", video_cap.maxwidth, video_cap.maxheight);
}
if(xioctl(fd, VIDIOCGWIN, &video_win) == -1)
perror("cam_info: Can't get window information");
else
printf("Current size:\t%d x %d\n", video_win.width, video_win.height);
if(xioctl(fd, VIDIOCGPICT, &video_pic) == -1)
perror("cam_info: Can't get picture information");
else
printf("Current depth:\t%d\n", video_pic.depth);
close(fd);
return 0;
}
I've got the next errors:
cam_info: Can't get capabilities: Inappropriate ioctl for device
cam_info: Can't get window information: Inappropriate ioctl for device
cam_info: Can't get picture information: Inappropriate ioctl for device
If I'm checking through command line for instance I can get the capabilities without issues running:
v4l2-ctl --device-/dev/video0 --list-formats-ext
Any ideas how can this be done?
Thanks in advance.
I don't know if this specifically answers your question, but you can get useful information by globbing certain patterns under /dev or /sys, for example this will return the full device path (including PCI bus) of each video device,
#include <glob.h>
#include <unistd.h>
void list_videos() {
int i;
glob_t globbuf;
if (glob("/sys/class/video4linux/video*", 0, NULL, &globbuf) != 0) {
perror("glob");
return;
}
for (i=0; i < globbuf.gl_pathc; i++) {
char buf[256] = {};
if (readlink(globbuf.gl_pathv[i], buf, sizeof(buf)-1) > 0) {
puts(buf);
}
}
}
On one system with 2 cameras this prints,
../../devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1.1/2-1.1:1.0/video4linux/video0
../../devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/video4linux/video1
Other interesting glob strings include /dev/v4l/by-id/* and /dev/v4l/by-path/*.
Since the latest Windows 10 1809 update we can no longer open a USB HID keyboard-like device of ours using CreateFile. We reduced the problem to this minimal example:
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#include <hidsdi.h>
void bad(const char *msg) {
DWORD w = GetLastError();
fprintf(stderr, "bad: %s, GetLastError() == 0x%08x\n", msg, (unsigned)w);
}
int main(void) {
int i;
GUID hidGuid;
HDEVINFO deviceInfoList;
const size_t DEVICE_DETAILS_SIZE = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH;
SP_DEVICE_INTERFACE_DETAIL_DATA *deviceDetails = alloca(DEVICE_DETAILS_SIZE);
deviceDetails->cbSize = sizeof(*deviceDetails);
HidD_GetHidGuid(&hidGuid);
deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
if(deviceInfoList == INVALID_HANDLE_VALUE) {
bad("SetupDiGetClassDevs");
return 1;
}
for (i = 0; ; ++i) {
SP_DEVICE_INTERFACE_DATA deviceInfo;
DWORD size = DEVICE_DETAILS_SIZE;
HIDD_ATTRIBUTES deviceAttributes;
HANDLE hDev = INVALID_HANDLE_VALUE;
fprintf(stderr, "Trying device %d\n", i);
deviceInfo.cbSize = sizeof(deviceInfo);
if (!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i,
&deviceInfo)) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
break;
} else {
bad("SetupDiEnumDeviceInterfaces");
continue;
}
}
if(!SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo,
deviceDetails, size, &size, NULL)) {
bad("SetupDiGetDeviceInterfaceDetail");
continue;
}
fprintf(stderr, "Opening device %s\n", deviceDetails->DevicePath);
hDev = CreateFile(deviceDetails->DevicePath, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if(hDev == INVALID_HANDLE_VALUE) {
bad("CreateFile");
continue;
}
deviceAttributes.Size = sizeof(deviceAttributes);
if(HidD_GetAttributes(hDev, &deviceAttributes)) {
fprintf(stderr, "VID = %04x PID = %04x\n", (unsigned)deviceAttributes.VendorID, (unsigned)deviceAttributes.ProductID);
} else {
bad("HidD_GetAttributes");
}
CloseHandle(hDev);
}
SetupDiDestroyDeviceInfoList(deviceInfoList);
return 0;
}
It enumerates all HID devices, trying to obtain the vendor ID/product ID for each one using CreateFile over the path provided by SetupDiGetDeviceInterfaceDetail and then calling HidD_GetAttributes.
This code runs without problems on previous Windows versions (tested on Windows 7, Windows 10 1709 and 1803, and the original code from which this was extracted works since always from XP onwards), but with the latest update (1809) all keyboard devices (including ours) cannot be opened, as CreateFile fails with access denied (GetLastError() == 5). Running the program as administrator doesn't have any effect.
Comparing the output before and after the update, I noticed that the devices that now cannot be opened gained a trailing \kbd in the device path, i.e. what previously was
\\?\hid#vid_24d6&pid_8000&mi_00#7&294a3305&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
now is
\\?\hid#vid_24d6&pid_8000&mi_00#7&294a3305&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}\kbd
Is it a bug/new security restriction in the latest Windows 10 version? Was this code always wrong and it worked by chance before? Can this be fixed?
Update
As a desperate attempt, we tried to remove the \kbd from the returned string... and CreateFile now works! So, now we have a workaround, but it would be interesting to understand if that's a bug in SetupDiGetDeviceInterfaceDetail, if it's intentional and if this workaround is actually the correct thing to do.
I think this is a new security restriction in the latest Windows 10 version.
I looked for the string KBD (in UTF-16 format) - it exists only in two drivers in version 1809, hidclass.sys and kbdhid.sys, and doesn't exist in version 1709.
In hidclass.sys they changed the HidpRegisterDeviceInterface function. Before this release it called IoRegisterDeviceInterface with GUID_DEVINTERFACE_HID and the ReferenceString pointer set to 0. But in the new version, depending on the result of GetHidClassCollection, it passes KBD as ReferenceString pointer.
Inside kbdhid.sys they changed KbdHid_Create, and here is a check for the KBD string to return errors (access denied or sharing violation).
To understand more exactly why, more research is needed. Some disasm:
For reference, HidpRegisterDeviceInterface from 1709 build
here ReferenceString == 0 always (xor r8d,r8d), and there's no check cmp word [rbp + a],6 on class collection data
However, KbdHid_Create in 1809 contains a bug. The code is:
NTSTATUS KbdHid_Create(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
//...
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (PFILE_OBJECT FileObject = IrpSp->FileObject)
{
PCUNICODE_STRING FileName = &FileObject->FileName;
if (FileName->Length)
{
#if ver == 1809
UNICODE_STRING KBD = RTL_CONSTANT_STRING(L"KBD"); // !! bug !!
NTSTATUS status = RtlEqualUnicodeString(FileName, &KBD, FALSE)
? STATUS_SHARING_VIOLATION : STATUS_ACCESS_DENIED;
#else
NTSTATUS status = STATUS_ACCESS_DENIED;
#endif
// log
Irp->IoStatus.Status = status;
IofCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
}
// ...
}
What it this function trying to do here? It looks for passed PFILE_OBJECT FileObject from Irp current stack location. It no FileObject is provided or it has an empty name, allow open; otherwise, the open fails.
Before 1809 it always failed with error STATUS_ACCESS_DENIED (0xc0000022), but starting from 1809, the name is checked, and if it's equal to KBD (case sensitive) another error - STATUS_SHARING_VIOLATION is returned. However, name always begins with the \ symbol, so it will never match KBD. It can be \KBD, so, to fix this check, the following line needs to be changed to:
UNICODE_STRING KBD = RTL_CONSTANT_STRING(L"\\KBD");
and perform the comparison with this string. So, by design we should have got a STATUS_SHARING_VIOLATION error when trying to open a keyboard device via *\KBD name, but due to an implementation error we actually got STATUS_ACCESS_DENIED here
Another change was in HidpRegisterDeviceInterface - before the call to IoRegisterDeviceInterface on the device it queries the GetHidClassCollection result, and if some WORD (2 byte) field in the structure is equal to 6, adds KBD suffix (ReferenceString). I guess (but I'm not sure) that 6 can be the Usage ID for keyboard, and the rationale for this prefix is to set Exclusive access mode
Actually, we can have a FileName begin without \ if we use relative device open via OBJECT_ATTRIBUTES. So, just for test, we can do this: if the interface name ends with \KBD, first open the file without this suffix (so with empty relative device name), and this open must work ok; then, we can try relative open file with name KBD - we must get STATUS_SHARING_VIOLATION in 1809 and STATUS_ACCESS_DENIED in previous builds (but here we will be have no \KBD suffix):
void TestOpen(PWSTR pszDeviceInterface)
{
HANDLE hFile;
if (PWSTR c = wcsrchr(pszDeviceInterface, '\\'))
{
static const UNICODE_STRING KBD = RTL_CONSTANT_STRING(L"KBD");
if (!wcscmp(c + 1, KBD.Buffer))
{
*c = 0;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, const_cast<PUNICODE_STRING>(&KBD) };
oa.RootDirectory = CreateFileW(pszDeviceInterface, 0,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (oa.RootDirectory != INVALID_HANDLE_VALUE)
{
IO_STATUS_BLOCK iosb;
// will be STATUS_SHARING_VIOLATION (c0000043)
NTSTATUS status = NtOpenFile(&hFile, SYNCHRONIZE, &oa, &iosb,
FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT);
CloseHandle(oa.RootDirectory);
if (0 <= status)
{
PrintAttr(hFile);
CloseHandle(hFile);
}
}
return ;
}
}
hFile = CreateFileW(pszDeviceInterface, 0,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
PrintAttr(hFile);
CloseHandle(hFile);
}
}
void PrintAttr(HANDLE hFile)
{
HIDD_ATTRIBUTES deviceAttributes = { sizeof(deviceAttributes) };
if(HidD_GetAttributes(hFile, &deviceAttributes)) {
printf("VID = %04x PID = %04x\r\n",
(ULONG)deviceAttributes.VendorID, (ULONG)deviceAttributes.ProductID);
} else {
bad(L"HidD_GetAttributes");
}
}
In a test on 1809 I actually got STATUS_SHARING_VIOLATION, that also shows another bug in kbdhid.KbdHid_Create - if we check FileName, we need to check RelatedFileObject - is it 0 or not.
Also, not related to bug, but as suggestion: it is more efficient to use CM_Get_Device_Interface_List instead of the SetupAPI:
volatile UCHAR guz = 0;
CONFIGRET EnumInterfaces(PGUID InterfaceClassGuid)
{
CONFIGRET err;
PVOID stack = alloca(guz);
ULONG BufferLen = 0, NeedLen = 256;
union {
PVOID buf;
PWSTR pszDeviceInterface;
};
for(;;)
{
if (BufferLen < NeedLen)
{
BufferLen = RtlPointerToOffset(buf = alloca((NeedLen - BufferLen) * sizeof(WCHAR)), stack) / sizeof(WCHAR);
}
switch (err = CM_Get_Device_Interface_ListW(InterfaceClassGuid,
0, pszDeviceInterface, BufferLen, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
case CR_BUFFER_SMALL:
if (err = CM_Get_Device_Interface_List_SizeW(&NeedLen, InterfaceClassGuid,
0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
default:
return err;
}
continue;
case CR_SUCCESS:
while (*pszDeviceInterface)
{
TestOpen(pszDeviceInterface);
pszDeviceInterface += 1 + wcslen(pszDeviceInterface);
}
return 0;
}
}
}
EnumInterfaces(const_cast<PGUID>(&GUID_DEVINTERFACE_HID));
The fix is in this windows update released today (March 1, 2019).
https://support.microsoft.com/en-us/help/4482887/windows-10-update-kb4482887
You can find a workaround at Delphi-Praxis in German
For short: Change in the Unit JvHidControllerClass
if not HidD_GetAttributes(HidFileHandle, FAttributes) then
raise EControllerError.CreateRes(#RsEDeviceCannotBeIdentified);
to
HidD_GetAttributes(HidFileHandle, FAttributes);
and recompile the Delhi JCL and JCVL Components by running the JEDI Install EXE.
I am trying to establish a serial connection with a device via RS232 and the C code. The purpose is to connect arduino to computer later and show the ip adress retrieved from the device on the LED screen.
Usually I connect the device to the computer via RS232, open PuTTY and establish the serial connection at 115200 baud rate. Then I press enter, type login, press enter, type password, press enter, type 'ip show' and then retrieve the ip adress.
The problem is I am not good at C programming (studied it only for 1 year in University). The code I come up with (copy-pasted and edited) is attached below. The questions are:
1) How do I get the information printed on the terminal screen. For example, after I type login and then press enter, there is a sentence saying type your password. How do I retrieve that to IDE's console?
2) On the final step (retrieving the ip), how do I retrieve the ip? It is in text format, after it's shown I need to copy it and paste it into another document).
As for now, my limited amount of knowledge about C prohibits me to go further.
Any kind of help (even the name of the helpful function) is appreciated!
//
// serial.c / serial.cpp
// A simple serial port writing example
// Written by Ted Burke - last updated 13-2-2013
//
// To compile with MinGW:
//
// gcc -o serial.exe serial.c
//
// To compile with cl, the Microsoft compiler:
//
// cl serial.cpp
//
// To run:
//
// serial.exe
//
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
// Define the five bytes to send ("hello")
char bytes_to_send[15];
bytes_to_send[0] = '\n';
bytes_to_send[1] = 'a';
bytes_to_send[2] = 'd';
bytes_to_send[3] = 'm';
bytes_to_send[4] = 'i';
bytes_to_send[5] = 'n';
bytes_to_send[6] = '\n';
bytes_to_send[7] = 's';
bytes_to_send[8] = 'h';
bytes_to_send[9] = 'o';
bytes_to_send[10] = 'w';
bytes_to_send[11] = ' ';
bytes_to_send[12] = 'i';
bytes_to_send[13] = 'p';
bytes_to_send[14] = '\n';
// Declare variables and structures
HANDLE hSerial;
DCB dcbSerialParams = {0};
COMMTIMEOUTS timeouts = {0};
// Open the highest available serial port number
fprintf(stderr, "Opening serial port...");
hSerial = CreateFile(
"\\\\.\\COM6", GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if (hSerial == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "Error\n");
return 1;
}
else fprintf(stderr, "OK\n");
// Set device parameters (38400 baud, 1 start bit,
// 1 stop bit, no parity)
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (GetCommState(hSerial, &dcbSerialParams) == 0)
{
fprintf(stderr, "Error getting device state\n");
CloseHandle(hSerial);
return 1;
}
dcbSerialParams.BaudRate = CBR_115200;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if(SetCommState(hSerial, &dcbSerialParams) == 0)
{
fprintf(stderr, "Error setting device parameters\n");
CloseHandle(hSerial);
return 1;
}
// Set COM port timeout settings
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if(SetCommTimeouts(hSerial, &timeouts) == 0)
{
fprintf(stderr, "Error setting timeouts\n");
CloseHandle(hSerial);
return 1;
}
// Send specified text (remaining command line arguments)
DWORD bytes_written, total_bytes_written = 0;
fprintf(stderr, "Sending bytes...");
if(!WriteFile(hSerial, bytes_to_send, sizeof(bytes_to_send), &bytes_written, NULL))
{
fprintf(stderr, "Error\n");
CloseHandle(hSerial);
return 1;
}
fprintf(stderr, "%d bytes written\n", bytes_written);
// Close serial port
fprintf(stderr, "Closing serial port...");
if (CloseHandle(hSerial) == 0)
{
fprintf(stderr, "Error\n");
return 1;
}
fprintf(stderr, "OK\n");
fprintf(stderr, "the sent sentence is: ");
for(int i=0;i<sizeof(bytes_to_send);i++){
fprintf(stderr,"%c",bytes_to_send[i]);
}
// exit normally
return 0;
}
For setting up the port and read/write commands you can use the code from this answer.
Then you only have to worry about what you send and what you receive.
Putty actually reads the serial port in the background and then prints it on the console so you can see it. You will have to do the same thing in your app. After you read the data, you have to print it.
For example, for login, as you described it:
write (fd, "login\r\n", 7); // send 7 character login command
// (similar to writing login + enter in Putty)
usleep ((7 + 25) * 100); // allow time for sending & receiving
// (sleep enough to transmit the 7 plus
// receive 25: approx 100 uS per char transmit)
char buf [100];
int n = read (fd, buf, sizeof(buf)); // read rx characters (Putty does this automatically)
// expect to have "the sentence saying type your password" in this buffer
// 100 characters are read, adjust it if you expect a longer answer
printf("Rx:"); // display the rx data (Putty does this automatically)
for (int i = 0; i < sizeof(buf); i++)
printf("%c",buf[i]);
printf("\n");
// continue with sending the password + reading the response
// then sending the ip command + reading the answer
I'm a beginner in UEFI. I'm trying to open a file from my UEFI application. The path of file is
fs1:/myfolder/myfile.txt
The code (With the help of this answer) :
efiStatus = bs->LocateHandleBuffer(ByProtocol,
&sfspGuid,
NULL,
&handleCount,
&handles);
for (index = 0; index < (int)handleCount; ++ index)
{
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* fs = NULL;
efiStatus = bs->HandleProtocol(
handles[index],
&sfspGuid,
(void**)&fs);
EFI_FILE_PROTOCOL* root = NULL;
...
efiStatus = fs->OpenVolume(fs, &root);
EFI_FILE_PROTOCOL* token = NULL;
efiStatus = root->Open(
root,
&token,
L"myfolder\\myfile.txt",
EFI_FILE_MODE_READ,
EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM);
}
But using this method, I can only go through all the file system handles and open each volume and try opening my file.
But I want to give full path to my file and open it in it's volume.
How can I acheive this?
EDIT:
I tried using Shell APIs for opening the file as suggested by #Alex in comments.
Below is the code. But it hangs in function OpenFileByName .
What is the mistake in this code? (argv[ 1 ] would be my file path fs1:\myfile.txt )
EFI_STATUS
EFIAPI
main (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS status;
UINTN argc;
CHAR16 **argv;
SHELL_FILE_HANDLE Handle;
status = get_args(&argc, &argv);
if (EFI_ERROR(status)) {
Print(L"ERROR: Parsing command line arguments: %d\n", status);
return status;
}
if (argc <= 1){
Print(L"No file name to open\n");
return (EFI_UNSUPPORTED); //need to have at least one parameter
}
Print(L"File to open is: %s\n", argv[1]);
status = gEfiShellProtocol->OpenFileByName (argv[1], &Handle,
EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE);
if (EFI_ERROR(status)) {
Print(L"\nFile Open did not work %s\n", argv[1]);
return (status);
}else{
Print(L"\nFile Open worked %s\n", argv[1]);
gEfiShellProtocol->CloseFile(Handle);
}
return EFI_SUCCESS;
}
And the code hangs even if I try GetCurDir function.
Print(L"Dir: %s \n",gEfiShellProtocol->GetCurDir(NULL));
Any pointers would be helpful.
Answer to the comment how to get EFI_SHELL_PROTOCOL:
The procedure is basically the same as for any Efi protocols. First, grab a handle to the interface:
UINTN BufferSize;
EFI_HANDLE* Buffer;
Status = bs->LocateHandle(ByProtocol, &gEfiShellProtocolGuid, NULL, &BufferSize, Buffer);
Than, allocate and recall with the buffer of the correct size:
Status = bs->AllocatePool(EfiBootServicesData, BufferSize, &Buffer);
Status = bs->LocateHandle(ByProtocol, &gEfiShellProtocolGuid, NULL, &BufferSize, Buffer);
Now, you can grab a handle to the protocol. Remember, it's EFI, there might be multiple protocols installed! That's why we have to iterate through all of them. But in this case most likely there will be just one instance of the SHELL protocol:
UINTN HandleCounter;
for (HandleCounter = 0 ; HandleCounter < (BufferSize/sizeof(EFI_HANDLE)) ; HandleCounter++)
{
Status = bs->OpenProtocol(Buffer[HandleCounter],
&gEfiShellProtocolGuid,
(VOID**)&gEfiShellProtocol,
imageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
And don't forget to check Status for every step!
And of course don't forget:
bs->FreePool(buffer);
As for the protocol itself you don't have to close it. EFI starting from 2.31 doesn't require it anymore.
I have this code which is part of a project source.
This code finds the MBR type: GRUB or LILO, and accordingly sets a flag.
Surprisingly in SLES 10-SP1 (SUSE Linux Enterprise Server), it is unable to determine.
/dev/sda1 is my swap.
/dev/sda2 is where the whole / is there, including the MBR.
Same code works for SLES11 and others.
Here MBR_SIZE is #defined to 0x1be.
int lnxfsGetBootType(int pNumber)
{
int i, retval = -1, ccode;
PartInfo *p = &cpuParts[pNumber];
char buffer[SECTOR_SIZE];
var64 offset = 0;
isdLogFileOut(ZISD_LOG_DEVELOPER,"[lnxGBT]\n");
if (getenv("ZENDEVICE") || gUtilPart == 1) {
offset = p->pOffset; // look at the partition BPB
}
//Now try to find the installed boot loader...
lseek64(p->handle, (var64)offset, SEEK_SET); // either MBR or BPB
ccode = read(p->handle, buffer, SECTOR_SIZE);
for (i=0; i<MBR_SIZE-4;i++) {
if (strncmp(&buffer[i], "LILO", 4) == 0) {
if (offset == 0){
retval = FLAG_LNXFS_LILO;
isdLogFileOut(ZISD_LOG_WARNING,"\tLILO MBR found on %s\n",p->header.deviceName);
} else {
retval = FLAG_LNXFS_LILO; // 10.31.06 _BPB;
isdLogFileOut(ZISD_LOG_WARNING,"\tLILO BPB found on %s\n",p->header.deviceName);
}
}
if (strncmp(&buffer[i], "GRUB", 4) == 0) {
if (offset == 0){
retval = FLAG_LNXFS_GRUB;
isdLogFileOut(ZISD_LOG_WARNING,"\tGRUB MBR found on %s\n",p->header.deviceName);
} else {
retval = FLAG_LNXFS_GRUB; // 10.31.06 _BPB;
isdLogFileOut(ZISD_LOG_WARNING,"\tGRUB BPB found on %s\n",p->header.deviceName);
}
}
}
if (retval == -1) {
isdLogFileOut(ZISD_LOG_WARNING,"\tLILO or GRUB mbr/bpb not found on %s\n",p->header.deviceName);
}
return retval;
} // lnxfsGetBootType
Here partinfo, is a struct of partition type:
//Data structure used internally by the image engine to store information about the
//partitions. It encapsulates the PartHeader struct, whcih is used to store partition
//information in image archives
typedef struct _PartInfo
{
PartHeader header;
int handle; //file handle for reading/writing physical device
var32 flags; //Various flags as needed. Defined above.
var64 pOffset; //offset to partition from start of physical device
int deviceNumber; //index into 'devices' where this partition's
// physical device is located
int archIndex; //for restoring only. Index into imgParts of the
// archive partition this physical partition is
// mapped to
int bytesWritten; //track number of sectors written so the device-level
// cache can be flushed
void *info; //partition-type-specific info struct
/* snip */
The testing is being done with different virtual disk images under VMWare. I've confirmed the disks are formatted with MBR and not GPT.
I'm not sure what you mean when you say it doesn't work. If your point is that your code returns -1, could you show us a copy of the MBR? You can use this command to capture it:
sudo dd if=/dev/sda bs=512 count=1 | xxd
You mention that your MBR is on /dev/sda2. That is very unusual indeed. If you mean that that is where the boot code is installed, that's a totally different thing. The MBR is always held on the first sector of the disk (assuming it is a DOS-format MBR).
I suppose it's possible that the problem in some of the failure cases is a seek failure or a short read. I've made some tweaks to add error handling and simplify a bit.
#define MBR_SIZE 0x1be
int lnxfsGetBootType(int pNumber)
{
int retval = -1, ccode;
PartInfo *p = &cpuParts[pNumber];
char buffer[SECTOR_SIZE];
off64_t offset = 0;
void *plilo, *pgrub;
const char *what = "MBR";
isdLogFileOut(ZISD_LOG_DEVELOPER,"[lnxGBT]\n");
if (getenv("ZENDEVICE") || gUtilPart == 1) {
offset = p->pOffset; // look at the partition BPB
what = "BPB";
}
// Now try to find the installed boot loader...
if (lseek64(p->handle, offset, SEEK_SET) == -1) {
isdLogFileOut(ZISD_LOG_ERROR,"\tFailed to seek to %s: %s\n", what, strerror(errno));
return -1;
}
ccode = read(p->handle, buffer, SECTOR_SIZE);
if (ccode != SECTOR_SIZE) {
isdLogFileOut(ZISD_LOG_ERROR,"\tFailed to read BPB/MBR: %s\n",
strerror(errno));
return -1;
}
plilo = memmem(buffer, ccode, "LILO", 4);
pgrub = memmem(buffer, ccode, "GRUB", 4);
if (plilo) {
retval = FLAG_LNXFS_LILO;
if (pgrub && pgrub < plilo)
retval = FLAG_LNXFS_GRUB;
}
} else if (pgrub) {
retval = FLAG_LNXFS_GRUB;
}
if (-1 == retval) {
isdLogFileOut(ZISD_LOG_WARNING,"\tLILO or GRUB %s not found on %s\n", what, p->header.deviceName);
} else {
isdLogFileOut(ZISD_LOG_WARNING,"\t%s %s not found on %s\n",
(retval == FLAG_LNXFS_GRUB ? "GRUB" : "LILO"),
what, p->header.deviceName);
}
return retval;
} // lnxfsGetBootType