mirror of
https://github.com/ziglang/zig.git
synced 2025-12-07 06:43:07 +00:00
668 lines
18 KiB
Zig
668 lines
18 KiB
Zig
const std = @import("std");
|
|
const mem = std.mem;
|
|
const uefi = std.os.uefi;
|
|
const Allocator = mem.Allocator;
|
|
const Guid = uefi.Guid;
|
|
|
|
pub const DevicePathProtocol = packed struct {
|
|
type: DevicePathType,
|
|
subtype: u8,
|
|
length: u16,
|
|
|
|
pub const guid align(8) = Guid{
|
|
.time_low = 0x09576e91,
|
|
.time_mid = 0x6d3f,
|
|
.time_high_and_version = 0x11d2,
|
|
.clock_seq_high_and_reserved = 0x8e,
|
|
.clock_seq_low = 0x39,
|
|
.node = [_]u8{ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b },
|
|
};
|
|
|
|
/// Returns the next DevicePathProtocol node in the sequence, if any.
|
|
pub fn next(self: *DevicePathProtocol) ?*DevicePathProtocol {
|
|
if (self.type == .End and @intToEnum(EndDevicePath.Subtype, self.subtype) == .EndEntire)
|
|
return null;
|
|
|
|
return @ptrCast(*DevicePathProtocol, @ptrCast([*]u8, self) + self.length);
|
|
}
|
|
|
|
/// Calculates the total length of the device path structure in bytes, including the end of device path node.
|
|
pub fn size(self: *DevicePathProtocol) usize {
|
|
var node = self;
|
|
|
|
while (node.next()) |next_node| {
|
|
node = next_node;
|
|
}
|
|
|
|
return (@ptrToInt(node) + node.length) - @ptrToInt(self);
|
|
}
|
|
|
|
/// Creates a file device path from the existing device path and a file path.
|
|
pub fn create_file_device_path(self: *DevicePathProtocol, allocator: Allocator, path: [:0]const u16) !*DevicePathProtocol {
|
|
var path_size = self.size();
|
|
|
|
// 2 * (path.len + 1) for the path and its null terminator, which are u16s
|
|
// DevicePathProtocol for the extra node before the end
|
|
var buf = try allocator.alloc(u8, path_size + 2 * (path.len + 1) + @sizeOf(DevicePathProtocol));
|
|
|
|
mem.copy(u8, buf, @ptrCast([*]const u8, self)[0..path_size]);
|
|
|
|
// Pointer to the copy of the end node of the current chain, which is - 4 from the buffer
|
|
// as the end node itself is 4 bytes (type: u8 + subtype: u8 + length: u16).
|
|
var new = @ptrCast(*MediaDevicePath.FilePathDevicePath, buf.ptr + path_size - 4);
|
|
|
|
new.type = .Media;
|
|
new.subtype = .FilePath;
|
|
new.length = @sizeOf(MediaDevicePath.FilePathDevicePath) + 2 * (@intCast(u16, path.len) + 1);
|
|
|
|
// The same as new.getPath(), but not const as we're filling it in.
|
|
var ptr = @ptrCast([*:0]u16, @alignCast(2, @ptrCast([*]u8, new)) + @sizeOf(MediaDevicePath.FilePathDevicePath));
|
|
|
|
for (path) |s, i|
|
|
ptr[i] = s;
|
|
|
|
ptr[path.len] = 0;
|
|
|
|
var end = @ptrCast(*EndDevicePath.EndEntireDevicePath, @ptrCast(*DevicePathProtocol, new).next().?);
|
|
end.type = .End;
|
|
end.subtype = .EndEntire;
|
|
end.length = @sizeOf(EndDevicePath.EndEntireDevicePath);
|
|
|
|
return @ptrCast(*DevicePathProtocol, buf.ptr);
|
|
}
|
|
|
|
pub fn getDevicePath(self: *const DevicePathProtocol) ?DevicePath {
|
|
inline for (@typeInfo(DevicePath).Union.fields) |ufield| {
|
|
const enum_value = std.meta.stringToEnum(DevicePathType, ufield.name);
|
|
|
|
// Got the associated union type for self.type, now
|
|
// we need to initialize it and its subtype
|
|
if (self.type == enum_value) {
|
|
var subtype = self.initSubtype(ufield.field_type);
|
|
|
|
if (subtype) |sb| {
|
|
// e.g. return .{ .Hardware = .{ .Pci = @ptrCast(...) } }
|
|
return @unionInit(DevicePath, ufield.name, sb);
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
pub fn initSubtype(self: *const DevicePathProtocol, comptime TUnion: type) ?TUnion {
|
|
const type_info = @typeInfo(TUnion).Union;
|
|
const TTag = type_info.tag_type.?;
|
|
|
|
inline for (type_info.fields) |subtype| {
|
|
// The tag names match the union names, so just grab that off the enum
|
|
const tag_val: u8 = @enumToInt(@field(TTag, subtype.name));
|
|
|
|
if (self.subtype == tag_val) {
|
|
// e.g. expr = .{ .Pci = @ptrCast(...) }
|
|
return @unionInit(TUnion, subtype.name, @ptrCast(subtype.field_type, self));
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
};
|
|
|
|
pub const DevicePath = union(DevicePathType) {
|
|
Hardware: HardwareDevicePath,
|
|
Acpi: AcpiDevicePath,
|
|
Messaging: MessagingDevicePath,
|
|
Media: MediaDevicePath,
|
|
BiosBootSpecification: BiosBootSpecificationDevicePath,
|
|
End: EndDevicePath,
|
|
};
|
|
|
|
pub const DevicePathType = enum(u8) {
|
|
Hardware = 0x01,
|
|
Acpi = 0x02,
|
|
Messaging = 0x03,
|
|
Media = 0x04,
|
|
BiosBootSpecification = 0x05,
|
|
End = 0x7f,
|
|
_,
|
|
};
|
|
|
|
pub const HardwareDevicePath = union(Subtype) {
|
|
Pci: *const PciDevicePath,
|
|
PcCard: *const PcCardDevicePath,
|
|
MemoryMapped: *const MemoryMappedDevicePath,
|
|
Vendor: *const VendorDevicePath,
|
|
Controller: *const ControllerDevicePath,
|
|
Bmc: *const BmcDevicePath,
|
|
|
|
pub const Subtype = enum(u8) {
|
|
Pci = 1,
|
|
PcCard = 2,
|
|
MemoryMapped = 3,
|
|
Vendor = 4,
|
|
Controller = 5,
|
|
Bmc = 6,
|
|
_,
|
|
};
|
|
|
|
pub const PciDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
function: u8,
|
|
device: u8,
|
|
};
|
|
|
|
pub const PcCardDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
function_number: u8,
|
|
};
|
|
|
|
pub const MemoryMappedDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
memory_type: u32,
|
|
start_address: u64,
|
|
end_address: u64,
|
|
};
|
|
|
|
pub const VendorDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
vendor_guid: Guid,
|
|
};
|
|
|
|
pub const ControllerDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
controller_number: u32,
|
|
};
|
|
|
|
pub const BmcDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
interface_type: u8,
|
|
base_address: usize,
|
|
};
|
|
};
|
|
|
|
pub const AcpiDevicePath = union(Subtype) {
|
|
Acpi: *const BaseAcpiDevicePath,
|
|
ExpandedAcpi: *const ExpandedAcpiDevicePath,
|
|
Adr: *const AdrDevicePath,
|
|
|
|
pub const Subtype = enum(u8) {
|
|
Acpi = 1,
|
|
ExpandedAcpi = 2,
|
|
Adr = 3,
|
|
_,
|
|
};
|
|
|
|
pub const BaseAcpiDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
hid: u32,
|
|
uid: u32,
|
|
};
|
|
|
|
pub const ExpandedAcpiDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
hid: u32,
|
|
uid: u32,
|
|
cid: u32,
|
|
// variable length u16[*:0] strings
|
|
// hid_str, uid_str, cid_str
|
|
};
|
|
|
|
pub const AdrDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
adr: u32,
|
|
// multiple adr entries can optionally follow
|
|
pub fn adrs(self: *const AdrDevicePath) []const u32 {
|
|
// self.length is a minimum of 8 with one adr which is size 4.
|
|
var entries = (self.length - 4) / @sizeOf(u32);
|
|
return @ptrCast([*]const u32, &self.adr)[0..entries];
|
|
}
|
|
};
|
|
};
|
|
|
|
pub const MessagingDevicePath = union(Subtype) {
|
|
Atapi: *const AtapiDevicePath,
|
|
Scsi: *const ScsiDevicePath,
|
|
FibreChannel: *const FibreChannelDevicePath,
|
|
FibreChannelEx: *const FibreChannelExDevicePath,
|
|
@"1394": *const F1394DevicePath,
|
|
Usb: *const UsbDevicePath,
|
|
Sata: *const SataDevicePath,
|
|
UsbWwid: *const UsbWwidDevicePath,
|
|
Lun: *const DeviceLogicalUnitDevicePath,
|
|
UsbClass: *const UsbClassDevicePath,
|
|
I2o: *const I2oDevicePath,
|
|
MacAddress: *const MacAddressDevicePath,
|
|
Ipv4: *const Ipv4DevicePath,
|
|
Ipv6: *const Ipv6DevicePath,
|
|
Vlan: *const VlanDevicePath,
|
|
InfiniBand: *const InfiniBandDevicePath,
|
|
Uart: *const UartDevicePath,
|
|
Vendor: *const VendorDefinedDevicePath,
|
|
|
|
pub const Subtype = enum(u8) {
|
|
Atapi = 1,
|
|
Scsi = 2,
|
|
FibreChannel = 3,
|
|
FibreChannelEx = 21,
|
|
@"1394" = 4,
|
|
Usb = 5,
|
|
Sata = 18,
|
|
UsbWwid = 16,
|
|
Lun = 17,
|
|
UsbClass = 15,
|
|
I2o = 6,
|
|
MacAddress = 11,
|
|
Ipv4 = 12,
|
|
Ipv6 = 13,
|
|
Vlan = 20,
|
|
InfiniBand = 9,
|
|
Uart = 14,
|
|
Vendor = 10,
|
|
_,
|
|
};
|
|
|
|
pub const AtapiDevicePath = packed struct {
|
|
const Role = enum(u8) {
|
|
Master = 0,
|
|
Slave = 1,
|
|
};
|
|
|
|
const Rank = enum(u8) {
|
|
Primary = 0,
|
|
Secondary = 1,
|
|
};
|
|
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
primary_secondary: Rank,
|
|
slave_master: Role,
|
|
logical_unit_number: u16,
|
|
};
|
|
|
|
pub const ScsiDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
target_id: u16,
|
|
logical_unit_number: u16,
|
|
};
|
|
|
|
pub const FibreChannelDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
reserved: u32,
|
|
world_wide_name: u64,
|
|
logical_unit_number: u64,
|
|
};
|
|
|
|
pub const FibreChannelExDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
reserved: u32,
|
|
world_wide_name: [8]u8,
|
|
logical_unit_number: [8]u8,
|
|
};
|
|
|
|
pub const F1394DevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
reserved: u32,
|
|
guid: u64,
|
|
};
|
|
|
|
pub const UsbDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
parent_port_number: u8,
|
|
interface_number: u8,
|
|
};
|
|
|
|
pub const SataDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
hba_port_number: u16,
|
|
port_multiplier_port_number: u16,
|
|
logical_unit_number: u16,
|
|
};
|
|
|
|
pub const UsbWwidDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
interface_number: u16,
|
|
device_vendor_id: u16,
|
|
device_product_id: u16,
|
|
|
|
pub fn serial_number(self: *const UsbWwidDevicePath) []const u16 {
|
|
var serial_len = (self.length - @sizeOf(UsbWwidDevicePath)) / @sizeOf(u16);
|
|
return @ptrCast([*]u16, @ptrCast([*]u8, self) + @sizeOf(UsbWwidDevicePath))[0..serial_len];
|
|
}
|
|
};
|
|
|
|
pub const DeviceLogicalUnitDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
lun: u8,
|
|
};
|
|
|
|
pub const UsbClassDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
vendor_id: u16,
|
|
product_id: u16,
|
|
device_class: u8,
|
|
device_subclass: u8,
|
|
device_protocol: u8,
|
|
};
|
|
|
|
pub const I2oDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
tid: u32,
|
|
};
|
|
|
|
pub const MacAddressDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
mac_address: uefi.MacAddress,
|
|
if_type: u8,
|
|
};
|
|
|
|
pub const Ipv4DevicePath = packed struct {
|
|
pub const IpType = enum(u8) {
|
|
Dhcp = 0,
|
|
Static = 1,
|
|
};
|
|
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
local_ip_address: uefi.Ipv4Address,
|
|
remote_ip_address: uefi.Ipv4Address,
|
|
local_port: u16,
|
|
remote_port: u16,
|
|
network_protocol: u16,
|
|
static_ip_address: IpType,
|
|
gateway_ip_address: u32,
|
|
subnet_mask: u32,
|
|
};
|
|
|
|
pub const Ipv6DevicePath = packed struct {
|
|
pub const Origin = enum(u8) {
|
|
Manual = 0,
|
|
AssignedStateless = 1,
|
|
AssignedStateful = 2,
|
|
};
|
|
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
local_ip_address: uefi.Ipv6Address,
|
|
remote_ip_address: uefi.Ipv6Address,
|
|
local_port: u16,
|
|
remote_port: u16,
|
|
protocol: u16,
|
|
ip_address_origin: Origin,
|
|
prefix_length: u8,
|
|
gateway_ip_address: uefi.Ipv6Address,
|
|
};
|
|
|
|
pub const VlanDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
vlan_id: u16,
|
|
};
|
|
|
|
pub const InfiniBandDevicePath = packed struct {
|
|
pub const ResourceFlags = packed struct {
|
|
pub const ControllerType = enum(u1) {
|
|
Ioc = 0,
|
|
Service = 1,
|
|
};
|
|
|
|
ioc_or_service: ControllerType,
|
|
extend_boot_environment: bool,
|
|
console_protocol: bool,
|
|
storage_protocol: bool,
|
|
network_protocol: bool,
|
|
|
|
// u1 + 4 * bool = 5 bits, we need a total of 32 bits
|
|
reserved: u27,
|
|
};
|
|
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
resource_flags: ResourceFlags,
|
|
port_gid: [16]u8,
|
|
service_id: u64,
|
|
target_port_id: u64,
|
|
device_id: u64,
|
|
};
|
|
|
|
pub const UartDevicePath = packed struct {
|
|
pub const Parity = enum(u8) {
|
|
Default = 0,
|
|
None = 1,
|
|
Even = 2,
|
|
Odd = 3,
|
|
Mark = 4,
|
|
Space = 5,
|
|
_,
|
|
};
|
|
|
|
pub const StopBits = enum(u8) {
|
|
Default = 0,
|
|
One = 1,
|
|
OneAndAHalf = 2,
|
|
Two = 3,
|
|
_,
|
|
};
|
|
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
reserved: u16,
|
|
baud_rate: u32,
|
|
data_bits: u8,
|
|
parity: Parity,
|
|
stop_bits: StopBits,
|
|
};
|
|
|
|
pub const VendorDefinedDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
vendor_guid: Guid,
|
|
};
|
|
};
|
|
|
|
pub const MediaDevicePath = union(Subtype) {
|
|
HardDrive: *const HardDriveDevicePath,
|
|
Cdrom: *const CdromDevicePath,
|
|
Vendor: *const VendorDevicePath,
|
|
FilePath: *const FilePathDevicePath,
|
|
MediaProtocol: *const MediaProtocolDevicePath,
|
|
PiwgFirmwareFile: *const PiwgFirmwareFileDevicePath,
|
|
PiwgFirmwareVolume: *const PiwgFirmwareVolumeDevicePath,
|
|
RelativeOffsetRange: *const RelativeOffsetRangeDevicePath,
|
|
RamDisk: *const RamDiskDevicePath,
|
|
|
|
pub const Subtype = enum(u8) {
|
|
HardDrive = 1,
|
|
Cdrom = 2,
|
|
Vendor = 3,
|
|
FilePath = 4,
|
|
MediaProtocol = 5,
|
|
PiwgFirmwareFile = 6,
|
|
PiwgFirmwareVolume = 7,
|
|
RelativeOffsetRange = 8,
|
|
RamDisk = 9,
|
|
_,
|
|
};
|
|
|
|
pub const HardDriveDevicePath = packed struct {
|
|
pub const Format = enum(u8) {
|
|
LegacyMbr = 0x01,
|
|
GuidPartitionTable = 0x02,
|
|
};
|
|
|
|
pub const SignatureType = enum(u8) {
|
|
NoSignature = 0x00,
|
|
/// "32-bit signature from address 0x1b8 of the type 0x01 MBR"
|
|
MbrSignature = 0x01,
|
|
GuidSignature = 0x02,
|
|
};
|
|
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
partition_number: u32,
|
|
partition_start: u64,
|
|
partition_size: u64,
|
|
partition_signature: [16]u8,
|
|
partition_format: Format,
|
|
signature_type: SignatureType,
|
|
};
|
|
|
|
pub const CdromDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
boot_entry: u32,
|
|
partition_start: u64,
|
|
partition_size: u64,
|
|
};
|
|
|
|
pub const VendorDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
guid: Guid,
|
|
// vendor-defined variable data
|
|
};
|
|
|
|
pub const FilePathDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
|
|
pub fn getPath(self: *const FilePathDevicePath) [*:0]const u16 {
|
|
return @ptrCast([*:0]const u16, @alignCast(2, @ptrCast([*]const u8, self)) + @sizeOf(FilePathDevicePath));
|
|
}
|
|
};
|
|
|
|
pub const MediaProtocolDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
guid: Guid,
|
|
};
|
|
|
|
pub const PiwgFirmwareFileDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
fv_filename: Guid,
|
|
};
|
|
|
|
pub const PiwgFirmwareVolumeDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
fv_name: Guid,
|
|
};
|
|
|
|
pub const RelativeOffsetRangeDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
reserved: u32,
|
|
start: u64,
|
|
end: u64,
|
|
};
|
|
|
|
pub const RamDiskDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
start: u64,
|
|
end: u64,
|
|
disk_type: Guid,
|
|
instance: u16,
|
|
};
|
|
};
|
|
|
|
pub const BiosBootSpecificationDevicePath = union(Subtype) {
|
|
BBS101: *const BBS101DevicePath,
|
|
|
|
pub const Subtype = enum(u8) {
|
|
BBS101 = 1,
|
|
_,
|
|
};
|
|
|
|
pub const BBS101DevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
device_type: u16,
|
|
status_flag: u16,
|
|
|
|
pub fn getDescription(self: *const BBS101DevicePath) [*:0]const u8 {
|
|
return @ptrCast([*:0]const u8, self) + @sizeOf(BBS101DevicePath);
|
|
}
|
|
};
|
|
};
|
|
|
|
pub const EndDevicePath = union(Subtype) {
|
|
EndEntire: *const EndEntireDevicePath,
|
|
EndThisInstance: *const EndThisInstanceDevicePath,
|
|
|
|
pub const Subtype = enum(u8) {
|
|
EndEntire = 0xff,
|
|
EndThisInstance = 0x01,
|
|
_,
|
|
};
|
|
|
|
pub const EndEntireDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
};
|
|
|
|
pub const EndThisInstanceDevicePath = packed struct {
|
|
type: DevicePathType,
|
|
subtype: Subtype,
|
|
length: u16,
|
|
};
|
|
};
|