Skip to content

Commit a62b795

Browse files
committed
Add file I/O primitives to UVM
1 parent 3f25c84 commit a62b795

8 files changed

Lines changed: 507 additions & 11 deletions

File tree

.github/workflows/test.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ jobs:
2222
working-directory: ./spec
2323
run: cargo build
2424

25+
- name: Check generated bindings are up to date
26+
working-directory: ./spec
27+
run: cargo run && git diff --exit-code
28+
2529
- name: Test VM
2630
working-directory: ./vm
2731
run: RUST_BACKTRACE=1 cargo test

docs/syscalls.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,3 +381,79 @@ Close an open socket.
381381

382382
File I/O and filesystem-related functionality. This subsystem is separated out from the general-purpose io subsystem for security reasons.
383383

384+
## file_open
385+
386+
```
387+
u64 file_open(const char* path, u64 flags)
388+
```
389+
390+
**Returns:** `u64 handle`
391+
392+
Open the file at the given path. The flags argument is a bitfield combining OPEN_READ, OPEN_WRITE, OPEN_CREATE and OPEN_TRUNC. All access is binary (byte-exact) with no newline translation. Returns a nonzero file handle on success, or 0 on failure (for example if the path is rejected by the sandbox or does not exist).
393+
394+
## file_close
395+
396+
```
397+
void file_close(u64 handle)
398+
```
399+
400+
Close a file handle previously returned by file_open. Has no effect if the handle is not open.
401+
402+
## file_read
403+
404+
```
405+
i64 file_read(u64 handle, u8* buf, u64 num_bytes)
406+
```
407+
408+
**Returns:** `i64 num_bytes`
409+
410+
Read up to num_bytes from the file into the buffer. Returns the number of bytes actually read, 0 at end of file, or -1 on error.
411+
412+
## file_write
413+
414+
```
415+
i64 file_write(u64 handle, const u8* buf, u64 num_bytes)
416+
```
417+
418+
**Returns:** `i64 num_bytes`
419+
420+
Write num_bytes from the buffer to the file. Returns the number of bytes actually written, or -1 on error.
421+
422+
## file_seek
423+
424+
```
425+
u64 file_seek(u64 handle, u64 pos)
426+
```
427+
428+
**Returns:** `u64 new_pos`
429+
430+
Seek to an absolute byte offset measured from the start of the file. Returns the new absolute position.
431+
432+
## file_tell
433+
434+
```
435+
u64 file_tell(u64 handle)
436+
```
437+
438+
**Returns:** `u64 pos`
439+
440+
Return the current absolute byte offset, measured from the start of the file.
441+
442+
## file_size
443+
444+
```
445+
u64 file_size(u64 handle)
446+
```
447+
448+
**Returns:** `u64 num_bytes`
449+
450+
Return the total size of the file in bytes. Does not change the current file position.
451+
452+
## Constants
453+
These are the constants associated with the fs subsystem:
454+
455+
- `u64 OPEN_READ = 1`
456+
- `u64 OPEN_WRITE = 2`
457+
- `u64 OPEN_CREATE = 4`
458+
- `u64 OPEN_TRUNC = 8`
459+

ncc/include/uvm/syscalls.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,34 @@
125125
// Close an open socket.
126126
#define net_close(__socket_id) asm (__socket_id) -> void { syscall net_close; }
127127

