Skip to content

Commit 12be1bb

Browse files
arch/x86: Changed system call ABI
Signed-off-by: Ioan-Cristian CÎRSTEA <ioan.cirstea@oxidos.io>
1 parent cf01b6c commit 12be1bb

2 files changed

Lines changed: 18 additions & 167 deletions

File tree

arch/x86/src/boundary/boundary_impl.rs

Lines changed: 18 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,11 @@ impl UserspaceKernelBoundary for Boundary {
8585

8686
unsafe fn set_syscall_return_value(
8787
&self,
88-
accessible_memory_start: *const u8,
89-
app_brk: *const u8,
88+
_accessible_memory_start: *const u8,
89+
_app_brk: *const u8,
9090
state: &mut Self::StoredState,
9191
return_value: SyscallReturn,
9292
) -> Result<(), ()> {
93-
let mut ret0 = 0;
94-
let mut ret1 = 0;
95-
let mut ret2 = 0;
96-
let mut ret3 = 0;
97-
9893
// These operations are only safe so long as
9994
// - the pointers are properly aligned. This is guaranteed because the
10095
// pointers are all offset multiples of 4 bytes from the stack
@@ -117,59 +112,26 @@ impl UserspaceKernelBoundary for Boundary {
117112
&kernel::utilities::arch_helpers::TRD104SyscallReturn::from_syscall_return(
118113
return_value,
119114
),
120-
&mut ret0,
121-
&mut ret1,
122-
&mut ret2,
123-
&mut ret3,
115+
&mut state.ebx,
116+
&mut state.ecx,
117+
&mut state.edx,
118+
&mut state.edi,
124119
);
125120

126-
// App allocates 16 bytes of stack space for passing syscall arguments. We re-use that stack
127-
// space to pass return values.
128-
//
129-
// Safety: Caller of this function has guaranteed that the memory region is valid.
130-
unsafe {
131-
state.write_stack(0, ret0, accessible_memory_start, app_brk)?;
132-
state.write_stack(1, ret1, accessible_memory_start, app_brk)?;
133-
state.write_stack(2, ret2, accessible_memory_start, app_brk)?;
134-
state.write_stack(3, ret3, accessible_memory_start, app_brk)?;
135-
}
136-
137121
Ok(())
138122
}
139123

140124
unsafe fn set_process_function(
141125
&self,
142-
accessible_memory_start: *const u8,
143-
app_brk: *const u8,
126+
_accessible_memory_start: *const u8,
127+
_app_brk: *const u8,
144128
state: &mut Self::StoredState,
145129
upcall: FunctionCall,
146130
) -> Result<(), ()> {
147-
// Our x86 port expects upcalls to be standard cdecl routines. We push args and return
148-
// address onto the stack accordingly.
149-
//
150-
// Upcall arguments are written directly into the existing stack space (rather than
151-
// being pushed on top). This is safe to do because:
152-
//
153-
// * When the process first starts ESP is initialized to `app_brk - 16`, giving us exactly
154-
// enough space for these arguments.
155-
// * Otherwise, we assume the app is currently issuing a `yield` syscall. We re-use the
156-
// stack space from that syscall. This is okay because `yield` doesn't return anything.
157-
//
158-
// Safety: Caller of this function has guaranteed that the memory region is valid.
159-
// usize is u32 on x86
160-
unsafe {
161-
state.write_stack(0, upcall.argument0 as u32, accessible_memory_start, app_brk)?;
162-
state.write_stack(1, upcall.argument1 as u32, accessible_memory_start, app_brk)?;
163-
state.write_stack(2, upcall.argument2 as u32, accessible_memory_start, app_brk)?;
164-
state.write_stack(
165-
3,
166-
upcall.argument3.as_usize() as u32,
167-
accessible_memory_start,
168-
app_brk,
169-
)?;
170-
171-
state.push_stack(state.eip, accessible_memory_start, app_brk)?;
172-
}
131+
state.ebx = upcall.argument0 as u32;
132+
state.ecx = upcall.argument1 as u32;
133+
state.edx = upcall.argument2 as u32;
134+
state.edi = upcall.argument3.as_usize() as u32;
173135

174136
// The next time we switch to this process, we will directly jump to the upcall. When the
175137
// upcall issues `ret`, it will return to wherever the yield syscall was invoked.
@@ -180,8 +142,8 @@ impl UserspaceKernelBoundary for Boundary {
180142

181143
unsafe fn switch_to_process(
182144
&self,
183-
accessible_memory_start: *const u8,
184-
app_brk: *const u8,
145+
_accessible_memory_start: *const u8,
146+
_app_brk: *const u8,
185147
state: &mut Self::StoredState,
186148
) -> (ContextSwitchReason, Option<*const u8>) {
187149
// Sanity check: don't try to run a faulted app
@@ -203,17 +165,10 @@ impl UserspaceKernelBoundary for Boundary {
203165
SYSCALL_VECTOR => {
204166
let num = state.eax as u8;
205167

206-
// Syscall arguments are passed on the stack using cdecl convention.
207-
//
208-
// Safety: Caller of this function has guaranteed that the memory region is valid.
209-
let arg0 =
210-
unsafe { state.read_stack(0, accessible_memory_start, app_brk) }.unwrap_or(0);
211-
let arg1 =
212-
unsafe { state.read_stack(1, accessible_memory_start, app_brk) }.unwrap_or(0);
213-
let arg2 =
214-
unsafe { state.read_stack(2, accessible_memory_start, app_brk) }.unwrap_or(0);
215-
let arg3 =
216-
unsafe { state.read_stack(3, accessible_memory_start, app_brk) }.unwrap_or(0);
168+
let arg0 = state.ebx;
169+
let arg1 = state.ecx;
170+
let arg2 = state.edx;
171+
let arg3 = state.edi;
217172

218173
Syscall::from_register_arguments(
219174
num,

arch/x86/src/boundary/context.rs

Lines changed: 0 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
// Copyright Tock Contributors 2024.
44

55
use core::fmt::{self, Display, Formatter};
6-
use core::mem::size_of;
7-
use core::ptr;
86

97
use crate::registers::irq::EXCEPTIONS;
108

@@ -44,108 +42,6 @@ pub struct UserContext {
4442
pub err_code: u32,
4543
}
4644

47-
impl UserContext {
48-
/// Pushes a value onto the user stack.
49-
///
50-
/// Returns an `Err` if the new stack value would fall outside of valid memory.
51-
///
52-
/// ## Safety
53-
///
54-
/// The memory region described by `accessible_memory_start` and `app_brk` must point to memory
55-
/// of the user process. This function will write to that memory.
56-
pub unsafe fn push_stack(
57-
&mut self,
58-
value: u32,
59-
accessible_memory_start: *const u8,
60-
app_brk: *const u8,
61-
) -> Result<(), ()> {
62-
let new_esp = self.esp - 4;
63-
64-
if new_esp < accessible_memory_start as u32 {
65-
return Err(());
66-
}
67-
68-
if new_esp + 4 > app_brk as u32 {
69-
return Err(());
70-
}
71-
72-
// Safety: We have validated above that new_esp lies within the specified memory region, and
73-
// the caller has guaranteed that this region is valid.
74-
unsafe { ptr::write_volatile(new_esp as *mut u32, value) };
75-
76-
self.esp = new_esp;
77-
78-
Ok(())
79-
}
80-
81-
/// Reads a value from `offset` relative to the current user stack pointer.
82-
///
83-
/// `offset` is a DWORD offset (i.e. 4 bytes), not bytes.
84-
///
85-
/// Returns an `Err` if the specified location falls outside of valid memory.
86-
///
87-
/// ## Safety
88-
///
89-
/// The memory region described by `accessible_memory_start` and `app_brk` must point to memory
90-
/// of the user process. This function will read from that memory.
91-
pub unsafe fn read_stack(
92-
&self,
93-
offset: u32,
94-
accessible_memory_start: *const u8,
95-
app_brk: *const u8,
96-
) -> Result<u32, ()> {
97-
let stack_addr = self.esp + (offset * 4);
98-
99-
if stack_addr < accessible_memory_start as u32 {
100-
return Err(());
101-
}
102-
103-
if stack_addr + 4 > app_brk as u32 {
104-
return Err(());
105-
}
106-
107-
// Safety: We have validated above that stack_addr lies within the specified memory region,
108-
// and the caller has guaranteed that this region is valid.
109-
let val = unsafe { ptr::read_volatile(stack_addr as *mut u32) };
110-
111-
Ok(val)
112-
}
113-
114-
/// Writes a value to `offset` relative to the current user stack pointer.
115-
///
116-
/// `offset` is a DWORD offset (i.e. 4 bytes), not bytes.
117-
///
118-
/// Returns an `Err` if the specified location falls outside of valid memory.
119-
///
120-
/// ## Safety
121-
///
122-
/// The memory region described by `accessible_memory_start` and `app_brk` must point to memory
123-
/// of the user process. This function will write to that memory.
124-
pub unsafe fn write_stack(
125-
&self,
126-
offset: u32,
127-
value: u32,
128-
accessible_memory_start: *const u8,
129-
app_brk: *const u8,
130-
) -> Result<(), ()> {
131-
let stack_addr = self.esp + (offset * size_of::<usize>() as u32);
132-
133-
if stack_addr < accessible_memory_start as u32 {
134-
return Err(());
135-
}
136-
137-
if stack_addr + 4 > app_brk as u32 {
138-
return Err(());
139-
}
140-
141-
// Safety: We have validated above that stack_addr lies within the specified memory region,
142-
// and the caller has guaranteed that this region is valid.
143-
unsafe { ptr::write_volatile(stack_addr as *mut u32, value) };
144-
145-
Ok(())
146-
}
147-
}
148-
14945
impl Display for UserContext {
15046
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
15147
writeln!(f)?;

0 commit comments

Comments
 (0)