Compare commits

...

3 Commits

Author SHA1 Message Date
anonymix007 f135f74e6c
Merge 18639361da into b7eefa1996 2024-11-21 13:01:29 +03:00
anonymix007 18639361da man: Document ukify --hwids= and --devicetree-auto= options 2024-11-17 20:56:38 +03:00
anonymix007 07879e662b ukify: Switch to JSON HWID description format 2024-11-17 20:56:33 +03:00
2 changed files with 45 additions and 65 deletions

View File

@ -71,6 +71,8 @@
<varname>Cmdline=</varname>/<option>--cmdline=</option>, <varname>Cmdline=</varname>/<option>--cmdline=</option>,
<varname>OSRelease=</varname>/<option>--os-release=</option>, <varname>OSRelease=</varname>/<option>--os-release=</option>,
<varname>DeviceTree=</varname>/<option>--devicetree=</option>, <varname>DeviceTree=</varname>/<option>--devicetree=</option>,
<varname>DeviceTreeAuto=</varname>/<option>--devicetree-auto=</option>,
<varname>HWIDs=</varname>/<option>--hwids=</option>,
<varname>Splash=</varname>/<option>--splash=</option>, <varname>Splash=</varname>/<option>--splash=</option>,
<varname>PCRPKey=</varname>/<option>--pcrpkey=</option>, <varname>PCRPKey=</varname>/<option>--pcrpkey=</option>,
<varname>Uname=</varname>/<option>--uname=</option>, <varname>Uname=</varname>/<option>--uname=</option>,
@ -373,6 +375,30 @@
<xi:include href="version-info.xml" xpointer="v253"/></listitem> <xi:include href="version-info.xml" xpointer="v253"/></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>DeviceTreeAuto=<replaceable>PATH</replaceable>...</varname></term>
<term><option>--devicetree-auto=<replaceable>PATH</replaceable></option></term>
<listitem><para>Zero or more automatically selectable DeviceTree files. In the configuration file, items are separated by
whitespace. Each DeviceTree will be in a separate <literal>.dtbauto</literal> section.</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>HWIDs=<replaceable>PATH</replaceable></varname></term>
<term><option>--hwids=<replaceable>PATH</replaceable></option></term>
<listitem><para>The hardware ID device table (the <literal>.hwids</literal> section). The argument is a
path to a directory with JSON HWID device description files. Each JSON file needs to contain <literal>name</literal>
and <literal>compatible</literal> strings and also array of CHIDs/HWIDs as <literal>hwids</literal>.
If not specified, the section will not be present. It is recommended to specify this parameter if automatically
selectable DeviceTrees are to be used.
</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>Uname=<replaceable>VERSION</replaceable></varname></term> <term><varname>Uname=<replaceable>VERSION</replaceable></varname></term>
<term><option>--uname=<replaceable>VERSION</replaceable></option></term> <term><option>--uname=<replaceable>VERSION</replaceable></option></term>

View File