128+
// u64 file_open(const char* path, u64 flags)
129+
// Open the file at the given path. The flags argument is a bitfield combining OPEN_READ, OPEN_WRITE, OPEN_CREATE and OPEN_TRUNC. All access is binary (byte-exact) with no newline translation. Returns a nonzero file handle on success, or 0 on failure (for example if the path is rejected by the sandbox or does not exist).
130+
#define file_open(__path, __flags) asm (__path, __flags) -> u64 { syscall file_open; }
131+
132+
// void file_close(u64 handle)
133+
// Close a file handle previously returned by file_open. Has no effect if the handle is not open.
134+
#define file_close(__handle) asm (__handle) -> void { syscall file_close; }
135+
136+
// i64 file_read(u64 handle, u8* buf, u64 num_bytes)
137+
// Read up to num_bytes from the file into the buffer. Returns the number of bytes actually read, 0 at end of file, or -1 on error.
138+
#define file_read(__handle, __buf, __num_bytes) asm (__handle, __buf, __num_bytes) -> i64 { syscall file_read; }
139+
140+
// i64 file_write(u64 handle, const u8* buf, u64 num_bytes)
141+
// Write num_bytes from the buffer to the file. Returns the number of bytes actually written, or -1 on error.
142+
#define file_write(__handle, __buf, __num_bytes) asm (__handle, __buf, __num_bytes) -> i64 { syscall file_write; }
143+
144+
// u64 file_seek(u64 handle, u64 pos)
145+
// Seek to an absolute byte offset measured from the start of the file. Returns the new absolute position.
146+
#define file_seek(__handle, __pos) asm (__handle, __pos) -> u64 { syscall file_seek; }
147+
148+
// u64 file_tell(u64 handle)
149+
// Return the current absolute byte offset, measured from the start of the file.
150+
#define file_tell(__handle) asm (__handle) -> u64 { syscall file_tell; }
151+
152+
// u64 file_size(u64 handle)
153+
// Return the total size of the file in bytes. Does not change the current file position.
154+
#define file_size(__handle) asm (__handle) -> u64 { syscall file_size; }
155+
128156
#define EVENT_QUIT 0
129157
#define EVENT_KEYDOWN 1
130158
#define EVENT_KEYUP 2
@@ -186,5 +214,9 @@
186214
#define KEY_DOWN 16004
187215
#define KEY_SHIFT 16005
188216
#define AUDIO_FORMAT_I16 0
217+
#define OPEN_READ 1
218+
#define OPEN_WRITE 2
219+
#define OPEN_CREATE 4
220+
#define OPEN_TRUNC 8
189221

190222
#endif

spec/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ fn main()
181181

182182
gen_rust_bindings("../vm/src/constants.rs", &subsystems, &idx_to_name);
183183
gen_c_bindings("../ncc/include/uvm/syscalls.h", &subsystems);
184-
gen_markdown("../doc/syscalls.md", &subsystems);
184+
gen_markdown("../docs/syscalls.md", &subsystems);
185185
}
186186

187187
fn gen_rust_bindings(out_file: &str, subsystems: &Vec<SubSystem>, idx_to_name: &Vec<Option<String>>)

spec/syscalls.json

