1use num_derive::{FromPrimitive, ToPrimitive};
6use zerocopy::byteorder::little_endian::U32;
7use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
8
9const ZBI_MAX_SMT: usize = 4;
10
11pub const ZBI_CONTAINER_MAGIC: u32 = 0x868c_f7e6;
13
14pub const ZBI_ITEM_MAGIC: u32 = 0xb578_1729;
16
17pub const ZBI_FLAGS_VERSION: u32 = 0x0001_0000;
19
20pub const ZBI_FLAGS_CRC32: u32 = 0x0002_0000;
23
24pub const ZBI_ITEM_NO_CRC32: u32 = 0x4a87_e8d6;
26
27pub const ZBI_ALIGNMENT_BYTES: u32 = 0x8;
29
30pub fn is_zbi_type_driver_metadata(zbi_type_raw: u32) -> bool {
31 (zbi_type_raw & 0xFF) == ZbiType::DriverMetadata.into_raw()
32}
33
34#[repr(u32)]
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
36pub enum ZbiType {
39 Container = 0x544f_4f42, Cmdline = 0x4c44_4d43, Crashlog = 0x4d4f_4f42, KernelDriver = 0x5652_444B, PlatformId = 0x4449_4C50, StorageBootfsFactory = 0x4653_4642, StorageRamdisk = 0x4b53_4452, ImageArgs = 0x4752_4149, SerialNumber = 0x4e4c_5253, BootloaderFile = 0x4C46_5442, DeviceTree = 0xd00d_feed, CpuTopology = 0x544f_504f, AcpiRsdp = 0x5044_5352, Smbios = 0x4942_4d53, Framebuffer = 0x4246_5753, DriverMetadata = 0x6D,
58 Unknown,
59}
60
61impl ZbiType {
62 pub fn from_raw(raw: u32) -> Self {
63 match raw {
64 x if x == ZbiType::Container.into_raw() => ZbiType::Container,
65 x if x == ZbiType::Cmdline.into_raw() => ZbiType::Cmdline,
66 x if x == ZbiType::Crashlog.into_raw() => ZbiType::Crashlog,
67 x if x == ZbiType::KernelDriver.into_raw() => ZbiType::KernelDriver,
68 x if x == ZbiType::PlatformId.into_raw() => ZbiType::PlatformId,
69 x if x == ZbiType::StorageBootfsFactory.into_raw() => ZbiType::StorageBootfsFactory,
70 x if x == ZbiType::StorageRamdisk.into_raw() => ZbiType::StorageRamdisk,
71 x if x == ZbiType::ImageArgs.into_raw() => ZbiType::ImageArgs,
72 x if x == ZbiType::SerialNumber.into_raw() => ZbiType::SerialNumber,
73 x if x == ZbiType::BootloaderFile.into_raw() => ZbiType::BootloaderFile,
74 x if x == ZbiType::DeviceTree.into_raw() => ZbiType::DeviceTree,
75 x if x == ZbiType::CpuTopology.into_raw() => ZbiType::CpuTopology,
76 x if x == ZbiType::AcpiRsdp.into_raw() => ZbiType::AcpiRsdp,
77 x if x == ZbiType::Smbios.into_raw() => ZbiType::Smbios,
78 x if x == ZbiType::Framebuffer.into_raw() => ZbiType::Framebuffer,
79 x if is_zbi_type_driver_metadata(x) => ZbiType::DriverMetadata,
80 _ => ZbiType::Unknown,
81 }
82 }
83
84 pub fn into_raw(self) -> u32 {
85 self as u32
86 }
87}
88
89#[repr(C)]
90#[derive(Debug, Default, Copy, Clone, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
91pub struct zbi_header_t {
92 pub zbi_type: U32,
93 pub length: U32,
94 pub extra: U32,
95 pub flags: U32,
96 pub reserved_0: U32,
97 pub reserved_1: U32,
98 pub magic: U32,
99 pub crc32: U32,
100}
101
102pub fn zbi_container_header(length: u32) -> zbi_header_t {
104 zbi_header_t {
105 zbi_type: U32::new(ZbiType::Container.into_raw()),
106 length: U32::new(length),
107 extra: U32::new(ZBI_CONTAINER_MAGIC),
108 flags: U32::new(ZBI_FLAGS_VERSION),
109 reserved_0: U32::new(0),
110 reserved_1: U32::new(0),
111 magic: U32::new(ZBI_ITEM_MAGIC),
112 crc32: U32::new(ZBI_ITEM_NO_CRC32),
113 }
114}
115
116#[repr(C)]
117#[derive(Copy, Clone, KnownLayout, FromBytes, Immutable)]
118pub struct ZbiTopologyNode {
121 pub entity_type: u8,
123 pub parent_index: u16,
124 pub entity: Entity,
125}
126
127#[repr(u8)]
128#[derive(FromPrimitive, ToPrimitive)]
129pub enum ZbiTopologyEntityType {
130 ZbiTopologyEntityUndefined = 0,
131 ZbiTopologyEntityProcessor = 1,
132 ZbiTopologyEntityCluster = 2,
133 ZbiTopologyEntityCache = 3,
134 ZbiTopologyEntityDie = 4,
135 ZbiTopologyEntitySocket = 5,
136 ZbiTopologyEntityPowerPlane = 6,
137 ZbiTopologyEntityNumaRegion = 7,
138}
139
140#[repr(u8)]
141#[derive(FromPrimitive, ToPrimitive)]
142pub enum ZbiTopologyArchitecture {
143 ZbiTopologyArchUndefined = 0,
144 ZbiTopologyArchX64 = 1,
145 ZbiTopologyArchArm64 = 2,
146}
147
148#[repr(C)]
149#[derive(Copy, Clone, KnownLayout, FromBytes, Immutable)]
150pub union Entity {
151 pub processor: ZbiTopologyProcessor,
152 pub cluster: ZbiTopologyCluster,
153 pub numa_region: ZbiTopologyNumaRegion,
154 pub cache: ZbiTopologyCache,
155}
156
157#[repr(C)]
158#[derive(Copy, Clone, KnownLayout, FromBytes, Immutable)]
159pub struct ZbiTopologyProcessor {
160 pub logical_ids: [u16; ZBI_MAX_SMT],
161 pub logical_id_count: u8,
162 pub flags: u16,
163
164 pub architecture: u8,
167 pub architecture_info: ArchitectureInfo,
168}
169
170#[repr(C)]
171#[derive(Copy, Clone, KnownLayout, FromBytes, Immutable)]
172pub union ArchitectureInfo {
173 pub arm64: ZbiTopologyArm64Info,
174 pub x64: ZbiTopologyX64Info,
175}
176
177#[repr(C)]
178#[derive(Copy, Clone, KnownLayout, FromBytes, Immutable)]
179pub struct ZbiTopologyCluster {
180 pub performance_class: u8,
183}
184
185#[repr(C)]
186#[derive(Copy, Clone, KnownLayout, FromBytes, Immutable)]
187pub struct ZbiTopologyNumaRegion {
188 pub start_address: u64,
190 pub end_address: u64,
191}
192
193#[repr(C)]
194#[derive(Copy, Clone, KnownLayout, FromBytes, Immutable)]
195pub struct ZbiTopologyCache {
196 pub cache_id: u32,
198}
199
200#[repr(C)]
201#[derive(Copy, Clone, KnownLayout, FromBytes, Immutable)]
202pub struct ZbiTopologyArm64Info {
203 pub cluster_1_id: u8,
206 pub cluster_2_id: u8,
207 pub cluster_3_id: u8,
208
209 pub cpu_id: u8,
211
212 pub gic_id: u8,
216}
217
218#[repr(C)]
219#[derive(Copy, Clone, KnownLayout, FromBytes, Immutable)]
220pub struct ZbiTopologyX64Info {
221 pub apic_ids: [u32; ZBI_MAX_SMT],
223 pub apic_id_count: u32,
224}
225
226#[cfg(test)]
227mod tests {
228 use super::*;
229
230 const MAX_SERIALIZATION_BUFFER_SIZE: usize = 128;
231
232 extern "C" {
234 pub fn serialize_zbi_topology_x64_info_t(
235 buffer: &[u8; MAX_SERIALIZATION_BUFFER_SIZE],
236 apic_ids: &[u32; 4],
237 apic_id_count: u32,
238 ) -> usize;
239
240 pub fn serialize_zbi_topology_arm64_info_t(
241 buffer: &[u8; MAX_SERIALIZATION_BUFFER_SIZE],
242 cluster_1_id: u8,
243 cluster_2_id: u8,
244 cluster_3_id: u8,
245 cpu_id: u8,
246 gic_id: u8,
247 ) -> usize;
248
249 pub fn serialize_zbi_topology_cache_t(
250 buffer: &[u8; MAX_SERIALIZATION_BUFFER_SIZE],
251 cache_id: u32,
252 ) -> usize;
253
254 pub fn serialize_zbi_topology_numa_region_v2_t(
255 buffer: &[u8; MAX_SERIALIZATION_BUFFER_SIZE],
256 start_address: u64,
257 end_address: u64,
258 ) -> usize;
259
260 pub fn serialize_zbi_topology_cluster_t(
261 buffer: &[u8; MAX_SERIALIZATION_BUFFER_SIZE],
262 performance_class: u8,
263 ) -> usize;
264
265 pub fn serialize_zbi_topology_processor_v2_t(
266 buffer: &[u8; MAX_SERIALIZATION_BUFFER_SIZE],
267 logical_ids: &[u16; 4],
268 logical_id_count: u8,
269 flags: u16,
270 architecture: u8,
271 architecture_info: ArchitectureInfo,
272 ) -> usize;
273
274 pub fn serialize_zbi_topology_node_v2_t(
275 buffer: &[u8; MAX_SERIALIZATION_BUFFER_SIZE],
276 entity_type: u8,
277 parent_index: u16,
278 entity: Entity,
279 ) -> usize;
280 }
281
282 unsafe fn as_u8_slice<T: Sized>(p: &T) -> &[u8] {
283 std::slice::from_raw_parts((p as *const T) as *const u8, ::std::mem::size_of::<T>())
284 }
285
286 #[fuchsia::test]
287 fn zbi_topology_x64_info_in_sync() {
288 let apic_ids = [0, 1, 3, 4];
289 let apic_id_count = 4;
290
291 let buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
292 let size = unsafe { serialize_zbi_topology_x64_info_t(&buffer, &apic_ids, apic_id_count) };
293 assert_eq!(size, std::mem::size_of::<ZbiTopologyX64Info>());
294
295 let x64_info = ZbiTopologyX64Info { apic_ids, apic_id_count };
296 assert_eq!(unsafe { as_u8_slice(&x64_info) }, &buffer[0..size]);
297 }
298
299 #[fuchsia::test]
300 fn zbi_topology_arm_info_in_sync() {
301 let cluster_1_id = 1;
302 let cluster_2_id = 2;
303 let cluster_3_id = 3;
304 let cpu_id = 0;
305 let gic_id = 1;
306
307 let buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
308 let size = unsafe {
309 serialize_zbi_topology_arm64_info_t(
310 &buffer,
311 cluster_1_id,
312 cluster_2_id,
313 cluster_3_id,
314 cpu_id,
315 gic_id,
316 )
317 };
318 assert_eq!(size, std::mem::size_of::<ZbiTopologyArm64Info>());
319
320 let arm_info =
321 ZbiTopologyArm64Info { cluster_1_id, cluster_2_id, cluster_3_id, cpu_id, gic_id };
322 assert_eq!(unsafe { as_u8_slice(&arm_info) }, &buffer[0..size]);
323 }
324
325 #[fuchsia::test]
326 fn zbi_topology_cache_in_sync() {
327 let cache_id = 1221;
328
329 let buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
330 let size = unsafe { serialize_zbi_topology_cache_t(&buffer, cache_id) };
331 assert_eq!(size, std::mem::size_of::<ZbiTopologyCache>());
332
333 let cache = ZbiTopologyCache { cache_id };
334 assert_eq!(unsafe { as_u8_slice(&cache) }, &buffer[0..size]);
335 }
336
337 #[fuchsia::test]
338 fn zbi_topology_numa_region_in_sync() {
339 let start_address = 1221;
340 let end_address = 1223;
341
342 let buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
343 let size =
344 unsafe { serialize_zbi_topology_numa_region_v2_t(&buffer, start_address, end_address) };
345 assert_eq!(size, std::mem::size_of::<ZbiTopologyNumaRegion>());
346
347 let numa_region = ZbiTopologyNumaRegion { start_address, end_address };
348 assert_eq!(unsafe { as_u8_slice(&numa_region) }, &buffer[0..size]);
349 }
350
351 #[fuchsia::test]
352 fn zbi_topology_cluster_in_sync() {
353 let performance_class = 2;
354
355 let buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
356 let size = unsafe { serialize_zbi_topology_cluster_t(&buffer, performance_class) };
357 assert_eq!(size, std::mem::size_of::<ZbiTopologyCluster>());
358
359 let cluster = ZbiTopologyCluster { performance_class };
360 assert_eq!(unsafe { as_u8_slice(&cluster) }, &buffer[0..size]);
361 }
362
363 #[fuchsia::test]
364 fn zbi_topology_processor_in_sync() {
365 let logical_ids = [0, 1, 3, 4];
366 let logical_id_count = 4;
367 let flags = 1;
368 let arm_info = ZbiTopologyArm64Info {
369 cluster_1_id: 1,
370 cluster_2_id: 1,
371 cluster_3_id: 0,
372 cpu_id: 0,
373 gic_id: 1,
374 };
375 let x64_info = ZbiTopologyX64Info { apic_ids: [0, 1, 3, 4], apic_id_count: 4 };
376 let mut architecture_info = ArchitectureInfo { arm64: arm_info };
377
378 let mut buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
379 let mut size = unsafe {
380 serialize_zbi_topology_processor_v2_t(
381 &buffer,
382 &logical_ids,
383 logical_id_count,
384 flags,
385 ZbiTopologyArchitecture::ZbiTopologyArchArm64 as u8,
386 architecture_info,
387 )
388 };
389 assert_eq!(size, std::mem::size_of::<ZbiTopologyProcessor>());
390
391 let mut arm_processor: ZbiTopologyProcessor = unsafe { std::mem::zeroed() };
393 arm_processor.logical_ids = logical_ids;
394 arm_processor.logical_id_count = logical_id_count;
395 arm_processor.flags = flags;
396 arm_processor.architecture = ZbiTopologyArchitecture::ZbiTopologyArchArm64 as u8;
397 arm_processor.architecture_info.arm64 = arm_info;
398 assert_eq!(unsafe { as_u8_slice(&arm_processor) }, &buffer[0..size]);
399
400 buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
401 architecture_info = ArchitectureInfo { x64: x64_info };
402 size = unsafe {
403 serialize_zbi_topology_processor_v2_t(
404 &buffer,
405 &logical_ids,
406 logical_id_count,
407 flags,
408 ZbiTopologyArchitecture::ZbiTopologyArchX64 as u8,
409 architecture_info,
410 )
411 };
412 assert_eq!(size, std::mem::size_of::<ZbiTopologyProcessor>());
413
414 let mut x64_processor: ZbiTopologyProcessor = unsafe { std::mem::zeroed() };
416 x64_processor.logical_ids = logical_ids;
417 x64_processor.logical_id_count = logical_id_count;
418 x64_processor.flags = flags;
419 x64_processor.architecture = ZbiTopologyArchitecture::ZbiTopologyArchX64 as u8;
420 x64_processor.architecture_info.x64 = x64_info;
421 assert_eq!(unsafe { as_u8_slice(&x64_processor) }, &buffer[0..size]);
422
423 buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
424 size = unsafe {
425 serialize_zbi_topology_processor_v2_t(
426 &buffer,
427 &logical_ids,
428 logical_id_count,
429 flags,
430 ZbiTopologyArchitecture::ZbiTopologyArchUndefined as u8,
431 architecture_info,
432 )
433 };
434 assert_eq!(size, std::mem::size_of::<ZbiTopologyProcessor>());
435
436 let mut undefined_processor: ZbiTopologyProcessor = unsafe { std::mem::zeroed() };
438 undefined_processor.logical_ids = logical_ids;
439 undefined_processor.logical_id_count = logical_id_count;
440 undefined_processor.flags = flags;
441 undefined_processor.architecture = ZbiTopologyArchitecture::ZbiTopologyArchUndefined as u8;
442 assert_eq!(unsafe { as_u8_slice(&undefined_processor) }, &buffer[0..size]);
443 }
444
445 #[fuchsia::test]
446 fn zbi_topology_node_in_sync() {
447 let parent_index = 5;
448 let mut processor: ZbiTopologyProcessor = unsafe { std::mem::zeroed() };
450 processor.logical_ids = [0, 0, 3, 0];
451 processor.logical_id_count = 4;
452 processor.flags = 2;
453 processor.architecture = ZbiTopologyArchitecture::ZbiTopologyArchUndefined as u8;
454 let mut entity = Entity { processor: processor };
455
456 let mut buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
457 let mut size = unsafe {
458 serialize_zbi_topology_node_v2_t(
459 &buffer,
460 ZbiTopologyEntityType::ZbiTopologyEntityProcessor as u8,
461 parent_index,
462 entity,
463 )
464 };
465 assert_eq!(size, std::mem::size_of::<ZbiTopologyNode>());
466
467 let mut processor_node: ZbiTopologyNode = unsafe { std::mem::zeroed() };
469 processor_node.parent_index = parent_index;
470 processor_node.entity_type = ZbiTopologyEntityType::ZbiTopologyEntityProcessor as u8;
471 processor_node.entity.processor = processor;
472 assert_eq!(unsafe { as_u8_slice(&processor_node) }, &buffer[0..size]);
473
474 let cluster = ZbiTopologyCluster { performance_class: 1 };
475 entity = Entity { cluster: cluster };
476 buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
477 size = unsafe {
478 serialize_zbi_topology_node_v2_t(
479 &buffer,
480 ZbiTopologyEntityType::ZbiTopologyEntityCluster as u8,
481 parent_index,
482 entity,
483 )
484 };
485 assert_eq!(size, std::mem::size_of::<ZbiTopologyNode>());
486
487 let mut cluster_node: ZbiTopologyNode = unsafe { std::mem::zeroed() };
489 cluster_node.parent_index = parent_index;
490 cluster_node.entity_type = ZbiTopologyEntityType::ZbiTopologyEntityCluster as u8;
491 cluster_node.entity.cluster = cluster;
492 assert_eq!(unsafe { as_u8_slice(&cluster_node) }, &buffer[0..size]);
493
494 let numa_region = ZbiTopologyNumaRegion { start_address: 2233, end_address: 3333 };
495 entity = Entity { numa_region: numa_region };
496 buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
497 size = unsafe {
498 serialize_zbi_topology_node_v2_t(
499 &buffer,
500 ZbiTopologyEntityType::ZbiTopologyEntityNumaRegion as u8,
501 parent_index,
502 entity,
503 )
504 };
505 assert_eq!(size, std::mem::size_of::<ZbiTopologyNode>());
506
507 let mut numa_region_node: ZbiTopologyNode = unsafe { std::mem::zeroed() };
509 numa_region_node.parent_index = parent_index;
510 numa_region_node.entity_type = ZbiTopologyEntityType::ZbiTopologyEntityNumaRegion as u8;
511 numa_region_node.entity.numa_region = numa_region;
512 assert_eq!(unsafe { as_u8_slice(&numa_region_node) }, &buffer[0..size]);
513
514 let cache = ZbiTopologyCache { cache_id: 3 };
515 entity = Entity { cache: cache };
516 buffer = [0 as u8; MAX_SERIALIZATION_BUFFER_SIZE];
517 size = unsafe {
518 serialize_zbi_topology_node_v2_t(
519 &buffer,
520 ZbiTopologyEntityType::ZbiTopologyEntityCache as u8,
521 parent_index,
522 entity,
523 )
524 };
525 assert_eq!(size, std::mem::size_of::<ZbiTopologyNode>());
526
527 let mut cache_node: ZbiTopologyNode = unsafe { std::mem::zeroed() };
529 cache_node.parent_index = parent_index;
530 cache_node.entity_type = ZbiTopologyEntityType::ZbiTopologyEntityCache as u8;
531 cache_node.entity.cache = cache;
532 assert_eq!(unsafe { as_u8_slice(&cache_node) }, &buffer[0..size]);
533 }
534}