Skip to content

Commit f0e9b2e

Browse files
committed
Dockerfile to build OVMF with NVME support tuned off
- We need to disable NVME support to emulate target environment Signed-off-by: Mikhail Malyshev <[email protected]>
1 parent 9be81d4 commit f0e9b2e

File tree

7 files changed

+214
-0
lines changed

7 files changed

+214
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@ Cargo.lock
1212

1313
# MSVC Windows builds of rustc generate these, which store debugging information
1414
*.pdb
15+
16+
# OVMF build artifacts, logs and QEMU VM directory
17+
/ovmf-no-nvme
18+
/vm
19+
debug.log
20+

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"cSpell.words": [
3+
"uefi"
4+
]
5+
}

Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "jumpstart"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
log = "0.4.20"
10+
uefi = { version = "0.26.0", features = ["alloc", "global_allocator"] }
11+
uefi-services = "0.23.0"

Dockerfile

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
FROM ubuntu:22.04 as base-build
2+
3+
RUN apt-get update && apt-get install -y \
4+
build-essential \
5+
git \
6+
nasm \
7+
python3 \
8+
python3-pip \
9+
uuid-dev \
10+
iasl
11+
12+
# make a link to python3
13+
RUN ln -s /usr/bin/python3 /usr/bin/python
14+
15+
ADD --keep-git-dir=true https://github.com/tianocore/edk2.git#edk2-stable202402 /edk2
16+
17+
WORKDIR /edk2
18+
19+
RUN git submodule update --init --recursive
20+
21+
RUN make -j $(nproc) -C BaseTools
22+
23+
FROM base-build as build-ovmf
24+
WORKDIR /edk2
25+
RUN bash -c "source edksetup.sh; build -n $(nproc) -b RELEASE -a X64 -t GCC5 -p OvmfPkg/OvmfPkgX64.dsc"
26+
27+
FROM base-build as build-ovmf-no-nvme
28+
WORKDIR /edk2
29+
# disable NVME support
30+
RUN sed -i 's/.*NvmExpressDxe.*/# disable NVME/' OvmfPkg/OvmfPkgX64.dsc && \
31+
sed -i 's/.*NvmExpressDxe.*/# disable NVME/' OvmfPkg/OvmfPkgX64.fdf
32+
RUN bash -c "source edksetup.sh; build -n $(nproc) -b RELEASE -a X64 -t GCC5 -p OvmfPkg/OvmfPkgX64.dsc"
33+
34+
FROM base-build as build-shell
35+
WORKDIR /edk2
36+
RUN bash -c "source edksetup.sh; build -n $(nproc) -b RELEASE -a X64 -t GCC5 -p ShellPkg/ShellPkg.dsc"
37+
38+
FROM scratch as ovmf
39+
# get NVME DXE driver
40+
COPY --from=build-ovmf /edk2/Build/OvmfX64/RELEASE_GCC5/X64/NvmExpressDxe.efi /NvmExpressDxe.efi
41+
# get OVMF firmware without NVME support
42+
COPY --from=build-ovmf-no-nvme /edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd /OVMF_no_nvme.fd
43+
COPY --from=build-ovmf-no-nvme /edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd /OVMF_VARS_no_nvme.fd
44+
COPY --from=build-ovmf-no-nvme /edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd /OVMF_CODE_no_nvme.fd
45+
# get shell
46+
COPY --from=build-shell /edk2/Build/Shell/RELEASE_GCC5/X64/ShellPkg/Application/Shell/Shell/OUTPUT/Shell.efi /shellx64.efi
47+
48+