Lines changed: 160 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,165 @@
918918
{
919919
"subsystem": "fs",
920920
"description": "File I/O and filesystem-related functionality. This subsystem is separated out from the general-purpose io subsystem for security reasons.",
921-
"syscalls": [],
922-
"constants": []
921+
"syscalls": [
922+
{
923+
"name": "file_open",
924+
"args": [
925+
[
926+
"const char*",
927+
"path"
928+
],
929+
[
930+
"u64",
931+
"flags"
932+
]
933+
],
934+
"returns": [
935+
"u64",
936+
"handle"
937+
],
938+
"permission": "file_open",
939+
"const_idx": 15,
940+
"description": "Open the file at the given path. The flags argument is a bitfield combining OPEN_READ, OPEN_WRITE, OPEN_CREATE and OPEN_TRUNC. All access is binary (byte-exact) with no newline translation. Returns a nonzero file handle on success, or 0 on failure (for example if the path is rejected by the sandbox or does not exist)."
941+
},
942+
{
943+
"name": "file_close",
944+
"args": [
945+
[
946+
"u64",
947+
"handle"
948+
]
949+
],
950+
"returns": [
951+
"void",
952+
""
953+
],
954+
"permission": "file_io",
955+
"const_idx": 19,
956+
"description": "Close a file handle previously returned by file_open. Has no effect if the handle is not open."
957+
},
958+
{
959+
"name": "file_read",
960+
"args": [
961+
[
962+
"u64",
963+
"handle"
964+
],
965+
[
966+
"u8*",
967+
"buf"
968+
],
969+
[
970+
"u64",
971+
"num_bytes"
972+
]
973+
],
974+
"returns": [
975+
"i64",
976+
"num_bytes"
977+
],
978+
"permission": "file_io",
979+
"const_idx": 32,
980+
"description": "Read up to num_bytes from the file into the buffer. Returns the number of bytes actually read, 0 at end of file, or -1 on error."
981+
},
982+
{
983+
"name": "file_write",
984+
"args": [
985+
[
986+
"u64",
987+
"handle"
988+
],
989+
[
990+
"const u8*",
991+
"buf"
992+
],
993+
[
994+
"u64",
995+
"num_bytes"
996+
]
997+
],
998+
"returns": [
999+
"i64",
1000+
"num_bytes"
1001+
],
1002+
"permission": "file_io",
1003+
"const_idx": 33,
1004+
"description": "Write num_bytes from the buffer to the file. Returns the number of bytes actually written, or -1 on error."
1005+
},
1006+
{
1007+
"name": "file_seek",
1008+
"args": [
1009+
[
1010+
"u64",
1011+
"handle"
1012+
],
1013+
[
1014+
"u64",
1015+
"pos"
1016+
]
1017+
],
1018+
"returns": [
1019+
"u64",
1020+
"new_pos"
1021+
],
1022+
"permission": "file_io",
1023+
"const_idx": 34,
1024+
"description": "Seek to an absolute byte offset measured from the start of the file. Returns the new absolute position."
1025+
},
1026+
{
1027+
"name": "file_tell",
1028+
"args": [
1029+
[
1030+
"u64",
1031+
"handle"
1032+
]
1033+
],
1034+
"returns": [
1035+
"u64",
1036+
"pos"
1037+
],
1038+
"permission": "file_io",
1039+
"const_idx": 35,
1040+
"description": "Return the current absolute byte offset, measured from the start of the file."
1041+
},
1042+
{
1043+
"name": "file_size",
1044+
"args": [
1045+
[
1046+
"u64",
1047+
"handle"
1048+
]
1049+
],
1050+
"returns": [
1051+
"u64",
1052+
"num_bytes"
1053+
],
1054+
"permission": "file_io",
1055+
"const_idx": 36,
1056+
"description": "Return the total size of the file in bytes. Does not change the current file position."
1057+
}
1058+
],
1059+
"constants": [
1060+
[
1061+
"OPEN_READ",
1062+
"u64",
1063+
1
1064+
],
1065+
[
1066+
"OPEN_WRITE",
1067+
"u64",
1068+
2
1069+
],
1070+
[
1071+
"OPEN_CREATE",
1072+
"u64",
1073+
4
1074+
],
1075+
[
1076+
"OPEN_TRUNC",
1077+
"u64",
1078+
8
1079+
]
1080+
]
9231081
}
9241082
]

vm/src/constants.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#![allow(unused)]
66

7-
pub const SYSCALL_TBL_LEN: usize = 32;
7+
pub const SYSCALL_TBL_LEN: usize = 37;
88

99
pub const TIME_CURRENT_MS: u16 = 0;
1010
pub const WINDOW_CREATE: u16 = 1;
@@ -21,9 +21,11 @@ pub const EXIT: u16 = 11;
2121
pub const AUDIO_OPEN_INPUT: u16 = 12;
2222
pub const AUDIO_READ_SAMPLES: u16 = 13;
2323
pub const VM_HEAP_SIZE: u16 = 14;
24+
pub const FILE_OPEN: u16 = 15;
2425
pub const MEMSET32: u16 = 16;
2526
pub const VM_GROW_HEAP: u16 = 17;
2627
pub const AUDIO_OPEN_OUTPUT: u16 = 18;
28+
pub const FILE_CLOSE: u16 = 19;
2729
pub const PRINT_F32: u16 = 20;
2830
pub const NET_LISTEN: u16 = 21;
2931
pub const NET_ACCEPT: u16 = 22;
@@ -36,6 +38,11 @@ pub const THREAD_ID: u16 = 28;
3638
pub const THREAD_SPAWN: u16 = 29;
3739
pub const THREAD_SLEEP: u16 = 30;
3840
pub const THREAD_JOIN: u16 = 31;
41+
pub const FILE_READ: u16 = 32;
42+
pub const FILE_WRITE: u16 = 33;
43+
pub const FILE_SEEK: u16 = 34;
44+
pub const FILE_TELL: u16 = 35;
45+
pub const FILE_SIZE: u16 = 36;
3946

