Skip to content

Commit 62cf28e

Browse files
committed
initial commit
0 parents  commit 62cf28e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+3960
-0
lines changed

.github/dependabot.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "cargo"
4+
directory: "/"
5+
schedule:
6+
interval: "monthly"
7+
open-pull-requests-limit: 3
8+
groups:
9+
all-dependencies:
10+
patterns:
11+
- "*"
12+
13+
- package-ecosystem: "github-actions"
14+
directory: "/"
15+
schedule:
16+
interval: "monthly"

.github/workflows/ci.yml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
name: ci
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
12+
jobs:
13+
test:
14+
name: cargo test
15+
runs-on: ubuntu-latest
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
rust: [stable, beta, nightly, 1.80.0] # stable, beta, nightly, and MSRV
20+
mode: ["", "--release"]
21+
steps:
22+
- name: checkout code
23+
uses: actions/checkout@v5
24+
25+
- name: install rust toolchain
26+
uses: dtolnay/rust-toolchain@master
27+
with:
28+
toolchain: ${{ matrix.rust }}
29+
30+
- name: cache rust toolchain
31+
uses: Swatinem/rust-cache@v2
32+
33+
- name: cargo test
34+
run: cargo test ${{ matrix.mode }}
35+
36+
deny:
37+
name: cargo deny
38+
runs-on: ubuntu-latest
39+
steps:
40+
- name: checkout code
41+
uses: actions/checkout@v5
42+
43+
- name: cargo deny
44+
uses: EmbarkStudios/cargo-deny-action@v2
45+
46+
fmt:
47+
name: cargo fmt
48+
runs-on: ubuntu-latest
49+
steps:
50+
- name: checkout code
51+
uses: actions/checkout@v5
52+
53+
- name: install rust toolchain
54+
uses: dtolnay/rust-toolchain@stable
55+
with:
56+
components: rustfmt
57+
58+
- name: cargo fmt
59+
run: cargo fmt --all -- --check
60+
61+
clippy:
62+
name: cargo clippy
63+
runs-on: ubuntu-latest
64+
steps:
65+
- name: checkout code
66+
uses: actions/checkout@v5
67+
68+
- name: install rust toolchain
69+
uses: dtolnay/rust-toolchain@stable
70+
with:
71+
components: clippy
72+
73+
- name: cargo clippy
74+
run: cargo clippy --bins -- -D warnings

.github/workflows/release.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
name: release
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: checkout code
17+
uses: actions/checkout@v5
18+
19+
- name: install rust toolchain
20+
uses: dtolnay/rust-toolchain@stable
21+
with:
22+
targets: x86_64-unknown-linux-musl
23+
24+
- name: cache rust toolchain
25+
uses: Swatinem/rust-cache@v2
26+
27+
- name: install musl-tools
28+
run: sudo apt-get update && sudo apt-get install -y musl-tools
29+
30+
- name: cargo build
31+
run: cargo build --release --target x86_64-unknown-linux-musl
32+
33+
- name: create release
34+
env:
35+
GH_TOKEN: ${{ github.token }}
36+
run: |
37+
gh release delete --yes ${{ github.ref_name }} || true
38+
gh release create --generate-notes ${{ github.ref_name }} target/x86_64-unknown-linux-musl/release/beacon

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target/

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "devpath"
3+
version = "0.1.0"
4+
edition = "2021"
5+
description = "UEFI Device Path parsing library"
6+
license = "MIT OR Apache-2.0"
7+
repository = "https://github.com/AMDEPYC/snpcert"
8+
readme = "README.md"
9+
keywords = ["uefi", "device-path", "firmware", "boot", "efi"]
10+
categories = ["embedded", "hardware-support", "parsing"]
11+
rust-version = "1.80"

