Skip to content

Commit d5f3883

Browse files
committed
basic simple file system protocol support
1 parent 25470f2 commit d5f3883

File tree

2 files changed

+260
-1
lines changed

2 files changed

+260
-1
lines changed

src/machine/uefi/efiguid.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
package uefi
22

3-
var EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID = EFI_GUID{0x964E5B22, 0x6459, 0x11D2, [8]uint8{0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B}}
43
var EFI_DEVICE_PATH_PROTOCOL_GUID = EFI_GUID{0x9576e91, 0x6d3f, 0x11d2, [8]uint8{0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}
54
var EFI_LOADED_IMAGE_GUID = EFI_GUID{0x5B1B31A1, 0x9562, 0x11d2, [8]uint8{0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B}}
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
package uefi
2+
3+
import (
4+
"unsafe"
5+
)
6+
7+
//---------------------------------------------------------------------------
8+
// GUIDs (§13.5 File Protocol and related info GUIDs)
9+
//---------------------------------------------------------------------------
10+
11+
// EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID = {964E5B22-6459-11D2-8E39-00A0C969723B}
12+
var EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID = EFI_GUID{
13+
0x964E5B22, 0x6459, 0x11D2,
14+
[8]uint8{0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b},
15+
}
16+
17+
// gEfiFileInfoGuid = {09576E92-6D3F-11D2-8E39-00A0C969723B}
18+
var EFI_FILE_INFO_ID = EFI_GUID{
19+
0x09576e92, 0x6d3f, 0x11d2,
20+
[8]uint8{0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b},
21+
}
22+
23+
// gEfiFileSystemInfoGuid = {09576E93-6D3F-11D2-8E39-00A0C969723B}
24+
var EFI_FILE_SYSTEM_INFO_ID = EFI_GUID{
25+
0x09576e93, 0x6d3f, 0x11d2,
26+
[8]uint8{0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b},
27+
}
28+
29+
// gEfiFileSystemVolumeLabelInfoIdGuid = {DB47D7D3-FE81-11D3-9A35-0090273FC14D}
30+
var EFI_FILE_SYSTEM_VOLUME_LABEL_ID = EFI_GUID{
31+
0xdb47d7d3, 0xfe81, 0x11d3,
32+
[8]uint8{0x9a, 0x35, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d},
33+
}
34+
35+
//---------------------------------------------------------------------------
36+
// Constants (§13.5.1)
37+
//---------------------------------------------------------------------------
38+
39+
// Open modes are 64-bit flags
40+
const (
41+
EFI_FILE_MODE_READ uint64 = 0x0000000000000001
42+
EFI_FILE_MODE_WRITE uint64 = 0x0000000000000002
43+
EFI_FILE_MODE_CREATE uint64 = 0x8000000000000000
44+
)
45+
46+
// Attribute flags (also 64-bit)
47+
const (
48+
EFI_FILE_READ_ONLY uint64 = 0x0000000000000001
49+
EFI_FILE_HIDDEN uint64 = 0x0000000000000002
50+
EFI_FILE_SYSTEM uint64 = 0x0000000000000004
51+
EFI_FILE_RESERVED uint64 = 0x0000000000000008
52+
EFI_FILE_DIRECTORY uint64 = 0x0000000000000010
53+
EFI_FILE_ARCHIVE uint64 = 0x0000000000000020
54+
)
55+
56+
// Optional: known protocol revision values (not strictly required to use)
57+
const (
58+
EFI_FILE_PROTOCOL_REVISION = 0x00010000
59+
EFI_FILE_PROTOCOL_REVISION2 = 0x00020000
60+
EFI_FILE_PROTOCOL_LATEST = EFI_FILE_PROTOCOL_REVISION2
61+
)
62+
63+
//---------------------------------------------------------------------------
64+
// Protocols (§13.4 Simple File System, §13.5 File Protocol)
65+
//---------------------------------------------------------------------------
66+
67+
// EFI_SIMPLE_FILE_SYSTEM_PROTOCOL (§13.4.2)
68+
// Function table: Revision, OpenVolume
69+
// OpenVolume returns a handle to the volume root directory (EFI_FILE_PROTOCOL*)
70+
71+
type EFI_SIMPLE_FILE_SYSTEM_PROTOCOL struct {
72+
Revision uint64
73+
openVolume uintptr // (this, **EFI_FILE_PROTOCOL)
74+
}
75+
76+
func (p *EFI_SIMPLE_FILE_SYSTEM_PROTOCOL) OpenVolume(root **EFI_FILE_PROTOCOL) EFI_STATUS {
77+
return UefiCall2(
78+
p.openVolume,
79+
uintptr(unsafe.Pointer(p)),
80+
uintptr(unsafe.Pointer(root)),
81+
)
82+
}
83+
84+
// EFI_FILE_PROTOCOL (§13.5.2)
85+
// Function table order: Revision, Open, Close, Delete, Read, Write, GetPosition, SetPosition, GetInfo, SetInfo, Flush
86+
87+
type EFI_FILE_PROTOCOL struct {
88+
Revision uint64
89+
open uintptr // (this, **newHandle, *FileName, OpenMode, Attributes)
90+
close uintptr // (this)
91+
delete uintptr // (this)
92+
read uintptr // (this, *BufferSize, Buffer)
93+
write uintptr // (this, *BufferSize, Buffer)
94+
getPosition uintptr // (this, *Position)
95+
setPosition uintptr // (this, Position)
96+
getInfo uintptr // (this, *InfoType, *BufferSize, Buffer)
97+
setInfo uintptr // (this, *InfoType, BufferSize, Buffer)
98+
flush uintptr // (this)
99+
}
100+
101+
// Open opens a file or directory relative to this handle (which may be a root or directory handle).
102+
// FileName must be a NUL-terminated UTF-16 path using '\\' separators. (§13.5.3)
103+
func (p *EFI_FILE_PROTOCOL) Open(newHandle **EFI_FILE_PROTOCOL, fileName *CHAR16, openMode uint64, attributes uint64) EFI_STATUS {
104+
return UefiCall6(
105+
p.open,
106+
uintptr(unsafe.Pointer(p)),
107+
uintptr(unsafe.Pointer(newHandle)),
108+
uintptr(unsafe.Pointer(fileName)),
109+
uintptr(openMode),
110+
uintptr(attributes),
111+
0,
112+
)
113+
}
114+
115+
// Close closes the file handle. (§13.5.4)
116+
func (p *EFI_FILE_PROTOCOL) Close() EFI_STATUS {
117+
return UefiCall1(p.close, uintptr(unsafe.Pointer(p)))
118+
}
119+
120+
// Delete deletes the file opened by this handle. (§13.5.5)
121+
func (p *EFI_FILE_PROTOCOL) Delete() EFI_STATUS {
122+
return UefiCall1(p.delete, uintptr(unsafe.Pointer(p)))
123+
}
124+
125+
// Read reads from the file into Buffer. BufferSize is in/out: on entry, size of Buffer; on return, bytes read. (§13.5.6)
126+
func (p *EFI_FILE_PROTOCOL) Read(bufferSize *UINTN, buffer unsafe.Pointer) EFI_STATUS {
127+
return UefiCall3(
128+
p.read,
129+
uintptr(unsafe.Pointer(p)),
130+
uintptr(unsafe.Pointer(bufferSize)),
131+
uintptr(buffer),
132+
)
133+
}
134+
135+
// Write writes to the file from Buffer. BufferSize is in/out: on entry, bytes to write; on return, bytes written. (§13.5.7)
136+
func (p *EFI_FILE_PROTOCOL) Write(bufferSize *UINTN, buffer unsafe.Pointer) EFI_STATUS {
137+
return UefiCall3(
138+
p.write,
139+
uintptr(unsafe.Pointer(p)),
140+
uintptr(unsafe.Pointer(bufferSize)),
141+
uintptr(buffer),
142+
)
143+
}
144+
145+
// GetPosition returns the current file position in bytes. (§13.5.8)
146+
func (p *EFI_FILE_PROTOCOL) GetPosition(position *uint64) EFI_STATUS {
147+
return UefiCall2(
148+
p.getPosition,
149+
uintptr(unsafe.Pointer(p)),
150+
uintptr(unsafe.Pointer(position)),
151+
)
152+
}
153+
154+
// SetPosition sets the current file position. Setting to 0xFFFFFFFFFFFFFFFF seeks to end-of-file. (§13.5.9)
155+
func (p *EFI_FILE_PROTOCOL) SetPosition(position uint64) EFI_STATUS {
156+
return UefiCall2(
157+
p.setPosition,
158+
uintptr(unsafe.Pointer(p)),
159+
uintptr(position),
160+
)
161+
}
162+
163+
// GetInfo retrieves metadata identified by InformationType. Common GUIDs: EFI_FILE_INFO_ID, EFI_FILE_SYSTEM_INFO_ID, EFI_FILE_SYSTEM_VOLUME_LABEL_ID. (§13.5.10)
164+
func (p *EFI_FILE_PROTOCOL) GetInfo(infoType *EFI_GUID, bufferSize *UINTN, buffer unsafe.Pointer) EFI_STATUS {
165+
return UefiCall4(
166+
p.getInfo,
167+
uintptr(unsafe.Pointer(p)),
168+
uintptr(unsafe.Pointer(infoType)),
169+
uintptr(unsafe.Pointer(bufferSize)),
170+
uintptr(buffer),
171+
)
172+
}
173+
174+
// SetInfo sets metadata identified by InformationType. (§13.5.11)
175+
func (p *EFI_FILE_PROTOCOL) SetInfo(infoType *EFI_GUID, bufferSize UINTN, buffer unsafe.Pointer) EFI_STATUS {
176+
return UefiCall4(
177+
p.setInfo,
178+
uintptr(unsafe.Pointer(p)),
179+
uintptr(unsafe.Pointer(infoType)),
180+
uintptr(bufferSize),
181+
uintptr(buffer),
182+
)
183+
}
184+
185+
// Flush flushes file data and metadata to the device. (§13.5.12)
186+
func (p *EFI_FILE_PROTOCOL) Flush() EFI_STATUS {
187+
return UefiCall1(p.flush, uintptr(unsafe.Pointer(p)))
188+
}
189+
190+
//---------------------------------------------------------------------------
191+
// Info structures (§13.5.13, §13.5.15)
192+
//---------------------------------------------------------------------------
193+
194+
// EFI_FILE_INFO head (FileName is a variable-length CHAR16[] immediately following this struct)
195+
// Layout must exactly match the spec; FileName is retrieved from the backing buffer used with GetInfo.
196+
197+
type EFI_FILE_INFO struct {
198+
Size uint64
199+
FileSize uint64
200+
PhysicalSize uint64
201+
CreateTime EFI_TIME
202+
LastAccessTime EFI_TIME
203+
ModificationTime EFI_TIME
204+
Attribute uint64
205+
// CHAR16 FileName[] follows
206+
}
207+
208+
// EFI_FILE_SYSTEM_INFO head (VolumeLabel is a variable-length CHAR16[] after the struct)
209+
210+
type EFI_FILE_SYSTEM_INFO struct {
211+
Size uint64
212+
ReadOnly bool
213+
_ [7]byte // pad to 8-byte alignment (bool is 1 byte)
214+
VolumeSize uint64
215+
FreeSpace uint64
216+
BlockSize uint32
217+
_ uint32 // padding to keep next CHAR16[] aligned as in C
218+
// CHAR16 VolumeLabel[] follows
219+
}
220+
221+
// EFI_FILE_SYSTEM_VOLUME_LABEL is just a CHAR16[] volume label; retrieved via GetInfo with EFI_FILE_SYSTEM_VOLUME_LABEL_ID.
222+
// Represented implicitly by reading a buffer of UTF-16 data.
223+
224+
//---------------------------------------------------------------------------
225+
// Helpers: enumerate volumes and open root
226+
//---------------------------------------------------------------------------
227+
228+
// EnumerateFileSystems locates all Simple File System handles and returns their protocol pointers.
229+
func EnumerateFileSystems() ([]*EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, error) {
230+
var (
231+
handleCount UINTN
232+
handleBuffer *EFI_HANDLE
233+
)
234+
st := BS().LocateHandleBuffer(ByProtocol, &EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, nil, &handleCount, &handleBuffer)
235+
if st == EFI_NOT_FOUND {
236+
return nil, nil
237+
}
238+
if st != EFI_SUCCESS {
239+
return nil, StatusError(st)
240+
}
241+
handles := unsafe.Slice((*EFI_HANDLE)(unsafe.Pointer(handleBuffer)), int(handleCount))
242+
out := make([]*EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, 0, len(handles))
243+
for _, h := range handles {
244+
var sfs *EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
245+
if st = BS().HandleProtocol(h, &EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, unsafe.Pointer(&sfs)); st == EFI_SUCCESS {
246+
out = append(out, sfs)
247+
}
248+
}
249+
return out, nil
250+
}
251+
252+
// OpenRoot opens the volume root directory for a given SFS.
253+
func OpenRoot(sfs *EFI_SIMPLE_FILE_SYSTEM_PROTOCOL) (*EFI_FILE_PROTOCOL, EFI_STATUS) {
254+
var root *EFI_FILE_PROTOCOL
255+
st := sfs.OpenVolume(&root)
256+
if st != EFI_SUCCESS {
257+
return nil, st
258+
}
259+
return root, EFI_SUCCESS
260+
}

0 commit comments

Comments
 (0)