@ -42,6 +42,7 @@ import subprocess
import sys import sys
import tempfile import tempfile
import textwrap import textwrap
import uuid
from collections.abc import Iterable, Iterator, Sequence from collections.abc import Iterable, Iterator, Sequence
from hashlib import sha256 from hashlib import sha256
from pathlib import Path from pathlib import Path
@ -1013,14 +1014,9 @@ def merge_sbat(input_pe: list[Path], input_text: list[str]) -> str:
) )
# Keep in sync with EFI_GUID (src/boot/efi.h)
# uint32_t Data1, uint16_t Data2, uint16_t Data3, uint8_t Data4[8]
EFI_GUID = tuple[int, int, int, tuple[int, int, int, int, int, int, int, int]]
EFI_GUID_STRUCT_SIZE = 4 + 2 + 2 + 1 * 8
# Keep in sync with Device (DEVICE_TYPE_DEVICETREE) from src/boot/chid.h # Keep in sync with Device (DEVICE_TYPE_DEVICETREE) from src/boot/chid.h
# uint32_t descriptor, EFI_GUID chid, uint32_t name_offset, uint32_t compatible_offset # uint32_t descriptor, EFI_GUID chid, uint32_t name_offset, uint32_t compatible_offset
DEVICE_STRUCT_SIZE = 4 + EFI_GUID_STRUCT_SIZE + 4 + 4 DEVICE_STRUCT_SIZE = 4 + 16 + 4 + 4
NULL_DEVICE = b'\0' * DEVICE_STRUCT_SIZE NULL_DEVICE = b'\0' * DEVICE_STRUCT_SIZE
DEVICE_TYPE_DEVICETREE = 1 DEVICE_TYPE_DEVICETREE = 1
@ -1029,29 +1025,21 @@ def device_make_descriptor(device_type: int, size: int) -> int:
return (size) | (device_type << 28) return (size) | (device_type << 28)
def pack_device(offsets: dict[str, int], name: str, compatible: str, chids: list[EFI_GUID]) -> bytes: DEVICETREE_DESCRIPTOR = device_make_descriptor(DEVICE_TYPE_DEVICETREE, DEVICE_STRUCT_SIZE)
def pack_device(offsets: dict[str, int], name: str, compatible: str, chids: list[uuid.UUID]) -> bytes:
data = b'' data = b''
for data1, data2, data3, data4 in chids: for chid in chids:
data += struct.pack( data += struct.pack('<I', DEVICETREE_DESCRIPTOR)
'<IIHH8BII', data += chid.bytes_le
device_make_descriptor(DEVICE_TYPE_DEVICETREE, DEVICE_STRUCT_SIZE), data += struct.pack('<II', offsets[name], offsets[compatible])
data1,
data2,
data3,
*data4,
offsets[name],
offsets[compatible],
)
assert len(data) == DEVICE_STRUCT_SIZE * len(chids) assert len(data) == DEVICE_STRUCT_SIZE * len(chids)
return data return data
def hex_pairs_list(string: str) -> list[int]:
return [int(string[i : i + 2], 16) for i in range(0, len(string), 2)]
def pack_strings(strings: set[str], base: int) -> tuple[bytes, dict[str, int]]: def pack_strings(strings: set[str], base: int) -> tuple[bytes, dict[str, int]]:
blob = b'' blob = b''
offsets = {} offsets = {}
@ -1064,56 +1052,22 @@ def pack_strings(strings: set[str], base: int) -> tuple[bytes, dict[str, int]]:
def parse_hwid_dir(path: Path) -> bytes: def parse_hwid_dir(path: Path) -> bytes:
hwid_files = path.rglob('*.txt') hwid_files = path.rglob('*.json')
strings: set[str] = set() strings: set[str] = set()
devices: collections.defaultdict[tuple[str, str], list[EFI_GUID]] = collections.defaultdict(list) devices: collections.defaultdict[tuple[str, str], list[uuid.UUID]] = collections.defaultdict(list)
uuid_regexp = re.compile(
r'\{[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}\}', re.I
)
for hwid_file in hwid_files: for hwid_file in hwid_files:
content = hwid_file.open().readlines() data = json.loads(hwid_file.read_text(encoding='UTF-8'))
data: dict[str, str] = { for k in ['name', 'compatible', 'hwids']:
'Manufacturer': '', if k not in data:
'Family': '',
'Compatible': '',
}
uuids: list[EFI_GUID] = []
for line in content:
for k in data:
if line.startswith(k):
data[k] = line.split(':')[1].strip()
break
else:
uuid = uuid_regexp.match(line)
if uuid is not None:
d1, d2, d3, d4, d5 = uuid.group(0)[1:-1].split('-')
data1 = int(d1, 16)
data2 = int(d2, 16)
data3 = int(d3, 16)
data4 = cast(
tuple[int, int, int, int, int, int, int, int],
tuple(hex_pairs_list(d4) + hex_pairs_list(d5)),
)
uuids.append((data1, data2, data3, data4))
for k, v in data.items():
if not v:
raise ValueError(f'hwid description file "{hwid_file}" does not contain "{k}"') raise ValueError(f'hwid description file "{hwid_file}" does not contain "{k}"')
name = data['Manufacturer'] + ' ' + data['Family'] strings |= set([data['name'], data['compatible']])
compatible = data['Compatible']
strings |= set([name, compatible]) # (name, compatible) pair uniquely identifies the device
devices[(data['name'], data['compatible'])] += [uuid.UUID(u) for u in data['hwids']]
# (compatible, name) pair uniquely identifies the device
devices[(compatible, name)] += uuids
total_device_structs = 1 total_device_structs = 1
for dev, uuids in devices.items(): for dev, uuids in devices.items():
@ -1122,7 +1076,7 @@ def parse_hwid_dir(path: Path) -> bytes:
strings_blob, offsets = pack_strings(strings, total_device_structs * DEVICE_STRUCT_SIZE) strings_blob, offsets = pack_strings(strings, total_device_structs * DEVICE_STRUCT_SIZE)
devices_blob = b'' devices_blob = b''
for (compatible, name), uuids in devices.items(): for (name, compatible), uuids in devices.items():
devices_blob += pack_device(offsets, name, compatible, uuids) devices_blob += pack_device(offsets, name, compatible, uuids)
devices_blob += NULL_DEVICE devices_blob += NULL_DEVICE