Makefile

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
TARGET ?= release
2+
3+
OVMF_DIR = ./ovmf-no-nvme
4+
OVMF_FILES = \
5+
./$(OVMF_DIR)/OVMF_CODE_no_nvme.fd \
6+
./$(OVMF_DIR)/OVMF_VARS_no_nvme.fd \
7+
./$(OVMF_DIR)/OVMF_no_nvme.fd \
8+
./$(OVMF_DIR)/NvmExpressDxe.efi \
9+
./$(OVMF_DIR)/shellx64.efi
10+
11+
ESP_DIR = ./vm/esp
12+
NVME_DIR = ./vm/nvme
13+
14+
BOOT_FILES = \
15+
$(ESP_DIR)/EFI/BOOT/BOOTX64.efi \
16+
$(ESP_DIR)/EFI/BOOT/JS/DRIVERS/NvmExpressDxe.efi
17+
18+
ifeq ($(TARGET),debug)
19+
BOOT_FILES += $(ESP_DIR)/EFI/BOOT/shellx64.efi
20+
endif
21+
22+
BOOTLOADER = ./target/x86_64-unknown-uefi/$(TARGET)/jumpstart.efi
23+
24+
.PHONY: all
25+
all: run
26+
27+
.PHONY: ovmf
28+
ovmf: $(OVMF_FILES)
29+
$(OVMF_FILES): Dockerfile
30+
docker buildx build -o type=local,dest=$(OVMF_DIR) .
31+
32+
.PHONY: vm-dir
33+
vm-dir: $(BOOT_FILES)
34+
$(BOOT_FILES): jumpstart_$(TARGET) ovmf
35+
mkdir -p $(ESP_DIR)/EFI/BOOT/JS/DRIVERS
36+
mkdir -p $(NVME_DIR)
37+
touch $(NVME_DIR)/nvme-dummy.txt
38+
cp $(OVMF_DIR)/NvmExpressDxe.efi $(ESP_DIR)/EFI/BOOT/JS/DRIVERS
39+
cp $(BOOTLOADER) $(ESP_DIR)/EFI/BOOT/BOOTX64.efi
40+
# copy UEFI Shell to the ESP only for debug target
41+
ifeq ($(TARGET),debug)
42+
cp $(OVMF_DIR)/shellx64.efi $(ESP_DIR)/EFI/BOOT
43+
endif
44+
45+
.PHONY: jumpstart_debug jumpstart_release
46+
jumpstart_$(TARGET): $(BOOTLOADER)
47+
48+
jumpstart_debug: CARGO_TARGET:=
49+
jumpstart_release: CARGO_TARGET:=--release
50+
51+
$(BOOTLOADER):
52+
cargo build --target=x86_64-unknown-uefi $(CARGO_TARGET)
53+
54+
.PHONY: run
55+
run: vm-dir
56+
qemu-system-x86_64 -enable-kvm -serial stdio \
57+
-debugcon file:debug.log -global isa-debugcon.iobase=0x402 \
58+
-drive if=pflash,format=raw,readonly=on,file=./$(OVMF_DIR)/OVMF_CODE_no_nvme.fd \
59+
-drive if=pflash,format=raw,readonly=on,file=./$(OVMF_DIR)/OVMF_VARS_no_nvme.fd \
60+
-drive format=raw,file=fat:rw:$(NVME_DIR),if=none,id=nvm \
61+
-device nvme,serial=deadbeef,drive=nvm \
62+
-drive format=raw,file=fat:rw:$(ESP_DIR)
63+
64+
.PHONY: clean
65+
clean:
66+
rm -rf $(OVMF_DIR)
67+
rm -rf ./vm
68+
rm debug.log

rust-toolchain.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[toolchain]
2+
targets = ["x86_64-unknown-uefi"]

src/main.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
use log::info;
5+
use uefi::prelude::*;
6+
use uefi::proto::device_path::text::{AllowShortcuts, DevicePathToText, DisplayOnly, PoolString};
7+
use uefi::proto::loaded_image::LoadedImage;
8+
use uefi::table::boot::SearchType;
9+
use uefi::{Identify, Result};
10+
11+
// Print the file path to the _image_handle
12+
fn print_image_path(boot_services: &BootServices) -> Result {
13+
let loaded_image =
14+
boot_services.open_protocol_exclusive::<LoadedImage>(boot_services.image_handle())?;
15+
16+
let device_path_to_text_handle = *boot_services
17+
.locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))?
18+
.first()
19+
.expect("DevicePathToText is missing");
20+
21+
let device_path_to_text =
22+
boot_services.open_protocol_exclusive::<DevicePathToText>(device_path_to_text_handle)?;
23+
24+
let image_device_path = loaded_image.file_path().expect("File path is not set");
25+
let image_device_path_text = device_path_to_text
26+
.convert_device_path_to_text(
27+
boot_services,
28+
image_device_path,
29+
DisplayOnly(true),
30+
AllowShortcuts(false),
31+
)
32+
.expect("convert_device_path_to_text failed");
33+
34+
info!("Image path: {}", &*image_device_path_text);
35+
Ok(())
36+
}
37+
38+
// get the file path of the image handle
39+
fn get_image_path(boot_services: &BootServices) -> Result<PoolString> {
40+
let loaded_image =
41+
boot_services.open_protocol_exclusive::<LoadedImage>(boot_services.image_handle())?;
42+
43+
let device_path_to_text_handle = *boot_services
44+
.locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))?
45+
.first()
46+
.expect("DevicePathToText is missing");
47+
48+
let device_path_to_text =
49+
boot_services.open_protocol_exclusive::<DevicePathToText>(device_path_to_text_handle)?;
50+
51+
let image_device_path = loaded_image.file_path().expect("File path is not set");
52+
let image_device_path_text = device_path_to_text
53+
.convert_device_path_to_text(
54+
boot_services,
55+
image_device_path,
56+
DisplayOnly(true),
57+
AllowShortcuts(false),
58+
)
59+
.expect("convert_device_path_to_text failed");
60+
61+
Ok(image_device_path_text.into())
62+
}
63+
64+
// The entry point for this UEFI application
65+
#[entry]
66+
fn main(_image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
67+
uefi_services::init(&mut system_table).unwrap();
68+
let boot_services = system_table.boot_services();
69+
70+
print_image_path(boot_services).unwrap();
71+
72+
boot_services.stall(10_000_000);
73+
Status::SUCCESS
74+
}

0 commit comments

Comments
 (0)