通常,每个UEFI系统至少有一个 ESP (EFI System Partition)分区,在这个分区上存放启动文件。EFI内置了EFI_SIMPLE_FILE_SYSTEM_PROTOCOL(简称 FileSystemIo)可以用来操作FAT文件系统【参考1】。
相关的介绍:
\MdePkg\Include\Protocol\SimpleFileSystem.h
///
/// The EFI_FILE_PROTOCOL provides file IO access to supported file systems.
/// An EFI_FILE_PROTOCOL provides access to a file's or directory's contents,
/// and is also a reference to a location in the directory tree of the file system
/// in which the file resides. With any given file handle, other files may be opened
/// relative to this file's location, yielding new file handles.
///
struct _EFI_FILE_PROTOCOL {
///
/// The version of the EFI_FILE_PROTOCOL interface. The version specified
/// by this specification is EFI_FILE_PROTOCOL_LATEST_REVISION.
/// Future versions are required to be backward compatible to version 1.0.
///
UINT64 Revision;
EFI_FILE_OPEN Open;
EFI_FILE_CLOSE Close;
EFI_FILE_DELETE Delete;
EFI_FILE_READ Read;
EFI_FILE_WRITE Write;
EFI_FILE_GET_POSITION GetPosition;
EFI_FILE_SET_POSITION SetPosition;
EFI_FILE_GET_INFO GetInfo;
EFI_FILE_SET_INFO SetInfo;
EFI_FILE_FLUSH Flush;
EFI_FILE_OPEN_EX OpenEx;
EFI_FILE_READ_EX ReadEx;
EFI_FILE_WRITE_EX WriteEx;
EFI_FILE_FLUSH_EX FlushEx;
};
/**
Writes data to a file.
@param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
handle to write data to.
@param BufferSize On input, the size of the Buffer. On output, the amount of data
actually written. In both cases, the size is measured in bytes.
@param Buffer The buffer of data to write.
@retval EFI_SUCCESS Data was written.
@retval EFI_UNSUPPORTED Writes to open directory files are not supported.
@retval EFI_NO_MEDIA The device has no medium.
@retval EFI_DEVICE_ERROR The device reported an error.
@retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
@retval EFI_WRITE_PROTECTED The file or medium is write-protected.
@retval EFI_ACCESS_DENIED The file was opened read only.
@retval EFI_VOLUME_FULL The volume is full.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_FILE_WRITE)(
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
IN VOID *Buffer
);
完整代码:
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>
#include <Protocol/SimpleFileSystem.h>
extern EFI_BOOT_SERVICES *gBS;
extern EFI_SYSTEM_TABLE *gST;
int
EFIAPI
main (
IN int Argc,
IN char **Argv
)
{
EFI_STATUS Status;
EFI_FILE_PROTOCOL *Root;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
UINTN BufSize;
CHAR16 *Textbuf = (CHAR16*) L"www.lab-z.com";
EFI_FILE_PROTOCOL *FileHandle=0;
Status = gBS->LocateProtocol(
&gEfiSimpleFileSystemProtocolGuid,
NULL,
(VOID **)&SimpleFileSystem);
if (EFI_ERROR(Status)) {
Print(L"Cannot find EFI_SIMPLE_FILE_SYSTEM_PROTOCOL \r\n");
return Status;
}
Status = SimpleFileSystem->OpenVolume(SimpleFileSystem,&Root);
if (EFI_ERROR(Status)) {
Print(L"OpenVolume error \r\n");
return Status;
}
Status = Root -> Open(Root,
&FileHandle,
(CHAR16 *) L"atest.txt",
EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
0);
if (EFI_ERROR(Status) || (FileHandle==0)) {
Print(L"Open error \r\n");
return Status;
}
BufSize = StrLen (Textbuf) * 2;
Print(L"[%d]\r\n",BufSize);
Print(L"[%s]\r\n",Textbuf);
Status = FileHandle -> Write(FileHandle, &BufSize, Textbuf);
Print(L"Write Done \r\n");
Status = FileHandle -> Close (FileHandle);
return EFI_SUCCESS;
}
运行结果:
比较有意思的是,我们按照上面的程序写入之后,使用 type 文件名 来显示文件内容和我们的预期有差别,原因是Type命令默认使用 ASCII 来显内容,而我们的文件中写入的是 Unicode。使用 type -u 强制使用 Unicode即可看到我们期望的内容。
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Protocol/SimpleFileSystem.h>
extern EFI_HANDLE gImageHandle;
EFI_STATUS
WriteMemoryToFile(
IN EFI_HANDLE ImageHandle,
IN CHAR16 *FileName,
IN VOID *Buffer,
IN UINTN BufferSize
)
{
EFI_STATUS Status;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
EFI_FILE_PROTOCOL *Root;
EFI_FILE_PROTOCOL *File;
EFI_HANDLE *Handles = NULL;
UINTN HandleCount = 0;
// Locate all handles that support the Simple File System Protocol
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);
if (EFI_ERROR(Status)) {
Print(L"Failed to locate handles for Simple File System Protocol: %r\n", Status);
return Status;
}
// Open the first Simple File System Protocol
Status = gBS->HandleProtocol(Handles[0], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&SimpleFileSystem);
if (EFI_ERROR(Status)) {
Print(L"Failed to open Simple File System Protocol: %r\n", Status);
return Status;
}
// Open the root directory
Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &Root);
if (EFI_ERROR(Status)) {
Print(L"Failed to open root directory: %r\n", Status);
return Status;
}
// Create or open the file
Status = Root->Open(Root, &File, FileName, EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
if (EFI_ERROR(Status)) {
Print(L"Failed to open or create file: %r\n", Status);
return Status;
}
// Write the buffer to the file
Status = File->Write(File, &BufferSize, Buffer);
if (EFI_ERROR(Status)) {
Print(L"Failed to write to file: %r\n", Status);
File->Close(File);
return Status;
}
// Close the file
Status = File->Close(File);
if (EFI_ERROR(Status)) {
Print(L"Failed to close file: %r\n", Status);
return Status;
}
Print(L"Memory successfully written to file: %s\n", FileName);
return EFI_SUCCESS;
}
USB HID class: Difference between report protocol and boot protocol?
Hi All
I would like to know:
1- For USB-HID class: What is the difference between report protocol and boot protocol?
2- For keyboard: the input report format is unique for both report/boot protocol?
3- When Host send Request(GET_DESCRIPTOR) specifying the report descriptor type, Will Device return the report descriptor including the input report data(i.e: 8-byte for keyboard) ? OR Host need to send Request GET_REPORT to get the input report?
In short, boot protocol is used on BIOS, report protocol is used on OS.
The device capability of boot protocol is shown at the interface triad,
(interfaceClass, interfaceSubclass, interfaceProtocol) field on the HID interface descriptor.
(interfaceClass, interfaceSubclass, interfaceProtocol) = (3, 1, 1): boot keyboard
(interfaceClass, interfaceSubclass, interfaceProtocol) = (3, 1, 2): boot mouse
BIOS checks just this triad, and it recognizes the device (interface) as specified.
BIOS doesn’t actually read out report descriptor from the device; It assumes that the device has standard keyboard or mouse report descriptor (*1) while the device in boot protocol.
After enumeration, BIOS puts Set_Protocol( BOOT ) to switch the device into boot protocol, if the device has boot capability. While BIOS is running, the device works as keyboard or mouse.
If the device doesn’t have boot capability, BIOS doesn’t enumerate the device.
At the start up of OS after BIOS, OS puts bus reset. The device gets back to default report protocol.
Usually, OS doesn’t put any Set_Protocol, the device is held in report protocol.
On the enumeration, OS reads out report descriptor of the device, and it determines the type of HID device, regardless of above subclass-protocol field.
(*1) see HID spec Appendix B: Boot Interface Descriptors
As I wrote above,
For boot protocol, the report format is fixed one.
For report protocol, you can define any report format on the report descriptor.
Device returns just the report descriptor, when host puts Get_Descriptor().
Actual input report is sent for Get_Report( input ) request, or for IN transfer over the interrupt IN endpoint.
If you are using Delphi TComPort VCL for some Arduino programs. Please set FlowControl -> ControlDTR to dtrEnable. Otherwise, you will get nothing from Serial Port.
It costed me one afternoon for this issue. I worked with a Arduino Pro Micro (Leonardo). The Serial Monitor of IDE worked well. Putty worked well and ‘Serial Port Utility’ worked well. Arduino Uno was tried. It works well……. Only my Delphi program couldn’t get anything from the Serial Port. At last, I noticed the example program of TComPort worked well. But if I deleted this VCL and added again, it would fail. At last I found this Properties.
I don’t know why. All the documents said Leonardo didn’t use DTR pin.
If you have any suggestion, please let me know. Thanks a lot.
typedef struct _EFI_GRAPHICS_OUTPUT_PROTOCOL EFI_GRAPHICS_OUTPUT_PROTOCOL;
///
/// Provides a basic abstraction to set video modes and copy pixels to and from
/// the graphics controller's frame buffer. The linear address of the hardware
/// frame buffer is also exposed so software can write directly to the video hardware.
///
struct _EFI_GRAPHICS_OUTPUT_PROTOCOL {
EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE QueryMode;
EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE SetMode;
EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT Blt;
///
/// Pointer to EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE data.
///
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode;
};
typedef struct {
///
/// The number of modes supported by QueryMode() and SetMode().
///
UINT32 MaxMode;
///
/// Current Mode of the graphics device. Valid mode numbers are 0 to MaxMode -1.
///
UINT32 Mode;
///
/// Pointer to read-only EFI_GRAPHICS_OUTPUT_MODE_INFORMATION data.
///
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
///
/// Size of Info structure in bytes.
///
UINTN SizeOfInfo;
///
/// Base address of graphics linear frame buffer.
/// Offset zero in FrameBufferBase represents the upper left pixel of the display.
///
EFI_PHYSICAL_ADDRESS FrameBufferBase;
///
/// Amount of frame buffer needed to support the active mode as defined by
/// PixelsPerScanLine xVerticalResolution x PixelElementSize.
///
UINTN FrameBufferSize;
} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE;
String comdata="";
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
while (Serial.available() > 0)
{
comdata += Serial.read();
delay(2);
}
if (comdata.length()>1) {Serial.println(comdata); comdata="";}
}
String comdata="";
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
while (Serial.available() > 0)
{
comdata +=(char)Serial.read();
delay(2);
}
if (comdata.length()>1) {Serial.println(comdata); comdata="";}
}