@@ -737,17 +737,36 @@ pub(crate) async fn run_impl(opts: RunEphemeralOpts) -> Result<()> {
737737 } ;
738738 tracing:: debug!( "Target image has cloud-init: {cloudinit}" ) ;
739739
740- // Find kernel and initramfs from the container image (not the host)
740+ // Verify KVM access
741+ if !Utf8Path :: new ( "/dev/kvm" ) . exists ( ) || !fs:: File :: open ( "/dev/kvm" ) . is_ok ( ) {
742+ return Err ( eyre ! ( "KVM device not accessible" ) ) ;
743+ }
744+
745+ // Create QEMU mount points
746+ fs:: create_dir_all ( "/run/qemu" ) ?;
747+
748+ // Find kernel and initramfs in /usr/lib/modules/
741749 let modules_dir = Utf8Path :: new ( "/run/source-image/usr/lib/modules" ) ;
742- let mut vmlinuz_path = None ;
743- let mut initramfs_path = None ;
750+ let mut uki_file: Option < Utf8PathBuf > = None ;
751+ let mut vmlinuz_path: Option < Utf8PathBuf > = None ;
752+ let mut initramfs_path: Option < Utf8PathBuf > = None ;
744753
745754 for entry in fs:: read_dir ( modules_dir) ? {
746755 let entry = entry?;
747- let kernel_dir = entry. path ( ) ;
748- if kernel_dir. is_dir ( ) {
749- let vmlinuz = kernel_dir. join ( "vmlinuz" ) ;
750- let initramfs = kernel_dir. join ( "initramfs.img" ) ;
756+ let path = Utf8PathBuf :: from_path_buf ( entry. path ( ) )
757+ . map_err ( |p| eyre ! ( "Path is not valid UTF-8: {}" , p. display( ) ) ) ?;
758+
759+ // Check for UKI (.efi file)
760+ if path. is_file ( ) && path. extension ( ) == Some ( "efi" ) {
761+ debug ! ( "Found UKI file: {:?}" , path) ;
762+ uki_file = Some ( path) ;
763+ break ;
764+ }
765+
766+ // Check for traditional kernel in subdirectories
767+ if path. is_dir ( ) {
768+ let vmlinuz = path. join ( "vmlinuz" ) ;
769+ let initramfs = path. join ( "initramfs.img" ) ;
751770 if vmlinuz. exists ( ) && initramfs. exists ( ) {
752771 debug ! ( "Found kernel at: {:?}" , vmlinuz) ;
753772 vmlinuz_path = Some ( vmlinuz) ;
@@ -757,50 +776,59 @@ pub(crate) async fn run_impl(opts: RunEphemeralOpts) -> Result<()> {
757776 }
758777 }
759778
760- let vmlinuz_path = vmlinuz_path
761- . ok_or_else ( || eyre ! ( "No kernel found in /run/source-image/usr/lib/modules" ) ) ?;
762- let initramfs_path = initramfs_path
763- . ok_or_else ( || eyre ! ( "No initramfs found in /run/source-image/usr/lib/modules" ) ) ?;
764-
765- // Verify KVM access
766- if !Utf8Path :: new ( "/dev/kvm" ) . exists ( ) || !fs:: File :: open ( "/dev/kvm" ) . is_ok ( ) {
767- return Err ( eyre ! ( "KVM device not accessible" ) ) ;
768- }
769-
770- // Create QEMU mount points
771- fs:: create_dir_all ( "/run/qemu" ) ?;
772779 let kernel_mount = "/run/qemu/kernel" ;
773780 let initramfs_mount = "/run/qemu/initramfs" ;
774- fs:: File :: create ( & kernel_mount) ?;
775- fs:: File :: create ( & initramfs_mount) ?;
776-
777- // Bind mount kernel and initramfs
778- let mut mount_cmd = Command :: new ( "mount" ) ;
779- mount_cmd. args ( [
780- "--bind" ,
781- "-o" ,
782- "ro" ,
783- vmlinuz_path. to_str ( ) . unwrap ( ) ,
784- & kernel_mount,
785- ] ) ;
786- let status = mount_cmd. status ( ) . context ( "Failed to bind mount kernel" ) ?;
787- if !status. success ( ) {
788- return Err ( eyre ! ( "Failed to bind mount kernel" ) ) ;
789- }
790781
791- let mut mount_cmd = Command :: new ( "mount" ) ;
792- mount_cmd. args ( [
793- "--bind" ,
794- "-o" ,
795- "ro" ,
796- initramfs_path. to_str ( ) . unwrap ( ) ,
797- & initramfs_mount,
798- ] ) ;
799- let status = mount_cmd
800- . status ( )
801- . context ( "Failed to bind mount initramfs" ) ?;
802- if !status. success ( ) {
803- return Err ( eyre ! ( "Failed to bind mount initramfs" ) ) ;
782+ // Extract from UKI if found, otherwise use traditional kernel
783+ if let Some ( uki_path) = uki_file {
784+ debug ! ( "Extracting kernel and initramfs from UKI: {:?}" , uki_path) ;
785+
786+ // Extract .linux section (kernel) from UKI
787+ Command :: new ( "objcopy" )
788+ . args ( [
789+ "--dump-section" ,
790+ & format ! ( ".linux={}" , kernel_mount) ,
791+ uki_path. as_str ( ) ,
792+ ] )
793+ . run ( )
794+ . map_err ( |e| eyre ! ( "Failed to extract kernel from UKI: {e}" ) ) ?;
795+ debug ! ( "Extracted kernel from UKI to {}" , kernel_mount) ;
796+
797+ // Extract .initrd section (initramfs) from UKI
798+ Command :: new ( "objcopy" )
799+ . args ( [
800+ "--dump-section" ,
801+ & format ! ( ".initrd={}" , initramfs_mount) ,
802+ uki_path. as_str ( ) ,
803+ ] )
804+ . run ( )
805+ . map_err ( |e| eyre ! ( "Failed to extract initramfs from UKI: {e}" ) ) ?;
806+ debug ! ( "Extracted initramfs from UKI to {}" , initramfs_mount) ;
807+ } else {
808+ let vmlinuz_path = vmlinuz_path
809+ . ok_or_else ( || eyre ! ( "No kernel found in /run/source-image/usr/lib/modules" ) ) ?;
810+ let initramfs_path = initramfs_path
811+ . ok_or_else ( || eyre ! ( "No initramfs found in /run/source-image/usr/lib/modules" ) ) ?;
812+
813+ fs:: File :: create ( & kernel_mount) ?;
814+ fs:: File :: create ( & initramfs_mount) ?;
815+
816+ // Bind mount kernel and initramfs
817+ Command :: new ( "mount" )
818+ . args ( [ "--bind" , "-o" , "ro" , vmlinuz_path. as_str ( ) , & kernel_mount] )
819+ . run ( )
820+ . map_err ( |e| eyre ! ( "Failed to bind mount kernel: {e}" ) ) ?;
821+
822+ Command :: new ( "mount" )
823+ . args ( [
824+ "--bind" ,
825+ "-o" ,
826+ "ro" ,
827+ initramfs_path. as_str ( ) ,
828+ & initramfs_mount,
829+ ] )
830+ . run ( )
831+ . map_err ( |e| eyre ! ( "Failed to bind mount initramfs: {e}" ) ) ?;
804832 }
805833
806834 // Process host mounts and prepare virtiofsd instances for each using async manager
@@ -995,7 +1023,8 @@ StandardOutput=file:/dev/virtio-ports/executestatus
9951023
9961024 std:: fs:: create_dir_all ( CONTAINER_STATEDIR ) ?;
9971025
998- // Configure qemu
1026+ // Configure qemu for direct kernel boot
1027+ debug ! ( "Configuring QEMU for direct kernel boot" ) ;
9991028 let mut qemu_config = crate :: qemu:: QemuConfig :: new_direct_boot (
10001029 opts. common . memory_mb ( ) ?,
10011030 opts. common . vcpus ( ) ?,
@@ -1016,7 +1045,8 @@ StandardOutput=file:/dev/virtio-ports/executestatus
10161045 let credential = crate :: credentials:: smbios_cred_for_root_ssh ( & pubkey) ?;
10171046 qemu_config. add_smbios_credential ( credential) ;
10181047 }
1019- // Build kernel command line
1048+
1049+ // Build kernel command line for direct boot
10201050 let mut kernel_cmdline = [
10211051 // At the core we boot from the mounted container's root,
10221052 "rootfstype=virtiofs" ,
@@ -1046,6 +1076,7 @@ StandardOutput=file:/dev/virtio-ports/executestatus
10461076 }
10471077
10481078 kernel_cmdline. extend ( opts. kernel_args . clone ( ) ) ;
1079+ qemu_config. set_kernel_cmdline ( kernel_cmdline) ;
10491080
10501081 // TODO allocate unlinked unnamed file and pass via fd
10511082 let mut tmp_swapfile = None ;
@@ -1153,9 +1184,7 @@ Options=
11531184 }
11541185 }
11551186
1156- qemu_config
1157- . set_kernel_cmdline ( kernel_cmdline)
1158- . set_console ( opts. common . console ) ;
1187+ qemu_config. set_console ( opts. common . console ) ;
11591188
11601189 // Add virtio-serial device for journal streaming
11611190 qemu_config. add_virtio_serial_out ( "org.bcvk.journal" , "/run/journal.log" . to_string ( ) , false ) ;
0 commit comments