Nothing to see here, move along
at main 269 lines 10 kB view raw
1use crate::cap::object::ObjectTag; 2use crate::cap::pool::POOL; 3use crate::cap::table::{CapRef, Rights}; 4use crate::ipc::{AlwaysBlocked, IpcOutcome, endpoint, message}; 5use crate::proc::context::{CpuContext, IpcMessage}; 6use crate::proc::{BlockedReason, PROCESSES, ProcessState}; 7use lancer_core::object_layout::EndpointObject; 8 9crate::kernel_test!( 10 fn recv_fast_path_delivers_message() { 11 let mut allocator = crate::mem::phys::BitmapFrameAllocator; 12 let mut ptable = PROCESSES.lock(); 13 14 let sender_created = ptable.allocate(&mut allocator).expect("alloc sender"); 15 let recv_created = ptable.allocate(&mut allocator).expect("alloc receiver"); 16 ptable.start(sender_created).expect("start sender"); 17 ptable.start(recv_created).expect("start receiver"); 18 let sender_pid = sender_created.pid(); 19 let recv_pid = recv_created.pid(); 20 21 let (ep_id, ep_gen) = 22 crate::tests::helpers::alloc_endpoint(&mut POOL.lock()).expect("alloc endpoint"); 23 24 let msg = IpcMessage::from_regs([ 25 0xCAFE_0001, 26 0xCAFE_0002, 27 0xCAFE_0003, 28 0xCAFE_0004, 29 0xCAFE_0005, 30 0xCAFE_0006, 31 ]); 32 ptable.exec_mut(sender_pid).unwrap().ipc_message = msg; 33 34 ptable.simulate_dispatch(sender_pid); 35 let blocked = ptable[sender_pid] 36 .block_on(BlockedReason::Sending(ep_id, ep_gen)) 37 .expect("block sender"); 38 39 { 40 let mut pool = POOL.lock(); 41 let ep = pool 42 .write_as::<EndpointObject>(ep_id, ep_gen) 43 .expect("get ep"); 44 let mut senders = endpoint::load_senders(ep); 45 endpoint::enqueue(&mut senders, blocked, &mut ptable).expect("enqueue sender"); 46 let ep = pool 47 .write_as::<EndpointObject>(ep_id, ep_gen) 48 .expect("get ep"); 49 endpoint::store_senders(ep, &senders); 50 } 51 52 let cap = CapRef::new(ObjectTag::Endpoint, ep_id, Rights::ALL, ep_gen); 53 let result = endpoint::do_recv(&cap, recv_pid, &mut ptable); 54 55 let returned_sender = match result { 56 Ok(IpcOutcome::Done(pid)) => pid, 57 _ => panic!("expected Done from do_recv fast path"), 58 }; 59 assert!( 60 returned_sender == sender_pid, 61 "do_recv should return the sender's pid" 62 ); 63 64 let recv_msg = ptable.exec(recv_pid).unwrap().ipc_message; 65 66 let mut ctx = CpuContext::zero(); 67 message::inject_into_context(&mut ctx, &recv_msg); 68 ctx.rax = returned_sender.raw() as u64; 69 70 assert!( 71 ctx.rsi == 0xCAFE_0001, 72 "msg[0] must be delivered to ctx.rsi" 73 ); 74 assert!( 75 ctx.rdx == 0xCAFE_0002, 76 "msg[1] must be delivered to ctx.rdx" 77 ); 78 assert!( 79 ctx.r10 == 0xCAFE_0003, 80 "msg[2] must be delivered to ctx.r10" 81 ); 82 assert!(ctx.r8 == 0xCAFE_0004, "msg[3] must be delivered to ctx.r8"); 83 assert!(ctx.r9 == 0xCAFE_0005, "msg[4] must be delivered to ctx.r9"); 84 assert!( 85 ctx.r12 == 0xCAFE_0006, 86 "msg[5] must be delivered to ctx.r12" 87 ); 88 89 let _ = POOL.lock().dec_ref_phys(ep_id, ep_gen); 90 ptable.destroy(sender_pid, &mut allocator); 91 ptable.destroy(recv_pid, &mut allocator); 92 } 93); 94 95crate::kernel_test!( 96 fn call_fast_path_sets_reply_target() { 97 let mut allocator = crate::mem::phys::BitmapFrameAllocator; 98 let mut ptable = PROCESSES.lock(); 99 100 let caller_created = ptable.allocate(&mut allocator).expect("alloc caller"); 101 let recv_created = ptable.allocate(&mut allocator).expect("alloc receiver"); 102 ptable.start(caller_created).expect("start caller"); 103 ptable.start(recv_created).expect("start receiver"); 104 let caller_pid = caller_created.pid(); 105 let recv_pid = recv_created.pid(); 106 107 let (ep_id, ep_gen) = 108 crate::tests::helpers::alloc_endpoint(&mut POOL.lock()).expect("alloc endpoint"); 109 110 ptable.simulate_dispatch(recv_pid); 111 let blocked_recv = ptable[recv_pid] 112 .block_on(BlockedReason::Receiving(ep_id, ep_gen)) 113 .expect("block receiver"); 114 115 { 116 let mut pool = POOL.lock(); 117 let ep = pool 118 .write_as::<EndpointObject>(ep_id, ep_gen) 119 .expect("get ep"); 120 let mut receivers = endpoint::load_receivers(ep); 121 endpoint::enqueue(&mut receivers, blocked_recv, &mut ptable).expect("enqueue receiver"); 122 let ep = pool 123 .write_as::<EndpointObject>(ep_id, ep_gen) 124 .expect("get ep"); 125 endpoint::store_receivers(ep, &receivers); 126 } 127 128 let msg = IpcMessage::from_regs([0x1234, 0x5678, 0, 0, 0, 0]); 129 ptable.exec_mut(caller_pid).unwrap().ipc_message = msg; 130 ptable.simulate_dispatch(caller_pid); 131 132 let cap = CapRef::new(ObjectTag::Endpoint, ep_id, Rights::ALL, ep_gen); 133 let result = endpoint::do_call(&cap, caller_pid, &mut ptable); 134 135 match result { 136 Ok(AlwaysBlocked) => {} 137 _ => panic!("expected Blocked from do_call fast path"), 138 } 139 140 assert!( 141 ptable[recv_pid].state() == ProcessState::Ready, 142 "receiver should be unblocked after do_call fast path" 143 ); 144 145 assert!( 146 ptable.exec(recv_pid).unwrap().saved_context.rax == caller_pid.raw() as u64, 147 "receiver's rax should hold the caller's pid" 148 ); 149 150 assert!( 151 ptable.exec(recv_pid).unwrap().reply_target == Some(caller_pid), 152 "do_call fast path must set reply_target so receiver can reply" 153 ); 154 155 assert!( 156 ptable[caller_pid].state() == ProcessState::Blocked, 157 "caller should be blocked waiting for reply" 158 ); 159 160 assert!( 161 matches!( 162 ptable[caller_pid].blocked_reason(), 163 Some(BlockedReason::Calling(id, _)) if id == ep_id 164 ), 165 "caller should be blocked as Calling on the endpoint" 166 ); 167 168 let _ = POOL.lock().dec_ref_phys(ep_id, ep_gen); 169 ptable.destroy(caller_pid, &mut allocator); 170 ptable.destroy(recv_pid, &mut allocator); 171 } 172); 173 174crate::kernel_test!( 175 fn send_skips_call_waiters() { 176 let mut allocator = crate::mem::phys::BitmapFrameAllocator; 177 let mut ptable = PROCESSES.lock(); 178 179 let server_created = ptable.allocate(&mut allocator).expect("alloc server"); 180 let client_a_created = ptable.allocate(&mut allocator).expect("alloc client_a"); 181 let client_b_created = ptable.allocate(&mut allocator).expect("alloc client_b"); 182 ptable.start(server_created).expect("start server"); 183 ptable.start(client_a_created).expect("start client_a"); 184 ptable.start(client_b_created).expect("start client_b"); 185 let server_pid = server_created.pid(); 186 let client_a_pid = client_a_created.pid(); 187 let client_b_pid = client_b_created.pid(); 188 189 let (ep_id, ep_gen) = 190 crate::tests::helpers::alloc_endpoint(&mut POOL.lock()).expect("alloc endpoint"); 191 192 ptable.simulate_dispatch(server_pid); 193 let blocked_server = ptable[server_pid] 194 .block_on(BlockedReason::Receiving(ep_id, ep_gen)) 195 .expect("block server"); 196 197 { 198 let mut pool = POOL.lock(); 199 let ep = pool 200 .write_as::<EndpointObject>(ep_id, ep_gen) 201 .expect("get ep"); 202 let mut receivers = endpoint::load_receivers(ep); 203 endpoint::enqueue(&mut receivers, blocked_server, &mut ptable).expect("enqueue server"); 204 let ep = pool 205 .write_as::<EndpointObject>(ep_id, ep_gen) 206 .expect("get ep"); 207 endpoint::store_receivers(ep, &receivers); 208 } 209 210 let msg_a = IpcMessage::from_regs([0xAAAA, 0, 0, 0, 0, 0]); 211 ptable.exec_mut(client_a_pid).unwrap().ipc_message = msg_a; 212 ptable.simulate_dispatch(client_a_pid); 213 214 let cap = CapRef::new(ObjectTag::Endpoint, ep_id, Rights::ALL, ep_gen); 215 let call_result = endpoint::do_call(&cap, client_a_pid, &mut ptable); 216 match call_result { 217 Ok(AlwaysBlocked) => {} 218 _ => panic!("expected Blocked from client_a do_call"), 219 } 220 221 assert!( 222 ptable[server_pid].state() == ProcessState::Ready, 223 "server should be Ready after receiving call" 224 ); 225 assert!( 226 ptable[client_a_pid].state() == ProcessState::Blocked, 227 "client_a should be Blocked waiting for reply" 228 ); 229 230 let msg_b = IpcMessage::from_regs([0xBBBB, 0, 0, 0, 0, 0]); 231 ptable.exec_mut(client_b_pid).unwrap().ipc_message = msg_b; 232 ptable.simulate_dispatch(client_b_pid); 233 234 let send_result = endpoint::do_send(&cap, client_b_pid, &mut ptable); 235 match send_result { 236 Ok(IpcOutcome::Blocked) => {} 237 _ => panic!("expected Blocked from client_b do_send (no genuine receiver)"), 238 } 239 240 assert!( 241 ptable[client_a_pid].state() == ProcessState::Blocked, 242 "client_a must still be blocked. send must not wake call-waiters" 243 ); 244 assert!( 245 matches!( 246 ptable[client_a_pid].blocked_reason(), 247 Some(BlockedReason::Calling(id, _)) if id == ep_id 248 ), 249 "client_a should still have Calling blocked reason" 250 ); 251 252 assert!( 253 ptable[client_b_pid].state() == ProcessState::Blocked, 254 "client_b should be blocked as sender (no genuine receiver available)" 255 ); 256 assert!( 257 matches!( 258 ptable[client_b_pid].blocked_reason(), 259 Some(BlockedReason::Sending(id, _)) if id == ep_id 260 ), 261 "client_b should have Sending blocked reason" 262 ); 263 264 let _ = POOL.lock().dec_ref_phys(ep_id, ep_gen); 265 ptable.destroy(server_pid, &mut allocator); 266 ptable.destroy(client_a_pid, &mut allocator); 267 ptable.destroy(client_b_pid, &mut allocator); 268 } 269);