STYLE.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Code Style Guide
2+
3+
## Module Organization
4+
5+
- **Module names**: Shortened, clear (e.g., `bluetooth_le``btle`, `device_logical_unit``dlu`)
6+
- **Module structure**: One primary struct per sub-type, implementation in same file
7+
- **File naming**: Match shortened module names
8+
9+
## Import Grouping
10+
11+
```rust
12+
// 1. External crates (if any)
13+
use core::net::Ipv4Addr;
14+
15+
// 2. Internal crate imports
16+
use crate::{Error, Head};
17+
use crate::parser::{ByteOrder, Parser};
18+
19+
// 3. Relative imports
20+
use super::ipv4::Protocol;
21+
```
22+
23+
## Field Naming
24+
25+
- **Brief names**: `vendor_id``vid`, `mac_address``mac`, `baud_rate``baud`
26+
- **Documentation**: Add doc comments for any ambiguous shortened names
27+
- **Standard abbreviations**: `nsid`, `lun`, `wwn`, `eui`, `vid`, `pid`, `hba_port`, `pm_port`
28+
29+
## Data Types
30+
31+
### String Handling
32+
- **UTF-8 strings**: Use `&CStr` for null-terminated UTF-8 strings
33+
- **UTF-16 strings**: Use `String` for UTF-16 strings (converted from parser)
34+
- **Raw strings**: Use `&str` for non-null-terminated UTF-8 strings (rare)
35+
36+
### Newtypes
37+
- **Single field structs**: Use newtype pattern
38+
```rust
39+
pub struct Vlan(pub u16);
40+
pub struct Protocol(pub u16);
41+
```
42+
43+
### Enums
44+
- **Small known value sets**: Use proper enums (no repr guarantees)
45+
- **Parser trait**: Implement for validation
46+
```rust
47+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
48+
pub enum Origin {
49+
Manual = 0x00,
50+
StatelessAutoConfiguration = 0x01,
51+
}
52+
```
53+
54+
### Structs
55+
- **Multi-field types**: Regular structs with brief field names
56+
- **Derive**: Always include `Debug, Clone, Copy, PartialEq, Eq, Hash`
57+
58+
## Reserved Fields
59+
60+
- **Storage**: Do NOT store reserved fields in structs
61+
- **Validation**: Parse and validate in `TryFrom` implementation
62+
- **Pattern**: `let _reserved: u32 = node.data.parse(ByteOrder::Little)?;`
63+
64+
## Error Handling
65+
66+
- **Invalid values**: Return `Error::Invalid` for spec violations
67+
- **Validation**: Check reserved field values, invalid NSIDs, etc.
68+
69+
## Documentation
70+
71+
- **Struct docs**: Include UEFI sub-type number and byte length
72+
- **Field docs**: Required for abbreviated field names
73+
- **Example**:
74+
```rust
75+
/// SATA Device Path (SubType 0x12)
76+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
77+
pub struct Sata {
78+
/// HBA port number
79+
pub hba_port: u16,
80+
/// Port multiplier port number
81+
pub pm_port: u16,
82+
pub lun: u16,
83+
}
84+
```
85+
86+
## Implementation Patterns
87+
88+
### Parse Order
89+
- **Last field**: Always use `finish()` method to guarantee end of data
90+
- **Earlier fields**: Use regular `parse()` method
91+
92+
### TryFrom Implementation
93+
```rust
94+
impl<'a> TryFrom<Head<'a>> for TypeName<'a> {
95+
type Error = Error;
96+
97+
fn try_from(mut node: Head<'a>) -> Result<Self, Self::Error> {
98+
// Parse reserved fields (don't store)
99+
let _reserved: u32 = node.data.parse(ByteOrder::Little)?;
100+
101+
// Parse fields (use finish() for last field)
102+
let field1 = node.data.parse(ByteOrder::Little)?;
103+
let utf8_string = node.data.finish(())?; // &CStr for UTF-8
104+
105+
Ok(TypeName { field1, utf8_string })
106+
}
107+
}
108+
```
109+
110+
### Byte Order
111+
- **Multi-byte integers**: Always specify `ByteOrder::Little`
112+
- **Single bytes**: Use `()` argument
113+
- **Arrays**: Use `()` argument
114+
115+
## Constants
116+
117+
- **Protocol numbers**: Define as associated constants
118+
- **Magic values**: Use descriptive constant names
119+
- **Grouping**: Related constants together with docs

deny.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[licenses]
2+
confidence-threshold = 0.8
3+
allow = [
4+
"MIT",
5+
"Apache-2.0",
6+
]
7+
8+
[bans]
9+
multiple-versions = "warn"
10+
11+
[sources]
12+
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
13+
unknown-registry = "deny"
14+
unknown-git = "deny"

src/acpi/adr.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//! ACPI Device Path address (`_ADR`) implementation
2+
//!
3+
//! This module implements the ACPI `_ADR` device path as defined in UEFI 2.11 specification.
4+
//! Used for identifying video output devices using ACPI `_ADR` values.
5+
6+
use crate::parser::{ByteOrder, Parser};
7+
use crate::{Error, Head};
8+
9+
use alloc::vec::Vec;
10+
11+
/// ACPI `_ADR` Device Path (SubType 0x03) - for video output devices
12+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13+
pub struct Adr {
14+
adrs: Vec<u32>,
15+
}
16+
17+
impl TryFrom<Head<'_>> for Adr {
18+
type Error = Error;
19+
20+
fn try_from(mut node: Head<'_>) -> Result<Self, Self::Error> {
21+
let mut values = Vec::new();
22+
23+
while node.data.len() >= 4 {
24+
let value: u32 = node.data.parse(ByteOrder::Little)?;
25+
values.push(value);
26+
}
27+
28+
if !node.data.is_empty() {
29+
return Err(Error::Invalid);
30+
}
31+
32+
Ok(Self { adrs: values })
33+
}
34+
}

src/acpi/expanded.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//! ACPI Device Path expanded format implementation
2+
//!
3+
//! This module implements the expanded ACPI device path format as defined in UEFI 2.11
4+
//! specification. The expanded format includes additional string-based identifiers.
5+
6+
use alloc::string::String;
7+
8+
use crate::parser::{ByteOrder, Format, Parser};
9+
use crate::{Error, Head};
10+
11+
/// Helper struct for ACPI device identifiers
12+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13+
pub struct Id(pub u32, pub String);
14+
15+
/// Expanded ACPI Device Path (SubType 0x02)
16+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17+
pub struct Expanded {
18+
/// Hardware ID - identifies the device's Plug and Play ID
19+
pub hid: Id,
20+
21+
/// Unique ID - distinguishes multiple instances of the same device
22+
pub uid: Id,
23+
24+
/// Compatible ID - identifies devices compatible with this device
25+
pub cid: Id,
26+
}
27+
28+
impl TryFrom<Head<'_>> for Expanded {
29+
type Error = Error;
30+
31+
fn try_from(mut node: Head<'_>) -> Result<Self, Self::Error> {
32+
let hid = node.data.parse(ByteOrder::Little)?;
33+
let uid = node.data.parse(ByteOrder::Little)?;
34+
let cid = node.data.parse(ByteOrder::Little)?;
35+
36+
Ok(Self {
37+
hid: Id(hid, node.data.parse(Format::Utf8(None))?),
38+
uid: Id(uid, node.data.parse(Format::Utf8(None))?),
39+
cid: Id(cid, node.data.finish(Format::Utf8(None))?),
40+
})
41+
}
42+
}

0 commit comments

Comments
 (0)