4047
pub struct SysCallDesc
4148
{
@@ -61,11 +68,11 @@ pub const SYSCALL_DESCS: [Option<SysCallDesc>; SYSCALL_TBL_LEN] = [
6168
Some(SysCallDesc { name: "audio_open_input", const_idx: 12, argc: 4, has_ret: true }),
6269
Some(SysCallDesc { name: "audio_read_samples", const_idx: 13, argc: 2, has_ret: false }),
6370
Some(SysCallDesc { name: "vm_heap_size", const_idx: 14, argc: 0, has_ret: true }),
64-
None,
71+
Some(SysCallDesc { name: "file_open", const_idx: 15, argc: 2, has_ret: true }),
6572
Some(SysCallDesc { name: "memset32", const_idx: 16, argc: 3, has_ret: false }),
6673
Some(SysCallDesc { name: "vm_grow_heap", const_idx: 17, argc: 1, has_ret: true }),
6774
Some(SysCallDesc { name: "audio_open_output", const_idx: 18, argc: 4, has_ret: true }),
68-
None,
75+
Some(SysCallDesc { name: "file_close", const_idx: 19, argc: 1, has_ret: false }),
6976
Some(SysCallDesc { name: "print_f32", const_idx: 20, argc: 1, has_ret: false }),
7077
Some(SysCallDesc { name: "net_listen", const_idx: 21, argc: 2, has_ret: true }),
7178
Some(SysCallDesc { name: "net_accept", const_idx: 22, argc: 4, has_ret: true }),
@@ -78,6 +85,11 @@ pub const SYSCALL_DESCS: [Option<SysCallDesc>; SYSCALL_TBL_LEN] = [
7885
Some(SysCallDesc { name: "thread_spawn", const_idx: 29, argc: 2, has_ret: true }),
7986
Some(SysCallDesc { name: "thread_sleep", const_idx: 30, argc: 1, has_ret: false }),
8087
Some(SysCallDesc { name: "thread_join", const_idx: 31, argc: 1, has_ret: true }),
88+
Some(SysCallDesc { name: "file_read", const_idx: 32, argc: 3, has_ret: true }),
89+
Some(SysCallDesc { name: "file_write", const_idx: 33, argc: 3, has_ret: true }),
90+
Some(SysCallDesc { name: "file_seek", const_idx: 34, argc: 2, has_ret: true }),
91+
Some(SysCallDesc { name: "file_tell", const_idx: 35, argc: 1, has_ret: true }),
92+
Some(SysCallDesc { name: "file_size", const_idx: 36, argc: 1, has_ret: true }),
8193
];
8294

8395
pub const EVENT_QUIT: u16 = 0;
@@ -141,3 +153,7 @@ pub const KEY_UP: u16 = 16003;
141153
pub const KEY_DOWN: u16 = 16004;
142154
pub const KEY_SHIFT: u16 = 16005;
143155
pub const AUDIO_FORMAT_I16: u16 = 0;
156+
pub const OPEN_READ: u64 = 1;
157+
pub const OPEN_WRITE: u64 = 2;
158+
pub const OPEN_CREATE: u64 = 4;
159+
pub const OPEN_TRUNC: u64 = 8;

0 commit comments

Comments
 (0)