{"id":22530148,"url":"https://github.com/ultimaweapon/zfi","last_synced_at":"2025-08-03T23:33:39.118Z","repository":{"id":189581840,"uuid":"680902520","full_name":"ultimaweapon/zfi","owner":"ultimaweapon","description":"Zero-cost and safe interface to UEFI firmware","archived":false,"fork":false,"pushed_at":"2024-12-01T09:00:47.000Z","size":107,"stargazers_count":29,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-12-01T09:32:22.881Z","etag":null,"topics":["rust","uefi"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ultimaweapon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-20T19:11:35.000Z","updated_at":"2024-12-01T09:00:50.000Z","dependencies_parsed_at":"2023-08-20T21:04:03.417Z","dependency_job_id":"97c9612b-dac5-472c-b35e-f4975f238aa9","html_url":"https://github.com/ultimaweapon/zfi","commit_stats":null,"previous_names":["ultimicro/zfi"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ultimaweapon%2Fzfi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ultimaweapon%2Fzfi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ultimaweapon%2Fzfi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ultimaweapon%2Fzfi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ultimaweapon","download_url":"https://codeload.github.com/ultimaweapon/zfi/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228572350,"owners_count":17938871,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["rust","uefi"],"created_at":"2024-12-07T07:18:28.979Z","updated_at":"2025-08-03T23:33:39.105Z","avatar_url":"https://github.com/ultimaweapon.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ZFI – Zero-cost and safe interface to UEFI firmware\n[![CI](https://github.com/ultimicro/zfi/actions/workflows/ci.yml/badge.svg)](https://github.com/ultimicro/zfi/actions/workflows/ci.yml)\n[![Crates.io](https://img.shields.io/crates/v/zfi)](https://crates.io/crates/zfi)\n\nZFI is a Rust crate for writing a UEFI application with the following goals:\n\n- Provides base APIs that are almost identical to the UEFI specifications.\n- Provides additional APIs that build on top of the base APIs.\n- Base APIs are zero-cost abstraction over UEFI API.\n- Safe and easy to use.\n- Work on stable Rust.\n\nZFI supports only single-thread environment, which is the same as UEFI specifications.\n\n## Example\n\n```rust\n#![no_std]\n#![no_main]\n\nuse alloc::boxed::Box;\nuse zfi::{pause, println, DebugFile, Image, Status, SystemTable};\n\nextern crate alloc;\n\n#[no_mangle]\nextern \"efiapi\" fn efi_main(image: \u0026'static Image, st: \u0026'static SystemTable) -\u003e Status {\n    // This is the only place you need to use unsafe. This must be done immediately after landing\n    // here.\n    unsafe {\n        zfi::init(\n            image,\n            st,\n            Some(|| Box::new(DebugFile::next_to_image(\"log\").unwrap())),\n        )\n    };\n\n    // Any EFI_HANDLE will be represents by a reference to a Rust type (e.g. image here is a type of\n    // Image). Each type that represents EFI_HANDLE provides the methods to access any protocols it\n    // is capable for (e.g. you can do image.proto() here to get an EFI_LOADED_IMAGE_PROTOCOL from\n    // it). You can download the UEFI specifications for free here: https://uefi.org/specifications\n    println!(\"Hello, world!\");\n    pause();\n\n    Status::SUCCESS\n}\n\n#[cfg(not(test))]\n#[panic_handler]\nfn panic_handler(info: \u0026core::panic::PanicInfo) -\u003e ! {\n    zfi::eprintln!(\"{info}\");\n    loop {}\n}\n\n#[cfg(not(test))]\n#[global_allocator]\nstatic ALLOCATOR: zfi::PoolAllocator = zfi:PoolAllocator;\n```\n\nYou can use `zfi::main` macro if you prefer a less boilerplate:\n\n```rust\n#![no_std]\n#![no_main]\n\nuse zfi::{pause, println, Status};\n\n// zfi::main will not enable the debug writer by default. See its documentation to see how to enable\n// the debug writer.\n#[zfi::main]\nfn main() -\u003e Status {\n    // Use Image::current() to get the image handle.\n    println!(\"Hello, world!\");\n    pause();\n\n    Status::SUCCESS\n}\n```\n\nTo build the above example you need to add a UEFI target to Rust:\n\n```sh\nrustup target add x86_64-unknown-uefi\n```\n\nThen build with the following command:\n\n```sh\ncargo build --target x86_64-unknown-uefi\n```\n\nYou can grab the EFI file in `target/x86_64-unknown-uefi/debug` and boot it on a compatible machine.\n\n## Integration Testing\n\nZFI provide [zfi-testing](https://crates.io/crates/zfi-testing) crate to help you write the\n[integration tests](https://doc.rust-lang.org/rust-by-example/testing/integration_testing.html).\nThis crate must be added as a\n[development dependency](https://doc.rust-lang.org/rust-by-example/testing/dev_dependencies.html),\nnot a standard dependency. You need to install the following tools before you can run the\nintegration tests that use `zfi-testing`:\n\n- [QEMU](https://www.qemu.org)\n- [OVMF](https://github.com/tianocore/tianocore.github.io/wiki/OVMF)\n\nOnce ready create `zfi.toml` in the root of your package (the same location as `Cargo.toml`) with\nthe following content:\n\n```toml\n[qemu.RUST_TARGET]\nbin = \"QEMU_BIN\"\nfirmware = \"OVMF_CODE\"\nnvram = \"OVMF_VARS\"\n```\n\nThis file should not commit to the version control because it is specific to your machine. Replace\nthe following placeholders with the appropriate value:\n\n- `RUST_TARGET`: name of Rust target you want to run on the QEMU (e.g. `x86_64-unknown-uefi`).\n- `QEMU_BIN`: path to the QEMU binary to run your tests. The binary must have the same CPU type as\n  `RUST_TARGET`. You don't need to specify a full path if the binary can be found in the `PATH`\n  environment variable (e.g. `qemu-system-x86_64`).\n- `OVMF_CODE`: path to `OVMF_CODE.fd` from OVMF. File must have the same CPU type as `RUST_TARGET`\n  (e.g. `/usr/share/edk2/x64/OVMF_CODE.fd`).\n- `OVMF_VARS`: path to `OVMF_VARS.fd` from OVMF. File must have the same CPU type as `RUST_TARGET`\n  (e.g. `/usr/share/edk2/x64/OVMF_VARS.fd`).\n\nExample:\n\n```toml\n[qemu.aarch64-unknown-uefi]\nbin = \"qemu-system-aarch64\"\nfirmware = \"/usr/share/AAVMF/AAVMF_CODE.fd\"\nnvram = \"/usr/share/AAVMF/AAVMF_VARS.fd\"\n\n[qemu.i686-unknown-uefi]\nbin = \"qemu-system-i386\"\nfirmware = \"/usr/share/edk2/ia32/OVMF_CODE.fd\"\nnvram = \"/usr/share/edk2/ia32/OVMF_VARS.fd\"\n\n[qemu.x86_64-unknown-uefi]\nbin = \"qemu-system-x86_64\"\nfirmware = \"/usr/share/edk2/x64/OVMF_CODE.fd\"\nnvram = \"/usr/share/edk2/x64/OVMF_VARS.fd\"\n```\n\n### Writing Tests\n\nTo write an integration test to run on QEMU, put `zfi_testing::qemu` attribute to your integration\ntest:\n\n```rust\nuse zfi_testing::qemu;\n\n#[test]\n#[qemu]\nfn proto() {\n    use zfi::{str, Image, PathBuf};\n\n    let proto = Image::current().proto();\n    let mut path = PathBuf::new();\n\n    if cfg!(target_arch = \"x86_64\") {\n        path.push_media_file_path(str!(r\"\\EFI\\BOOT\\BOOTX64.EFI\"));\n    } else {\n        todo!(\"path for non-x86-64\");\n    }\n\n    assert_eq!(proto.device().file_system().is_some(), true);\n    assert_eq!(*proto.file_path(), path);\n}\n```\n\nThe code in the function that has `zfi_testing::qemu` attribute will run on the QEMU. This test can\nbe run in the same way as normal integration tests:\n\n```sh\ncargo test\n```\n\nKeep in mind that you need to put everything your test needed in the same function because what\n`qemu` attribute does is moving your function body into `efi_main` and run it on QEMU.\n\n### Known Issues\n\n- Any panic (including assertion failed) in your integration test will be show as `src/main.rs:L:C`.\n  This is a limitation on stable Rust for [now](https://github.com/rust-lang/rust/issues/54725).\n- rust-analyzer not report any syntax error. The reason is because `qemu` attribute replace the\n  whole function body, which mean what rust-analyzer see when running syntax check is the replaced\n  function, not the origial function. Right now there is no way to check if our proc macro being run\n  by rust-analyzer until this [issue](https://github.com/rust-lang/rust-analyzer/issues/13731) has\n  been resolved.\n\n## Breaking Changes\n\n### 0.1 to 0.2\n\n- `Path` is changed from sized type to unsized type. Any code that cast `Path` to a raw pointer need\n  to update otherwise you will get a fat pointer, which is Rust specific. You can get a pointer to\n  `EFI_DEVICE_PATH_PROTOCOL` via `Path::as_bytes()`.\n- `FileInfo` is changed from sized type to unsized type in the same way as `Path`.\n- `File::info()` now return `Box\u003cFileInfo\u003e` instead of `Owned\u003cFileInfo\u003e` when success.\n- The second parameter of `Owned::new()` is changed to `Dtor`.\n- `SystemTable::current()` was replaced with `zfi::system_table()`.\n- `Image::current()` was replaced with `zfi::current_image()`.\n- All getters on `SystemTable` no longer return a static lifetime.\n- `EfiStr` and `EfiString` to longer implement `Display`. Use `EfiStr::display()` instead.\n- `Display` implementation of `DebugFileError`, `FileCreateError` and `FileSetLenError` no longer print the nested error. Use `core::error::Error::source()` to obtains the inner error instead.\n- `Path` no longer implement `Display`. Use `Path::display()` instead.\n- `PathNode` no longer implement `Display`. Currently no alternative is provided yet. Please create the issue if you want this feature so I can prioritize it.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fultimaweapon%2Fzfi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fultimaweapon%2Fzfi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fultimaweapon%2Fzfi/lists"}