1const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;
3
4pub const DevicePathProtocol = packed struct {
5    type: DevicePathType,
6    subtype: u8,
7    length: u16,
8
9    pub const guid align(8) = Guid{
10        .time_low = 0x09576e91,
11        .time_mid = 0x6d3f,
12        .time_high_and_version = 0x11d2,
13        .clock_seq_high_and_reserved = 0x8e,
14        .clock_seq_low = 0x39,
15        .node = [_]u8{ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b },
16    };
17
18    pub fn getDevicePath(self: *const DevicePathProtocol) ?DevicePath {
19        return switch (self.type) {
20            .Hardware => blk: {
21                const hardware: ?HardwareDevicePath = switch (@intToEnum(HardwareDevicePath.Subtype, self.subtype)) {
22                    .Pci => .{ .Pci = @ptrCast(*const HardwareDevicePath.PciDevicePath, self) },
23                    .PcCard => .{ .PcCard = @ptrCast(*const HardwareDevicePath.PcCardDevicePath, self) },
24                    .MemoryMapped => .{ .MemoryMapped = @ptrCast(*const HardwareDevicePath.MemoryMappedDevicePath, self) },
25                    .Vendor => .{ .Vendor = @ptrCast(*const HardwareDevicePath.VendorDevicePath, self) },
26                    .Controller => .{ .Controller = @ptrCast(*const HardwareDevicePath.ControllerDevicePath, self) },
27                    .Bmc => .{ .Bmc = @ptrCast(*const HardwareDevicePath.BmcDevicePath, self) },
28                    _ => null,
29                };
30                break :blk if (hardware) |h| .{ .Hardware = h } else null;
31            },
32            .Acpi => blk: {
33                const acpi: ?AcpiDevicePath = switch (@intToEnum(AcpiDevicePath.Subtype, self.subtype)) {
34                    else => null, // TODO
35                };
36                break :blk if (acpi) |a| .{ .Acpi = a } else null;
37            },
38            .Messaging => blk: {
39                const messaging: ?MessagingDevicePath = switch (@intToEnum(MessagingDevicePath.Subtype, self.subtype)) {
40                    else => null, // TODO
41                };
42                break :blk if (messaging) |m| .{ .Messaging = m } else null;
43            },
44            .Media => blk: {
45                const media: ?MediaDevicePath = switch (@intToEnum(MediaDevicePath.Subtype, self.subtype)) {
46                    .HardDrive => .{ .HardDrive = @ptrCast(*const MediaDevicePath.HardDriveDevicePath, self) },
47                    .Cdrom => .{ .Cdrom = @ptrCast(*const MediaDevicePath.CdromDevicePath, self) },
48                    .Vendor => .{ .Vendor = @ptrCast(*const MediaDevicePath.VendorDevicePath, self) },
49                    .FilePath => .{ .FilePath = @ptrCast(*const MediaDevicePath.FilePathDevicePath, self) },
50                    .MediaProtocol => .{ .MediaProtocol = @ptrCast(*const MediaDevicePath.MediaProtocolDevicePath, self) },
51                    .PiwgFirmwareFile => .{ .PiwgFirmwareFile = @ptrCast(*const MediaDevicePath.PiwgFirmwareFileDevicePath, self) },
52                    .PiwgFirmwareVolume => .{ .PiwgFirmwareVolume = @ptrCast(*const MediaDevicePath.PiwgFirmwareVolumeDevicePath, self) },
53                    .RelativeOffsetRange => .{ .RelativeOffsetRange = @ptrCast(*const MediaDevicePath.RelativeOffsetRangeDevicePath, self) },
54                    .RamDisk => .{ .RamDisk = @ptrCast(*const MediaDevicePath.RamDiskDevicePath, self) },
55                    _ => null,
56                };
57                break :blk if (media) |m| .{ .Media = m } else null;
58            },
59            .BiosBootSpecification => blk: {
60                const bbs: ?BiosBootSpecificationDevicePath = switch (@intToEnum(BiosBootSpecificationDevicePath.Subtype, self.subtype)) {
61                    .BBS101 => .{ .BBS101 = @ptrCast(*const BiosBootSpecificationDevicePath.BBS101DevicePath, self) },
62                    _ => null,
63                };
64                break :blk if (bbs) |b| .{ .BiosBootSpecification = b } else null;
65            },
66            .End => blk: {
67                const end: ?EndDevicePath = switch (@intToEnum(EndDevicePath.Subtype, self.subtype)) {
68                    .EndEntire => .{ .EndEntire = @ptrCast(*const EndDevicePath.EndEntireDevicePath, self) },
69                    .EndThisInstance => .{ .EndThisInstance = @ptrCast(*const EndDevicePath.EndThisInstanceDevicePath, self) },
70                    _ => null,
71                };
72                break :blk if (end) |e| .{ .End = e } else null;
73            },
74            _ => null,
75        };
76    }
77};
78
79pub const DevicePath = union(DevicePathType) {
80    Hardware: HardwareDevicePath,
81    Acpi: AcpiDevicePath,
82    Messaging: MessagingDevicePath,
83    Media: MediaDevicePath,
84    BiosBootSpecification: BiosBootSpecificationDevicePath,
85    End: EndDevicePath,
86};
87
88pub const DevicePathType = enum(u8) {
89    Hardware = 0x01,
90    Acpi = 0x02,
91    Messaging = 0x03,
92    Media = 0x04,
93    BiosBootSpecification = 0x05,
94    End = 0x7f,
95    _,
96};
97
98pub const HardwareDevicePath = union(Subtype) {
99    Pci: *const PciDevicePath,
100    PcCard: *const PcCardDevicePath,
101    MemoryMapped: *const MemoryMappedDevicePath,
102    Vendor: *const VendorDevicePath,
103    Controller: *const ControllerDevicePath,
104    Bmc: *const BmcDevicePath,
105
106    pub const Subtype = enum(u8) {
107        Pci = 1,
108        PcCard = 2,
109        MemoryMapped = 3,
110        Vendor = 4,
111        Controller = 5,
112        Bmc = 6,
113        _,
114    };
115
116    pub const PciDevicePath = packed struct {
117        type: DevicePathType,
118        subtype: Subtype,
119        length: u16,
120        // TODO
121    };
122
123    pub const PcCardDevicePath = packed struct {
124        type: DevicePathType,
125        subtype: Subtype,
126        length: u16,
127        // TODO
128    };
129
130    pub const MemoryMappedDevicePath = packed struct {
131        type: DevicePathType,
132        subtype: Subtype,
133        length: u16,
134        // TODO
135    };
136
137    pub const VendorDevicePath = packed struct {
138        type: DevicePathType,
139        subtype: Subtype,
140        length: u16,
141        // TODO
142    };
143
144    pub const ControllerDevicePath = packed struct {
145        type: DevicePathType,
146        subtype: Subtype,
147        length: u16,
148        // TODO
149    };
150
151    pub const BmcDevicePath = packed struct {
152        type: DevicePathType,
153        subtype: Subtype,
154        length: u16,
155        // TODO
156    };
157};
158
159pub const AcpiDevicePath = union(Subtype) {
160    Acpi: void, // TODO
161    ExpandedAcpi: void, // TODO
162    Adr: void, // TODO
163    Nvdimm: void, // TODO
164
165    pub const Subtype = enum(u8) {
166        Acpi = 1,
167        ExpandedAcpi = 2,
168        Adr = 3,
169        Nvdimm = 4,
170        _,
171    };
172};
173
174pub const MessagingDevicePath = union(Subtype) {
175    Atapi: void, // TODO
176    Scsi: void, // TODO
177    FibreChannel: void, // TODO
178    FibreChannelEx: void, // TODO
179    @"1394": void, // TODO
180    Usb: void, // TODO
181    Sata: void, // TODO
182    UsbWwid: void, // TODO
183    Lun: void, // TODO
184    UsbClass: void, // TODO
185    I2o: void, // TODO
186    MacAddress: void, // TODO
187    Ipv4: void, // TODO
188    Ipv6: void, // TODO
189    Vlan: void, // TODO
190    InfiniBand: void, // TODO
191    Uart: void, // TODO
192    Vendor: void, // TODO
193
194    pub const Subtype = enum(u8) {
195        Atapi = 1,
196        Scsi = 2,
197        FibreChannel = 3,
198        FibreChannelEx = 21,
199        @"1394" = 4,
200        Usb = 5,
201        Sata = 18,
202        UsbWwid = 16,
203        Lun = 17,
204        UsbClass = 15,
205        I2o = 6,
206        MacAddress = 11,
207        Ipv4 = 12,
208        Ipv6 = 13,
209        Vlan = 20,
210        InfiniBand = 9,
211        Uart = 14,
212        Vendor = 10,
213        _,
214    };
215};
216
217pub const MediaDevicePath = union(Subtype) {
218    HardDrive: *const HardDriveDevicePath,
219    Cdrom: *const CdromDevicePath,
220    Vendor: *const VendorDevicePath,
221    FilePath: *const FilePathDevicePath,
222    MediaProtocol: *const MediaProtocolDevicePath,
223    PiwgFirmwareFile: *const PiwgFirmwareFileDevicePath,
224    PiwgFirmwareVolume: *const PiwgFirmwareVolumeDevicePath,
225    RelativeOffsetRange: *const RelativeOffsetRangeDevicePath,
226    RamDisk: *const RamDiskDevicePath,
227
228    pub const Subtype = enum(u8) {
229        HardDrive = 1,
230        Cdrom = 2,
231        Vendor = 3,
232        FilePath = 4,
233        MediaProtocol = 5,
234        PiwgFirmwareFile = 6,
235        PiwgFirmwareVolume = 7,
236        RelativeOffsetRange = 8,
237        RamDisk = 9,
238        _,
239    };
240
241    pub const HardDriveDevicePath = packed struct {
242        type: DevicePathType,
243        subtype: Subtype,
244        length: u16,
245        // TODO
246    };
247
248    pub const CdromDevicePath = packed struct {
249        type: DevicePathType,
250        subtype: Subtype,
251        length: u16,
252        // TODO
253    };
254
255    pub const VendorDevicePath = packed struct {
256        type: DevicePathType,
257        subtype: Subtype,
258        length: u16,
259        // TODO
260    };
261
262    pub const FilePathDevicePath = packed struct {
263        type: DevicePathType,
264        subtype: Subtype,
265        length: u16,
266
267        pub fn getPath(self: *const FilePathDevicePath) [*:0]const u16 {
268            return @ptrCast([*:0]const u16, @alignCast(2, @ptrCast([*]const u8, self)) + @sizeOf(FilePathDevicePath));
269        }
270    };
271
272    pub const MediaProtocolDevicePath = packed struct {
273        type: DevicePathType,
274        subtype: Subtype,
275        length: u16,
276        // TODO
277    };
278
279    pub const PiwgFirmwareFileDevicePath = packed struct {
280        type: DevicePathType,
281        subtype: Subtype,
282        length: u16,
283    };
284
285    pub const PiwgFirmwareVolumeDevicePath = packed struct {
286        type: DevicePathType,
287        subtype: Subtype,
288        length: u16,
289    };
290
291    pub const RelativeOffsetRangeDevicePath = packed struct {
292        type: DevicePathType,
293        subtype: Subtype,
294        length: u16,
295        reserved: u32,
296        start: u64,
297        end: u64,
298    };
299
300    pub const RamDiskDevicePath = packed struct {
301        type: DevicePathType,
302        subtype: Subtype,
303        length: u16,
304        start: u64,
305        end: u64,
306        disk_type: uefi.Guid,
307        instance: u16,
308    };
309};
310
311pub const BiosBootSpecificationDevicePath = union(Subtype) {
312    BBS101: *const BBS101DevicePath,
313
314    pub const Subtype = enum(u8) {
315        BBS101 = 1,
316        _,
317    };
318
319    pub const BBS101DevicePath = packed struct {
320        type: DevicePathType,
321        subtype: Subtype,
322        length: u16,
323        device_type: u16,
324        status_flag: u16,
325
326        pub fn getDescription(self: *const BBS101DevicePath) [*:0]const u8 {
327            return @ptrCast([*:0]const u8, self) + @sizeOf(BBS101DevicePath);
328        }
329    };
330};
331
332pub const EndDevicePath = union(Subtype) {
333    EndEntire: *const EndEntireDevicePath,
334    EndThisInstance: *const EndThisInstanceDevicePath,
335
336    pub const Subtype = enum(u8) {
337        EndEntire = 0xff,
338        EndThisInstance = 0x01,
339        _,
340    };
341
342    pub const EndEntireDevicePath = packed struct {
343        type: DevicePathType,
344        subtype: Subtype,
345        length: u16,
346    };
347
348    pub const EndThisInstanceDevicePath = packed struct {
349        type: DevicePathType,
350        subtype: Subtype,
351        length: u16,
352    };
353};
354