-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsyscalls.c
181 lines (149 loc) · 3.66 KB
/
syscalls.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include <machine/syscall.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
#include "chardev.h"
#include "kernel_stat.h"
#include "interrupts.h"
#define STDIN_BUF_SIZE 256
static uint8_t stdin_buf[STDIN_BUF_SIZE];
static size_t stdin_buf_rpos = 0;
static size_t stdin_buf_wpos = 0;
static size_t stdin_buf_next_pos(size_t pos)
{
return (pos + 1) % STDIN_BUF_SIZE;
}
static int stdin_buf_is_empty()
{
return stdin_buf_rpos == stdin_buf_wpos;
}
static int stdin_buf_is_full()
{
return stdin_buf_next_pos(stdin_buf_wpos) == stdin_buf_rpos;
}
static void external_interrupt_isr()
{
if (!stdin_buf_is_full())
{
uint8_t byte = *(uint8_t*)0x20000000;
stdin_buf[stdin_buf_wpos] = byte;
stdin_buf_wpos = stdin_buf_next_pos(stdin_buf_wpos);
}
}
static void init_stdin()
{
register_isr(IRQ_MEI, &external_interrupt_isr);
enable_irq(IRQ_MEI);
}
static int sys_close(int fd)
{
if (fd != STDIN_FILENO && fd != STDOUT_FILENO)
return -EBADF;
return 0;
}
static off_t sys_lseek(int fd, off_t offset, int whence)
{
if (fd != STDIN_FILENO && fd != STDOUT_FILENO)
return -EBADF;
return -ESPIPE;
}
static ssize_t sys_read(int fd, void* buf, size_t count)
{
if (fd != STDIN_FILENO)
return -EBADF;
if (stdin_buf_is_empty())
return -EAGAIN;
size_t num_read = 0;
uint8_t* byte_buf = buf;
while (!stdin_buf_is_empty() && num_read < count)
{
*byte_buf = stdin_buf[stdin_buf_rpos];
++num_read;
++byte_buf;
stdin_buf_rpos = stdin_buf_next_pos(stdin_buf_rpos);
}
return num_read;
}
static ssize_t sys_write(int fd, const void* buf, size_t count)
{
if (fd != STDOUT_FILENO)
return -EBADF;
for (size_t i = 0; i < count; ++i)
CHARDEV = ((const char*)buf)[i];
return count;
}
static int sys_fstat(int fd, struct kernel_stat* statbuf)
{
if (fd != STDOUT_FILENO)
return -EBADF;
statbuf->st_dev = 0;
statbuf->st_ino = 0;
statbuf->st_mode = 020600;
statbuf->st_nlink = 1;
statbuf->st_uid = 0;
statbuf->st_gid = 0;
statbuf->st_rdev = 0;
statbuf->st_size = 0;
statbuf->st_blksize = 0;
statbuf->st_blocks = 0;
statbuf->st_atim.tv_sec = 0;
statbuf->st_atim.tv_nsec = 0;
statbuf->st_mtim.tv_sec = 0;
statbuf->st_mtim.tv_nsec = 0;
statbuf->st_ctim.tv_sec = 0;
statbuf->st_ctim.tv_nsec = 0;
return 0;
}
long sys_brk(void* addr)
{
static bool sys_brk_init = false;
extern char* heap_pointer;
static char* brk;
if(!sys_brk_init)
{
brk = heap_pointer;
sys_brk_init = true;
}
if (addr == NULL)
{
return (long)brk;
}
if ((char*)addr >= heap_pointer)
{
brk = addr;
return (long)brk;
}
return -1;
}
__attribute__((noreturn)) static void unsupported_syscall(long n)
{
printf("Unsupported syscall: %li\n", n);
extern __attribute__((noreturn)) void _halt();
_halt();
}
long syscall(long a0, long a1, long a2, long a3, long a4, long a5, long _, long n)
{
switch (n)
{
case SYS_close:
return sys_close(a0);
case SYS_lseek:
return sys_lseek(a0, a1, a2);
case SYS_read:
return sys_read(a0, (void*)a1, a2);
case SYS_write:
return sys_write(a0, (const void*)a1, a2);
case SYS_fstat:
return sys_fstat(a0, (struct kernel_stat*)a1);
case SYS_brk:
return sys_brk((void*)a0);
default:
unsupported_syscall(n);
}
}
__attribute__((constructor)) static void init_syscalls()
{
init_stdin();
}