@@ -737,70 +737,102 @@ 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" ) ;
750+ let mut uki_file = None ;
742751 let mut vmlinuz_path = None ;
743752 let mut initramfs_path = 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 = entry. path ( ) ;
757+
758+ // Check for UKI (.efi file)
759+ if path. is_file ( ) && path. extension ( ) . and_then ( |s| s. to_str ( ) ) == Some ( "efi" ) {
760+ debug ! ( "Found UKI file: {:?}" , path) ;
761+ uki_file = Some ( path) ;
762+ break ;
763+ }
764+
765+ // Check for traditional kernel in subdirectories
766+ if path. is_dir ( ) {
767+ let vmlinuz = path. join ( "vmlinuz" ) ;
768+ let initramfs = path. join ( "initramfs.img" ) ;
751769 if vmlinuz. exists ( ) && initramfs. exists ( ) {
752770 debug ! ( "Found kernel at: {:?}" , vmlinuz) ;
753771 vmlinuz_path = Some ( vmlinuz) ;
754772 initramfs_path = Some ( initramfs) ;
755- break ;
756773 }
757774 }
758775 }
759776
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" ) ?;
772777 let kernel_mount = "/run/qemu/kernel" ;
773778 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- }
790779
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" ) ) ;
780+ // Extract from UKI if found, otherwise use traditional kernel
781+ if let Some ( uki_path) = uki_file {
782+ debug ! ( "Extracting kernel and initramfs from UKI: {:?}" , uki_path) ;
783+
784+ // Extract .linux section (kernel) from UKI
785+ Command :: new ( "objcopy" )
786+ . args ( [
787+ "--dump-section" ,
788+ & format ! ( ".linux={}" , kernel_mount) ,
789+ uki_path. to_str ( ) . unwrap ( ) ,
790+ ] )
791+ . run ( )
792+ . map_err ( |e| eyre ! ( "Failed to extract kernel from UKI: {e}" ) ) ?;
793+ debug ! ( "Extracted kernel from UKI to {}" , kernel_mount) ;
794+
795+ // Extract .initrd section (initramfs) from UKI
796+ Command :: new ( "objcopy" )
797+ . args ( [
798+ "--dump-section" ,
799+ & format ! ( ".initrd={}" , initramfs_mount) ,
800+ uki_path. to_str ( ) . unwrap ( ) ,
801+ ] )
802+ . run ( )
803+ . map_err ( |e| eyre ! ( "Failed to extract initramfs from UKI: {e}" ) ) ?;
804+ debug ! ( "Extracted initramfs from UKI to {}" , initramfs_mount) ;
805+ } else {
806+ let vmlinuz_path = vmlinuz_path
807+ . ok_or_else ( || eyre ! ( "No kernel found in /run/source-image/usr/lib/modules" ) ) ?;
808+ let initramfs_path = initramfs_path
809+ . ok_or_else ( || eyre ! ( "No initramfs found in /run/source-image/usr/lib/modules" ) ) ?;
810+
811+ fs:: File :: create ( & kernel_mount) ?;
812+ fs:: File :: create ( & initramfs_mount) ?;
813+
814+ // Bind mount kernel and initramfs
815+ Command :: new ( "mount" )
816+ . args ( [
817+ "--bind" ,
818+ "-o" ,
819+ "ro" ,
820+ vmlinuz_path. to_str ( ) . unwrap ( ) ,
821+ & kernel_mount,
822+ ] )
823+ . run ( )
824+ . context ( "Failed to bind mount kernel" ) ?;
825+
826+ Command :: new ( "mount" )
827+ . args ( [
828+ "--bind" ,
829+ "-o" ,
830+ "ro" ,
831+ initramfs_path. to_str ( ) . unwrap ( ) ,
832+ & initramfs_mount,
833+ ] )
834+ . run ( )
835+ . context ( "Failed to bind mount initramfs" ) ?;
804836 }
805837
806838 // Process host mounts and prepare virtiofsd instances for each using async manager
@@ -993,7 +1025,8 @@ StandardOutput=file:/dev/virtio-ports/executestatus
9931025
9941026 std:: fs:: create_dir_all ( CONTAINER_STATEDIR ) ?;
9951027
996- // Configure qemu
1028+ // Configure qemu for direct kernel boot
1029+ debug ! ( "Configuring QEMU for direct kernel boot" ) ;
9971030 let mut qemu_config = crate :: qemu:: QemuConfig :: new_direct_boot (
9981031 opts. common . memory_mb ( ) ?,
9991032 opts. common . vcpus ( ) ?,
@@ -1014,7 +1047,8 @@ StandardOutput=file:/dev/virtio-ports/executestatus
10141047 let credential = crate :: credentials:: smbios_cred_for_root_ssh ( & pubkey) ?;
10151048 qemu_config. add_smbios_credential ( credential) ;
10161049 }
1017- // Build kernel command line
1050+
1051+ // Build kernel command line for direct boot
10181052 let mut kernel_cmdline = [
10191053 // At the core we boot from the mounted container's root,
10201054 "rootfstype=virtiofs" ,
@@ -1044,6 +1078,7 @@ StandardOutput=file:/dev/virtio-ports/executestatus
10441078 }
10451079
10461080 kernel_cmdline. extend ( opts. kernel_args . clone ( ) ) ;
1081+ qemu_config. set_kernel_cmdline ( kernel_cmdline) ;
10471082
10481083 // TODO allocate unlinked unnamed file and pass via fd
10491084 let mut tmp_swapfile = None ;
@@ -1151,9 +1186,7 @@ Options=
11511186 }
11521187 }
11531188
1154- qemu_config
1155- . set_kernel_cmdline ( kernel_cmdline)
1156- . set_console ( opts. common . console ) ;
1189+ qemu_config. set_console ( opts. common . console ) ;
11571190
11581191 // Add virtio-serial device for journal streaming
11591192 qemu_config. add_virtio_serial_out ( "org.bcvk.journal" , "/run/journal.log" . to_string ( ) , false ) ;
0 commit comments