Skip to content

Commit c617d91

Browse files
authored
Merge pull request #74 from Lind-Project/mmap-impl
mmap/sbrk/brk implementation and integration into glibc/wasmtime
2 parents c3ed5e0 + 1a23771 commit c617d91

File tree

26 files changed

+710
-294
lines changed

26 files changed

+710
-294
lines changed

src/RawPOSIX/src/interface/mem.rs

+215-55
Large diffs are not rendered by default.

src/RawPOSIX/src/safeposix/dispatcher.rs

+18-14
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ pub fn lind_syscall_api(
239239
let mut fildes = arg5 as i32;
240240
let off = arg6 as i64;
241241

242-
interface::mmap_handler(cageid, addr, len, prot, flags, fildes, off)
242+
interface::mmap_handler(cageid, addr, len, prot, flags, fildes, off) as i32
243243
}
244244

245245
PREAD_SYSCALL => {
@@ -1204,33 +1204,32 @@ pub fn lind_syscall_api(
12041204
cage.waitpid_syscall(pid, status, options)
12051205
}
12061206

1207-
12081207
SBRK_SYSCALL => {
1208+
let brk = arg1 as i32;
1209+
1210+
interface::sbrk_handler(cageid, brk) as i32
1211+
}
1212+
1213+
BRK_SYSCALL => {
12091214
let brk = arg1 as u32;
12101215

1211-
interface::sbrk_handler(cageid, brk)
1216+
interface::brk_handler(cageid, brk)
12121217
}
12131218

12141219
_ => -1, // Return -1 for unknown syscalls
12151220
};
1216-
ret
1217-
}
12181221

1219-
// initilize the vmmap, invoked by wasmtime
1220-
pub fn lind_cage_vmmap_init(cageid: u64) {
1221-
let cage = interface::cagetable_getref(cageid);
1222-
let mut vmmap = cage.vmmap.write();
1223-
vmmap.add_entry(VmmapEntry::new(0, 0x30, PROT_WRITE | PROT_READ, 0 /* not sure about this field */, (MAP_PRIVATE | MAP_ANONYMOUS) as i32, false, 0, 0, cageid, MemoryBackingType::Anonymous));
1224-
// BUG: currently need to insert an entry at the end to indicate the end of memory space. This should be fixed soon so that
1225-
// no dummy entries are required to be inserted
1226-
vmmap.add_entry(VmmapEntry::new(1 << 18, 1, PROT_NONE, 0 /* not sure about this field */, (MAP_PRIVATE | MAP_ANONYMOUS) as i32, false, 0, 0, cageid, MemoryBackingType::Anonymous));
1222+
ret
12271223
}
12281224

