1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
|
/** @file
Internal macro definitions, type definitions, and function declarations for
the Virtio Filesystem device driver.
Copyright (C) 2020, Red Hat, Inc.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef VIRTIO_FS_DXE_H_
#define VIRTIO_FS_DXE_H_
#include <Base.h> // SIGNATURE_64()
#include <Guid/FileInfo.h> // EFI_FILE_INFO
#include <IndustryStandard/VirtioFs.h> // VIRTIO_FS_TAG_BYTES
#include <Library/DebugLib.h> // CR()
#include <Protocol/SimpleFileSystem.h> // EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
#include <Protocol/VirtioDevice.h> // VIRTIO_DEVICE_PROTOCOL
#include <Uefi/UefiBaseType.h> // EFI_EVENT
#define VIRTIO_FS_SIG SIGNATURE_64 ('V', 'I', 'R', 'T', 'I', 'O', 'F', 'S')
#define VIRTIO_FS_FILE_SIG \
SIGNATURE_64 ('V', 'I', 'O', 'F', 'S', 'F', 'I', 'L')
//
// The following limit applies to two kinds of pathnames.
//
// - The length of a POSIX-style, canonical pathname *at rest* never exceeds
// VIRTIO_FS_MAX_PATHNAME_LENGTH. (Length is defined as the number of CHAR8
// elements in the canonical pathname, excluding the terminating '\0'.) This
// is an invariant that is ensured for canonical pathnames created, and that
// is assumed about canonical pathname inputs (which all originate
// internally).
//
// - If the length of a UEFI-style pathname *argument*, originating directly or
// indirectly from the EFI_FILE_PROTOCOL caller, exceeds
// VIRTIO_FS_MAX_PATHNAME_LENGTH, then the argument is rejected. (Length is
// defined as the number of CHAR16 elements in the UEFI-style pathname,
// excluding the terminating L'\0'.) This is a restriction that's checked on
// external UEFI-style pathname inputs.
//
// The limit is not expected to be a practical limitation; it's only supposed
// to prevent attempts at overflowing size calculations. For both kinds of
// pathnames, separate limits could be used; a common limit is used purely for
// simplicity.
//
#define VIRTIO_FS_MAX_PATHNAME_LENGTH ((UINTN)65535)
//
// Maximum value for VIRTIO_FS_FILE.NumFileInfo.
//
#define VIRTIO_FS_FILE_MAX_FILE_INFO 256
//
// Filesystem label encoded in UCS-2, transformed from the UTF-8 representation
// in "VIRTIO_FS_CONFIG.Tag", and NUL-terminated. Only the printable ASCII code
// points (U+0020 through U+007E) are supported.
//
typedef CHAR16 VIRTIO_FS_LABEL[VIRTIO_FS_TAG_BYTES + 1];
//
// Main context structure, expressing an EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
// interface on top of the Virtio Filesystem device.
//
typedef struct {
//
// Parts of this structure are initialized / torn down in various functions
// at various call depths. The table to the right should make it easier to
// track them.
//
// field init function init depth
// ----------- ------------------ ----------
UINT64 Signature; // DriverBindingStart 0
VIRTIO_DEVICE_PROTOCOL *Virtio; // DriverBindingStart 0
VIRTIO_FS_LABEL Label; // VirtioFsInit 1
UINT16 QueueSize; // VirtioFsInit 1
VRING Ring; // VirtioRingInit 2
VOID *RingMap; // VirtioRingMap 2
UINT64 RequestId; // FuseInitSession 1
UINT32 MaxWrite; // FuseInitSession 1
EFI_EVENT ExitBoot; // DriverBindingStart 0
LIST_ENTRY OpenFiles; // DriverBindingStart 0
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFs; // DriverBindingStart 0
} VIRTIO_FS;
#define VIRTIO_FS_FROM_SIMPLE_FS(SimpleFsReference) \
CR (SimpleFsReference, VIRTIO_FS, SimpleFs, VIRTIO_FS_SIG);
//
// Structure for describing a contiguous buffer, potentially mapped for Virtio
// transfer.
//
typedef struct {
//
// The following fields originate from the owner of the buffer.
//
VOID *Buffer;
UINTN Size;
//
// All of the fields below, until the end of the structure, are
// zero-initialized when the structure is initially validated.
//
// Mapped, MappedAddress and Mapping are updated when the buffer is mapped
// for VirtioOperationBusMasterRead or VirtioOperationBusMasterWrite. They
// are again updated when the buffer is unmapped.
//
BOOLEAN Mapped;
EFI_PHYSICAL_ADDRESS MappedAddress;
VOID *Mapping;
//
// Transferred is updated after VirtioFlush() returns successfully:
// - for VirtioOperationBusMasterRead, Transferred is set to Size;
// - for VirtioOperationBusMasterWrite, Transferred is calculated from the
// UsedLen output parameter of VirtioFlush().
//
UINTN Transferred;
} VIRTIO_FS_IO_VECTOR;
//
// Structure for describing a list of IO Vectors.
//
typedef struct {
//
// The following fields originate from the owner of the buffers.
//
VIRTIO_FS_IO_VECTOR *IoVec;
UINTN NumVec;
//
// TotalSize is calculated when the scatter-gather list is initially
// validated.
//
UINT32 TotalSize;
} VIRTIO_FS_SCATTER_GATHER_LIST;
//
// Private context structure that exposes EFI_FILE_PROTOCOL on top of an open
// FUSE file reference.
//
typedef struct {
UINT64 Signature;
EFI_FILE_PROTOCOL SimpleFile;
BOOLEAN IsDirectory;
BOOLEAN IsOpenForWriting;
VIRTIO_FS *OwnerFs;
LIST_ENTRY OpenFilesEntry;
CHAR8 *CanonicalPathname;
UINT64 FilePosition;
//
// In the FUSE wire protocol, every request except FUSE_INIT refers to a
// file, namely by the "VIRTIO_FS_FUSE_REQUEST.NodeId" field; that is, by the
// inode number of the file. However, some of the FUSE requests that we need
// for some of the EFI_FILE_PROTOCOL member functions require an open file
// handle *in addition* to the inode number. For simplicity, whenever a
// VIRTIO_FS_FILE object is created, primarily defined by its NodeId field,
// we also *open* the referenced file at once, and save the returned file
// handle in the FuseHandle field. This way, when an EFI_FILE_PROTOCOL member
// function must send a FUSE request that needs the file handle *in addition*
// to the inode number, FuseHandle will be at our disposal at once.
//
UINT64 NodeId;
UINT64 FuseHandle;
//
// EFI_FILE_INFO objects cached for an in-flight directory read.
//
// For reading through a directory stream with tolerable performance, we have
// to call FUSE_READDIRPLUS each time with such a buffer that can deliver a
// good number of variable size records (VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE
// elements). Every time we do that, we turn the whole bunch into an array of
// EFI_FILE_INFOs immediately. EFI_FILE_PROTOCOL.Read() invocations (on
// directories) will be served from this EFI_FILE_INFO cache.
//
UINT8 *FileInfoArray;
UINTN SingleFileInfoSize;
UINTN NumFileInfo;
UINTN NextFileInfo;
} VIRTIO_FS_FILE;
#define VIRTIO_FS_FILE_FROM_SIMPLE_FILE(SimpleFileReference) \
CR (SimpleFileReference, VIRTIO_FS_FILE, SimpleFile, VIRTIO_FS_FILE_SIG);
#define VIRTIO_FS_FILE_FROM_OPEN_FILES_ENTRY(OpenFilesEntryReference) \
CR (OpenFilesEntryReference, VIRTIO_FS_FILE, OpenFilesEntry, \
VIRTIO_FS_FILE_SIG);
//
// Initialization and helper routines for the Virtio Filesystem device.
//
EFI_STATUS
VirtioFsInit (
IN OUT VIRTIO_FS *VirtioFs
);
VOID
VirtioFsUninit (
IN OUT VIRTIO_FS *VirtioFs
);
VOID
EFIAPI
VirtioFsExitBoot (
IN EFI_EVENT ExitBootEvent,
IN VOID *VirtioFsAsVoid
);
EFI_STATUS
VirtioFsSgListsValidate (
IN VIRTIO_FS *VirtioFs,
IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList,
IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL
);
EFI_STATUS
VirtioFsSgListsSubmit (
IN OUT VIRTIO_FS *VirtioFs,
IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList,
IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL
);
EFI_STATUS
VirtioFsFuseNewRequest (
IN OUT VIRTIO_FS *VirtioFs,
OUT VIRTIO_FS_FUSE_REQUEST *Request,
IN UINT32 RequestSize,
IN VIRTIO_FS_FUSE_OPCODE Opcode,
IN UINT64 NodeId
);
EFI_STATUS
VirtioFsFuseCheckResponse (
IN VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList,
IN UINT64 RequestId,
OUT UINTN *TailBufferFill
);
EFI_STATUS
VirtioFsErrnoToEfiStatus (
IN INT32 Errno
);
EFI_STATUS
VirtioFsAppendPath (
IN CHAR8 *LhsPath8,
IN CHAR16 *RhsPath16,
OUT CHAR8 **ResultPath8,
OUT BOOLEAN *RootEscape
);
EFI_STATUS
VirtioFsLookupMostSpecificParentDir (
IN OUT VIRTIO_FS *VirtioFs,
IN OUT CHAR8 *Path,
OUT UINT64 *DirNodeId,
OUT CHAR8 **LastComponent
);
EFI_STATUS
VirtioFsGetBasename (
IN CHAR8 *Path,
OUT CHAR16 *Basename OPTIONAL,
IN OUT UINTN *BasenameSize
);
EFI_STATUS
VirtioFsComposeRenameDestination (
IN CHAR8 *LhsPath8,
IN CHAR16 *RhsPath16,
OUT CHAR8 **ResultPath8,
OUT BOOLEAN *RootEscape
);
EFI_STATUS
VirtioFsFuseAttrToEfiFileInfo (
IN VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr,
OUT EFI_FILE_INFO *FileInfo
);
EFI_STATUS
VirtioFsFuseDirentPlusToEfiFileInfo (
IN VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE *FuseDirent,
IN OUT EFI_FILE_INFO *FileInfo
);
VOID
VirtioFsGetFuseSizeUpdate (
IN EFI_FILE_INFO *Info,
IN EFI_FILE_INFO *NewInfo,
OUT BOOLEAN *Update,
OUT UINT64 *Size
);
//
// Wrapper functions for FUSE commands (primitives).
//
EFI_STATUS
VirtioFsFuseLookup (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 DirNodeId,
IN CHAR8 *Name,
OUT UINT64 *NodeId,
OUT VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr
);
EFI_STATUS
VirtioFsFuseForget (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 NodeId
);
EFI_STATUS
VirtioFsFuseGetAttr (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 NodeId,
OUT VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr
);
EFI_STATUS
VirtioFsFuseSetAttr (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 NodeId,
IN UINT64 *Size OPTIONAL,
IN UINT64 *Atime OPTIONAL,
IN UINT64 *Mtime OPTIONAL,
IN UINT32 *Mode OPTIONAL
);
EFI_STATUS
VirtioFsFuseMkDir (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 ParentNodeId,
IN CHAR8 *Name,
OUT UINT64 *NodeId
);
EFI_STATUS
VirtioFsFuseRemoveFileOrDir (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 ParentNodeId,
IN CHAR8 *Name,
IN BOOLEAN IsDir
);
EFI_STATUS
VirtioFsFuseOpen (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 NodeId,
IN BOOLEAN ReadWrite,
OUT UINT64 *FuseHandle
);
EFI_STATUS
VirtioFsFuseReadFileOrDir (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 NodeId,
IN UINT64 FuseHandle,
IN BOOLEAN IsDir,
IN UINT64 Offset,
IN OUT UINT32 *Size,
OUT VOID *Data
);
EFI_STATUS
VirtioFsFuseWrite (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 NodeId,
IN UINT64 FuseHandle,
IN UINT64 Offset,
IN OUT UINT32 *Size,
IN VOID *Data
);
EFI_STATUS
VirtioFsFuseStatFs (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 NodeId,
OUT VIRTIO_FS_FUSE_STATFS_RESPONSE *FilesysAttr
);
EFI_STATUS
VirtioFsFuseReleaseFileOrDir (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 NodeId,
IN UINT64 FuseHandle,
IN BOOLEAN IsDir
);
EFI_STATUS
VirtioFsFuseFsyncFileOrDir (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 NodeId,
IN UINT64 FuseHandle,
IN BOOLEAN IsDir
);
EFI_STATUS
VirtioFsFuseFlush (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 NodeId,
IN UINT64 FuseHandle
);
EFI_STATUS
VirtioFsFuseInitSession (
IN OUT VIRTIO_FS *VirtioFs
);
EFI_STATUS
VirtioFsFuseOpenDir (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 NodeId,
OUT UINT64 *FuseHandle
);
EFI_STATUS
VirtioFsFuseOpenOrCreate (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 ParentNodeId,
IN CHAR8 *Name,
OUT UINT64 *NodeId,
OUT UINT64 *FuseHandle
);
EFI_STATUS
VirtioFsFuseRename (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 OldParentNodeId,
IN CHAR8 *OldName,
IN UINT64 NewParentNodeId,
IN CHAR8 *NewName
);
//
// EFI_SIMPLE_FILE_SYSTEM_PROTOCOL member functions for the Virtio Filesystem
// driver.
//
EFI_STATUS
EFIAPI
VirtioFsOpenVolume (
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
OUT EFI_FILE_PROTOCOL **Root
);
//
// EFI_FILE_PROTOCOL member functions for the Virtio Filesystem driver.
//
EFI_STATUS
EFIAPI
VirtioFsSimpleFileClose (
IN EFI_FILE_PROTOCOL *This
);
EFI_STATUS
EFIAPI
VirtioFsSimpleFileDelete (
IN EFI_FILE_PROTOCOL *This
);
EFI_STATUS
EFIAPI
VirtioFsSimpleFileFlush (
IN EFI_FILE_PROTOCOL *This
);
EFI_STATUS
EFIAPI
VirtioFsSimpleFileGetInfo (
IN EFI_FILE_PROTOCOL *This,
IN EFI_GUID *InformationType,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
);
EFI_STATUS
EFIAPI
VirtioFsSimpleFileGetPosition (
IN EFI_FILE_PROTOCOL *This,
OUT UINT64 *Position
);
EFI_STATUS
EFIAPI
VirtioFsSimpleFileOpen (
IN EFI_FILE_PROTOCOL *This,
OUT EFI_FILE_PROTOCOL **NewHandle,
IN CHAR16 *FileName,
IN UINT64 OpenMode,
IN UINT64 Attributes
);
EFI_STATUS
EFIAPI
VirtioFsSimpleFileRead (
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
);
EFI_STATUS
EFIAPI
VirtioFsSimpleFileSetInfo (
IN EFI_FILE_PROTOCOL *This,
IN EFI_GUID *InformationType,
IN UINTN BufferSize,
IN VOID *Buffer
);
EFI_STATUS
EFIAPI
VirtioFsSimpleFileSetPosition (
IN EFI_FILE_PROTOCOL *This,
IN UINT64 Position
);
EFI_STATUS
EFIAPI
VirtioFsSimpleFileWrite (
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
IN VOID *Buffer
);
#endif // VIRTIO_FS_DXE_H_
|