@@ -1209,158 +1209,164 @@ pub fn sys_execv_with_frame(
12091209 program_name_ptr : u64 ,
12101210 argv_ptr : u64 ,
12111211) -> SyscallResult {
1212- x86_64:: instructions:: interrupts:: without_interrupts ( || {
1213- log:: info!(
1214- "sys_execv_with_frame called: program_name_ptr={:#x}, argv_ptr={:#x}" ,
1215- program_name_ptr,
1216- argv_ptr
1217- ) ;
1212+ // IMPORTANT: Do NOT wrap the entire function in without_interrupts()!
1213+ // ELF loading from ext2 filesystem requires interrupts for VirtIO I/O.
1214+ // Only the final frame manipulation needs to be interrupt-safe.
12181215
1219- // Get current process and thread
1220- let current_thread_id = match crate :: task:: scheduler:: current_thread_id ( ) {
1221- Some ( id) => id,
1222- None => {
1223- log:: error!( "sys_execv: No current thread" ) ;
1224- return SyscallResult :: Err ( 22 ) ; // EINVAL
1225- }
1226- } ;
1216+ log:: info!(
1217+ "sys_execv_with_frame called: program_name_ptr={:#x}, argv_ptr={:#x}" ,
1218+ program_name_ptr,
1219+ argv_ptr
1220+ ) ;
12271221
1228- // Read the program name from userspace
1229- if program_name_ptr == 0 {
1230- log:: error!( "sys_execv: NULL program name" ) ;
1222+ // Get current process and thread
1223+ let current_thread_id = match crate :: task:: scheduler:: current_thread_id ( ) {
1224+ Some ( id) => id,
1225+ None => {
1226+ log:: error!( "sys_execv: No current thread" ) ;
12311227 return SyscallResult :: Err ( 22 ) ; // EINVAL
12321228 }
1229+ } ;
12331230
1234- let name_bytes = match copy_string_from_user ( program_name_ptr, 256 ) {
1235- Ok ( bytes) => bytes,
1236- Err ( e) => {
1237- log:: error!( "sys_execv: Failed to read program name: {}" , e) ;
1238- return SyscallResult :: Err ( 14 ) ; // EFAULT
1239- }
1240- } ;
1241-
1242- let name_len = name_bytes. iter ( ) . position ( |& b| b == 0 ) . unwrap_or ( name_bytes. len ( ) ) ;
1243- let program_name = match core:: str:: from_utf8 ( & name_bytes[ ..name_len] ) {
1244- Ok ( s) => s,
1245- Err ( _) => {
1246- log:: error!( "sys_execv: Invalid UTF-8 in program name" ) ;
1247- return SyscallResult :: Err ( 22 ) ; // EINVAL
1248- }
1249- } ;
1231+ // Read the program name from userspace
1232+ if program_name_ptr == 0 {
1233+ log:: error!( "sys_execv: NULL program name" ) ;
1234+ return SyscallResult :: Err ( 22 ) ; // EINVAL
1235+ }
12501236
1251- log:: info!( "sys_execv: Loading program '{}'" , program_name) ;
1237+ let name_bytes = match copy_string_from_user ( program_name_ptr, 256 ) {
1238+ Ok ( bytes) => bytes,
1239+ Err ( e) => {
1240+ log:: error!( "sys_execv: Failed to read program name: {}" , e) ;
1241+ return SyscallResult :: Err ( 14 ) ; // EFAULT
1242+ }
1243+ } ;
12521244
1253- // Read argv array from userspace
1254- let mut argv_vec: Vec < Vec < u8 > > = Vec :: new ( ) ;
1245+ let name_len = name_bytes. iter ( ) . position ( |& b| b == 0 ) . unwrap_or ( name_bytes. len ( ) ) ;
1246+ let program_name = match core:: str:: from_utf8 ( & name_bytes[ ..name_len] ) {
1247+ Ok ( s) => s,
1248+ Err ( _) => {
1249+ log:: error!( "sys_execv: Invalid UTF-8 in program name" ) ;
1250+ return SyscallResult :: Err ( 22 ) ; // EINVAL
1251+ }
1252+ } ;
12551253
1256- if argv_ptr != 0 {
1257- // Read up to 64 argument pointers
1258- const MAX_ARGS : usize = 64 ;
1259- const MAX_ARG_LEN : usize = 4096 ;
1254+ log:: info!( "sys_execv: Loading program '{}'" , program_name) ;
12601255
1261- for i in 0 ..MAX_ARGS {
1262- let ptr_addr = argv_ptr + ( i * 8 ) as u64 ;
1263- let arg_ptr_bytes = match copy_from_user ( ptr_addr, 8 ) {
1264- Ok ( bytes) => bytes,
1265- Err ( e) => {
1266- log:: error!( "sys_execv: Failed to read argv[{}] pointer: {}" , i, e) ;
1267- return SyscallResult :: Err ( 14 ) ; // EFAULT
1268- }
1269- } ;
1256+ // Read argv array from userspace (with interrupts enabled - safe)
1257+ let mut argv_vec: Vec < Vec < u8 > > = Vec :: new ( ) ;
12701258
1271- // Interpret as u64 pointer
1272- let arg_ptr = u64:: from_le_bytes ( [
1273- arg_ptr_bytes[ 0 ] , arg_ptr_bytes[ 1 ] , arg_ptr_bytes[ 2 ] , arg_ptr_bytes[ 3 ] ,
1274- arg_ptr_bytes[ 4 ] , arg_ptr_bytes[ 5 ] , arg_ptr_bytes[ 6 ] , arg_ptr_bytes[ 7 ] ,
1275- ] ) ;
1259+ if argv_ptr != 0 {
1260+ // Read up to 64 argument pointers
1261+ const MAX_ARGS : usize = 64 ;
1262+ const MAX_ARG_LEN : usize = 4096 ;
12761263
1277- // NULL pointer marks end of argv
1278- if arg_ptr == 0 {
1279- break ;
1264+ for i in 0 ..MAX_ARGS {
1265+ let ptr_addr = argv_ptr + ( i * 8 ) as u64 ;
1266+ let arg_ptr_bytes = match copy_from_user ( ptr_addr, 8 ) {
1267+ Ok ( bytes) => bytes,
1268+ Err ( e) => {
1269+ log:: error!( "sys_execv: Failed to read argv[{}] pointer: {}" , i, e) ;
1270+ return SyscallResult :: Err ( 14 ) ; // EFAULT
12801271 }
1272+ } ;
12811273
1282- // Read the argument string
1283- let arg_bytes = match copy_string_from_user ( arg_ptr, MAX_ARG_LEN ) {
1284- Ok ( bytes) => bytes,
1285- Err ( e) => {
1286- log:: error!( "sys_execv: Failed to read argv[{}] string at {:#x}: {}" , i, arg_ptr, e) ;
1287- return SyscallResult :: Err ( 14 ) ; // EFAULT
1288- }
1289- } ;
1274+ // Interpret as u64 pointer
1275+ let arg_ptr = u64:: from_le_bytes ( [
1276+ arg_ptr_bytes[ 0 ] , arg_ptr_bytes[ 1 ] , arg_ptr_bytes[ 2 ] , arg_ptr_bytes[ 3 ] ,
1277+ arg_ptr_bytes[ 4 ] , arg_ptr_bytes[ 5 ] , arg_ptr_bytes[ 6 ] , arg_ptr_bytes[ 7 ] ,
1278+ ] ) ;
12901279
1291- // Find null terminator and truncate
1292- let arg_len = arg_bytes. iter ( ) . position ( |& b| b == 0 ) . unwrap_or ( arg_bytes. len ( ) ) ;
1293- let mut arg = arg_bytes[ ..arg_len] . to_vec ( ) ;
1294- arg. push ( 0 ) ; // Ensure null-terminated
1295- argv_vec. push ( arg) ;
1280+ // NULL pointer marks end of argv
1281+ if arg_ptr == 0 {
1282+ break ;
12961283 }
1297- }
12981284
1299- // If no argv provided, use program name as argv[0]
1300- if argv_vec. is_empty ( ) {
1301- let mut arg0 = program_name. as_bytes ( ) . to_vec ( ) ;
1302- arg0. push ( 0 ) ;
1303- argv_vec. push ( arg0) ;
1285+ // Read the argument string
1286+ let arg_bytes = match copy_string_from_user ( arg_ptr, MAX_ARG_LEN ) {
1287+ Ok ( bytes) => bytes,
1288+ Err ( e) => {
1289+ log:: error!( "sys_execv: Failed to read argv[{}] string at {:#x}: {}" , i, arg_ptr, e) ;
1290+ return SyscallResult :: Err ( 14 ) ; // EFAULT
1291+ }
1292+ } ;
1293+
1294+ // Find null terminator and truncate
1295+ let arg_len = arg_bytes. iter ( ) . position ( |& b| b == 0 ) . unwrap_or ( arg_bytes. len ( ) ) ;
1296+ let mut arg = arg_bytes[ ..arg_len] . to_vec ( ) ;
1297+ arg. push ( 0 ) ; // Ensure null-terminated
1298+ argv_vec. push ( arg) ;
13041299 }
1300+ }
13051301
1306- log:: info!( "sys_execv: argc={}" , argv_vec. len( ) ) ;
1307- for ( i, arg) in argv_vec. iter ( ) . enumerate ( ) {
1308- if let Ok ( s) = core:: str:: from_utf8 ( & arg[ ..arg. len ( ) . saturating_sub ( 1 ) ] ) {
1309- log:: debug!( "sys_execv: argv[{}] = '{}'" , i, s) ;
1310- }
1302+ // If no argv provided, use program name as argv[0]
1303+ if argv_vec. is_empty ( ) {
1304+ let mut arg0 = program_name. as_bytes ( ) . to_vec ( ) ;
1305+ arg0. push ( 0 ) ;
1306+ argv_vec. push ( arg0) ;
1307+ }
1308+
1309+ log:: info!( "sys_execv: argc={}" , argv_vec. len( ) ) ;
1310+ for ( i, arg) in argv_vec. iter ( ) . enumerate ( ) {
1311+ if let Ok ( s) = core:: str:: from_utf8 ( & arg[ ..arg. len ( ) . saturating_sub ( 1 ) ] ) {
1312+ log:: debug!( "sys_execv: argv[{}] = '{}'" , i, s) ;
13111313 }
1314+ }
13121315
1313- #[ cfg( feature = "testing" ) ]
1314- {
1315- // Try to load from ext2 filesystem first, fall back to test disk
1316- let elf_vec = if program_name . contains ( '/' ) {
1317- // Path-like name: load from ext2 filesystem
1318- match load_elf_from_ext2 ( program_name ) {
1319- Ok ( data ) => data ,
1320- Err ( errno ) => return SyscallResult :: Err ( errno as u64 ) ,
1321- }
1322- } else {
1323- // Bare name: try ext2 /bin/ first, then fall back to test disk
1324- let bin_path = alloc :: format! ( " /bin/{}" , program_name ) ;
1325- match load_elf_from_ext2 ( & bin_path ) {
1326- Ok ( data ) => data ,
1327- Err ( _ ) => {
1328- // Fall back to test disk for compatibility
1329- crate :: userspace_test :: get_test_binary ( program_name )
1330- }
1316+ #[ cfg( feature = "testing" ) ]
1317+ {
1318+ // Load ELF binary WITH interrupts enabled - ext2 I/O needs timer interrupts
1319+ // for proper VirtIO operation
1320+ let elf_vec = if program_name . contains ( '/' ) {
1321+ // Path-like name: load from ext2 filesystem
1322+ match load_elf_from_ext2 ( program_name ) {
1323+ Ok ( data ) => data ,
1324+ Err ( errno ) => return SyscallResult :: Err ( errno as u64 ) ,
1325+ }
1326+ } else {
1327+ // Bare name: try ext2 /bin/ first, then fall back to test disk
1328+ let bin_path = alloc :: format! ( "/bin/{}" , program_name ) ;
1329+ match load_elf_from_ext2 ( & bin_path ) {
1330+ Ok ( data ) => data ,
1331+ Err ( _ ) => {
1332+ // Fall back to test disk for compatibility
1333+ crate :: userspace_test :: get_test_binary ( program_name )
13311334 }
1332- } ;
1333- let boxed_slice = elf_vec. into_boxed_slice ( ) ;
1334- let elf_data = Box :: leak ( boxed_slice) as & ' static [ u8 ] ;
1335- let name_string = alloc:: string:: String :: from ( program_name) ;
1336- let leaked_name: & ' static str = Box :: leak ( name_string. into_boxed_str ( ) ) ;
1335+ }
1336+ } ;
1337+ let boxed_slice = elf_vec. into_boxed_slice ( ) ;
1338+ let elf_data = Box :: leak ( boxed_slice) as & ' static [ u8 ] ;
1339+ let name_string = alloc:: string:: String :: from ( program_name) ;
1340+ let leaked_name: & ' static str = Box :: leak ( name_string. into_boxed_str ( ) ) ;
13371341
1338- // Find current process
1339- let current_pid = {
1340- let manager_guard = crate :: process:: manager ( ) ;
1341- if let Some ( ref manager) = * manager_guard {
1342- if let Some ( ( pid, _) ) = manager. find_process_by_thread ( current_thread_id) {
1343- pid
1344- } else {
1345- log:: error!( "sys_execv: Thread {} not found in any process" , current_thread_id) ;
1346- return SyscallResult :: Err ( 3 ) ; // ESRCH
1347- }
1342+ // Find current process
1343+ let current_pid = {
1344+ let manager_guard = crate :: process:: manager ( ) ;
1345+ if let Some ( ref manager) = * manager_guard {
1346+ if let Some ( ( pid, _) ) = manager. find_process_by_thread ( current_thread_id) {
1347+ pid
13481348 } else {
1349- log:: error!( "sys_execv: Process manager not available" ) ;
1350- return SyscallResult :: Err ( 12 ) ; // ENOMEM
1349+ log:: error!( "sys_execv: Thread {} not found in any process" , current_thread_id ) ;
1350+ return SyscallResult :: Err ( 3 ) ; // ESRCH
13511351 }
1352- } ;
1352+ } else {
1353+ log:: error!( "sys_execv: Process manager not available" ) ;
1354+ return SyscallResult :: Err ( 12 ) ; // ENOMEM
1355+ }
1356+ } ;
13531357
1354- log:: info!(
1355- "sys_execv: Replacing process {} (thread {}) with new program" ,
1356- current_pid. as_u64( ) ,
1357- current_thread_id
1358- ) ;
1358+ log:: info!(
1359+ "sys_execv: Replacing process {} (thread {}) with new program" ,
1360+ current_pid. as_u64( ) ,
1361+ current_thread_id
1362+ ) ;
13591363
1360- // Convert argv_vec to slice of slices for exec_process_with_argv
1361- let argv_slices: Vec < & [ u8 ] > = argv_vec. iter ( ) . map ( |v| v. as_slice ( ) ) . collect ( ) ;
1364+ // Convert argv_vec to slice of slices for exec_process_with_argv
1365+ let argv_slices: Vec < & [ u8 ] > = argv_vec. iter ( ) . map ( |v| v. as_slice ( ) ) . collect ( ) ;
13621366
1363- // Replace the process's address space with argv support
1367+ // CRITICAL SECTION: Frame manipulation and process state changes
1368+ // Only this part needs interrupts disabled for atomicity
1369+ x86_64:: instructions:: interrupts:: without_interrupts ( || {
13641370 let mut manager_guard = crate :: process:: manager ( ) ;
13651371 if let Some ( ref mut manager) = * manager_guard {
13661372 match manager. exec_process_with_argv ( current_pid, elf_data, Some ( leaked_name) , & argv_slices) {
@@ -1424,13 +1430,13 @@ pub fn sys_execv_with_frame(
14241430 log:: error!( "sys_execv: Process manager not available" ) ;
14251431 SyscallResult :: Err ( 12 ) // ENOMEM
14261432 }
1427- }
1433+ } )
1434+ }
14281435
1429- #[ cfg( not( feature = "testing" ) ) ]
1430- {
1431- SyscallResult :: Err ( 38 ) // ENOSYS
1432- }
1433- } )
1436+ #[ cfg( not( feature = "testing" ) ) ]
1437+ {
1438+ SyscallResult :: Err ( 38 ) // ENOSYS
1439+ }
14341440}
14351441
14361442/// sys_exec - Replace the current process with a new program (deprecated)
0 commit comments