12291225
// set the wasm linear memory base address to vmmap
1230-
pub fn set_base_address(cageid: u64, base_address: i64) {
1226+
pub fn init_vmmap_helper(cageid: u64, base_address: usize, program_break: Option<u32>) {
12311227
let cage = interface::cagetable_getref(cageid);
12321228
let mut vmmap = cage.vmmap.write();
12331229
vmmap.set_base_address(base_address);
1230+
if program_break.is_some() {
1231+
vmmap.set_program_break(program_break.unwrap());
1232+
}
12341233
}
12351234

12361235
// clone the cage memory. Invoked by wasmtime after cage is forked
@@ -1241,6 +1240,11 @@ pub fn fork_vmmap_helper(parent_cageid: u64, child_cageid: u64) {
12411240
let child_vmmap = child_cage.vmmap.read();
12421241

12431242
interface::fork_vmmap(&parent_vmmap, &child_vmmap);
1243+
1244+
// update program break for child
1245+
drop(child_vmmap);
1246+
let mut child_vmmap = child_cage.vmmap.write();
1247+
child_vmmap.set_program_break(parent_vmmap.program_break);
12441248
}
12451249

12461250
#[no_mangle]

src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,7 @@ impl Cage {
779779
flags: i32,
780780
virtual_fd: i32,
781781
off: i64
782-
) -> i64 {
782+
) -> usize {
783783
if virtual_fd != -1 {
784784
match fdtables::translate_virtual_fd(self.cageid, virtual_fd as u64) {
785785
Ok(kernel_fd) => {
@@ -789,13 +789,13 @@ impl Cage {
789789

790790
// Check if mmap failed and return the appropriate error if so
791791
if ret == -1 {
792-
return syscall_error(Errno::EINVAL, "mmap", "mmap failed with invalid flags") as i64;
792+
return syscall_error(Errno::EINVAL, "mmap", "mmap failed with invalid flags") as usize;
793793
}
794794

795-
ret
795+
ret as usize
796796
},
797797
Err(_e) => {
798-
return syscall_error(Errno::EBADF, "mmap", "Bad File Descriptor") as i64;
798+
return syscall_error(Errno::EBADF, "mmap", "Bad File Descriptor") as usize;
799799
}
800800
}
801801
} else {
@@ -805,10 +805,10 @@ impl Cage {
805805
};
806806
// Check if mmap failed and return the appropriate error if so
807807
if ret == -1 {
808-
return syscall_error(Errno::EINVAL, "mmap", "mmap failed with invalid flags") as i64;
808+
return syscall_error(Errno::EINVAL, "mmap", "mmap failed with invalid flags") as usize;
809809
}
810810

811-
ret
811+
ret as usize
812812
}
813813
}
814814

src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ impl Cage {
179179
sigset: newsigset,
180180
main_threadid: interface::RustAtomicU64::new(0),
181181
interval_timer: interface::IntervalTimer::new(child_cageid),
182-
vmmap: interface::RustLock::new(Vmmap::new()), // Initialize empty virtual memory map for new process
182+
vmmap: interface::RustLock::new(new_vmmap), // Initialize empty virtual memory map for new process
183183
zombies: interface::RustLock::new(vec![]),
184184
child_num: interface::RustAtomicU64::new(0),
185185
};

src/RawPOSIX/src/safeposix/vmmap.rs

+66-77
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use crate::constants::{
2-
PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC,
3-
MAP_SHARED, MAP_PRIVATE, MAP_FIXED, MAP_ANONYMOUS,
4-
MAP_FAILED
2+
MAP_ANONYMOUS, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, MAP_SHARED, PAGESHIFT, PROT_EXEC, PROT_NONE, PROT_READ, PROT_WRITE
53
};
64
use std::io;
75
use nodit::NoditMap;
86
use nodit::{interval::ie, Interval};
97
use crate::fdtables;
108
use crate::safeposix::cage::syscall_error;
119
use crate::safeposix::cage::Errno;
10+
11+
const DEFAULT_VMMAP_SIZE: u32 = 1 << (32 - PAGESHIFT);
12+
1213
/// Used to identify whether the vmmap entry is backed anonymously,
1314
/// by an fd, or by a shared memory segment
1415
///
@@ -243,8 +244,11 @@ pub struct Vmmap {
243244
pub entries: NoditMap<u32, Interval<u32>, VmmapEntry>, // Keyed by `page_num`
244245
pub cached_entry: Option<VmmapEntry>, // TODO: is this still needed?
245246
// Use Option for safety
246-
pub base_address: Option<i64>, // wasm base address. None means uninitialized yet
247+
pub base_address: Option<usize>, // wasm base address. None means uninitialized yet
247248

249+
pub start_address: u32, // start address of valid vmmap address range
250+
pub end_address: u32, // end address of valid vmmap address range
251+
pub program_break: u32, // program break (i.e. heap bottom) of the memory
248252
}
249253

250254
#[allow(dead_code)]
@@ -255,7 +259,10 @@ impl Vmmap {
255259
Vmmap {
256260
entries: NoditMap::new(),
257261
cached_entry: None,
258-
base_address: None
262+
base_address: None,
263+
start_address: 0,
264+
end_address: DEFAULT_VMMAP_SIZE,
265+
program_break: 0,
259266
}
260267
}
261268

@@ -287,20 +294,28 @@ impl Vmmap {
287294
///
288295
/// Arguments:
289296
/// - base_address: The base address to set
290-
pub fn set_base_address(&mut self, base_address: i64) {
297+
pub fn set_base_address(&mut self, base_address: usize) {
291298
// Store the provided base address
292299
self.base_address = Some(base_address);
293300
}
294301

302+
/// Sets the program break for the memory
303+
///
304+
/// Arguments:
305+
/// - program_break: The program break to set
306+
pub fn set_program_break(&mut self, program_break: u32) {
307+
self.program_break = program_break;
308+
}
309+
295310
/// Converts a user address to a system address
296311
///
297312
/// Arguments:
298313
/// - address: User space address to convert
299314
///
300315
/// Returns the corresponding system address
301-
pub fn user_to_sys(&self, address: i32) -> i64 {
316+
pub fn user_to_sys(&self, address: u32) -> usize {
302317
// Add base address to user address to get system address
303-
address as i64 + self.base_address.unwrap()
318+
address as usize + self.base_address.unwrap()
304319
}
305320

306321
/// Converts a system address to a user address
@@ -309,9 +324,9 @@ impl Vmmap {
309324
/// - address: System address to convert
310325
///
311326
/// Returns the corresponding user space address
312-
pub fn sys_to_user(&self, address: i64) -> i32 {
327+
pub fn sys_to_user(&self, address: usize) -> u32 {
313328
// Subtract base address from system address to get user address
314-
(address as i64 - self.base_address.unwrap()) as i32
329+
(address as usize - self.base_address.unwrap()) as u32
315330
}
316331

317332
// Visits each entry in the vmmap, applying a visitor function to each entry
@@ -814,24 +829,17 @@ impl VmmapOps for Vmmap {
814829
/// - Some(Interval) containing the found space
815830
/// - None if no suitable space found
816831
fn find_space(&self, npages: u32) -> Option<Interval<u32>> {
817-
let start = self.first_entry();
818-
let end = self.last_entry();
832+
let start = self.start_address;
833+
let end = self.end_address;
819834

820-
if start == None || end == None {
821-
return None;
822-
} else {
823-
let start_unwrapped = start.unwrap().0.start();
824-
let end_unwrapped = end.unwrap().0.end();
825-
826-
let desired_space = npages + 1; // TODO: check if this is correct
835+
let desired_space = npages + 1; // TODO: check if this is correct
827836

828-
for gap in self
829-
.entries
830-
.gaps_trimmed(ie(start_unwrapped, end_unwrapped))
831-
{
832-
if gap.end() - gap.start() >= desired_space {
833-
return Some(gap);
834-
}
837+
for gap in self
838+
.entries
839+
.gaps_trimmed(ie(start, end))
840+
{
841+
if gap.end() - gap.start() >= desired_space {
842+
return Some(gap);
835843
}
836844
}
837845

@@ -852,19 +860,13 @@ impl VmmapOps for Vmmap {
852860
/// - None if no suitable space found
853861
fn find_space_above_hint(&self, npages: u32, hint: u32) -> Option<Interval<u32>> {
854862
let start = hint;
855-
let end = self.last_entry();
863+
let end = self.end_address;
856864

857-
if end == None {
858-
return None;
859-
} else {
860-
let end_unwrapped = end.unwrap().0.end();
861-
862-
let desired_space = npages + 1; // TODO: check if this is correct
865+
let desired_space = npages + 1; // TODO: check if this is correct
863866

864-
for gap in self.entries.gaps_trimmed(ie(start, end_unwrapped)) {
865-
if gap.end() - gap.start() >= desired_space {
866-
return Some(gap);
867-
}
867+
for gap in self.entries.gaps_trimmed(ie(start, end)) {
868+
if gap.end() - gap.start() >= desired_space {
869+
return Some(gap);
868870
}
869871
}
870872

@@ -888,31 +890,24 @@ impl VmmapOps for Vmmap {
888890
/// - Rounds page numbers up to alignment boundaries
889891
/// - Handles alignment constraints for start and end addresses
890892
fn find_map_space(&self, num_pages: u32, pages_per_map: u32) -> Option<Interval<u32>> {
891-
let start = self.first_entry();
892-
let end = self.last_entry();
893+
let start = self.start_address;
894+
let end = self.end_address;
893895

894-
if start == None || end == None {
895-
return None;
896-
} else {
897-
let start_unwrapped = start.unwrap().0.start();
898-
let end_unwrapped = end.unwrap().0.end();
899-
900-
let rounded_num_pages =
901-
self.round_page_num_up_to_map_multiple(num_pages, pages_per_map);
896+
let rounded_num_pages =
897+
self.round_page_num_up_to_map_multiple(num_pages, pages_per_map);
902898

903-
for gap in self
904-
.entries
905-
.gaps_trimmed(ie(start_unwrapped, end_unwrapped))
906-
{
907-
let aligned_start_page =
908-
self.trunc_page_num_down_to_map_multiple(gap.start(), pages_per_map);
909-
let aligned_end_page =
910-
self.round_page_num_up_to_map_multiple(gap.end(), pages_per_map);
911-
912-
let gap_size = aligned_end_page - aligned_start_page;
913-
if gap_size >= rounded_num_pages {
914-
return Some(ie(aligned_end_page - rounded_num_pages, aligned_end_page));
915-
}
899+
for gap in self
900+
.entries
901+
.gaps_trimmed(ie(start, end))
902+
{
903+
let aligned_start_page =
904+
self.trunc_page_num_down_to_map_multiple(gap.start(), pages_per_map);
905+
let aligned_end_page =
906+
self.round_page_num_up_to_map_multiple(gap.end(), pages_per_map);
907+
908+
let gap_size = aligned_end_page - aligned_start_page;
909+
if gap_size >= rounded_num_pages {
910+
return Some(ie(aligned_end_page - rounded_num_pages, aligned_end_page));
916911
}
917912
}
918913

@@ -944,26 +939,20 @@ impl VmmapOps for Vmmap {
944939
hint: u32,
945940
) -> Option<Interval<u32>> {
946941
let start = hint;
947-
let end = self.last_entry();
942+
let end = self.end_address;
948943

949-
if end == None {
950-
return None;
951-
} else {
952-
let end_unwrapped = end.unwrap().0.end();
953-
954-
let rounded_num_pages =
955-
self.round_page_num_up_to_map_multiple(num_pages, pages_per_map);
944+
let rounded_num_pages =
945+
self.round_page_num_up_to_map_multiple(num_pages, pages_per_map);
956946

957-
for gap in self.entries.gaps_trimmed(ie(start, end_unwrapped)) {
958-
let aligned_start_page =
959-
self.trunc_page_num_down_to_map_multiple(gap.start(), pages_per_map);
960-
let aligned_end_page =
961-
self.round_page_num_up_to_map_multiple(gap.end(), pages_per_map);
947+
for gap in self.entries.gaps_trimmed(ie(start, end)) {
948+
let aligned_start_page =
949+
self.trunc_page_num_down_to_map_multiple(gap.start(), pages_per_map);
950+
let aligned_end_page =
951+
self.round_page_num_up_to_map_multiple(gap.end(), pages_per_map);
962952

963-
let gap_size = aligned_end_page - aligned_start_page;
964-
if gap_size >= rounded_num_pages {
965-
return Some(ie(aligned_end_page - rounded_num_pages, aligned_end_page));
966-
}
953+
let gap_size = aligned_end_page - aligned_start_page;
954+
if gap_size >= rounded_num_pages {
955+
return Some(ie(aligned_end_page - rounded_num_pages, aligned_end_page));
967956
}
968957
}
969958

src/glibc/lind_syscall/lind_syscall.c

+19-11
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,23 @@ int __imported_wasi_snapshot_preview1_lind_syscall(unsigned int callnumber, unsi
3232
// handled here instead
3333
int lind_syscall (unsigned int callnumber, unsigned long long callname, unsigned long long arg1, unsigned long long arg2, unsigned long long arg3, unsigned long long arg4, unsigned long long arg5, unsigned long long arg6)
3434
{
35-
int ret = __imported_wasi_snapshot_preview1_lind_syscall(callnumber, callname, arg1, arg2, arg3, arg4, arg5, arg6);
36-
// handle the errno
37-
if(ret < 0)
38-
{
39-
errno = -ret;
40-
}
41-
else
42-
{
43-
errno = 0;
44-
}
45-
return ret;
35+
int ret = __imported_wasi_snapshot_preview1_lind_syscall(callnumber, callname, arg1, arg2, arg3, arg4, arg5, arg6);
36+
// handle the errno
37+
// in rawposix, we use -errno as the return value to indicate the error
38+
// but this may cause some issues for mmap syscall, because mmap syscall
39+
// is returning an 32-bit address, which may overflow the int type (i32)
40+
// luckily we can handle this easily because the return value of mmap is always
41+
// multiple of pages (typically 4096) even when overflow, therefore we can distinguish
42+
// the errno and mmap result by simply checking if the return value is
43+
// within the valid errno range
44+
if(ret < 0 && ret > -256)
45+
{
46+
errno = -ret;
47+
return -1;
48+
}
49+
else
50+
{
51+
errno = 0;
52+
}
53+
return ret;
4654
}

0 commit comments

Comments
 (0)