1 |
52 |
dgisselq |
////////////////////////////////////////////////////////////////////////////////
|
2 |
|
|
//
|
3 |
|
|
// Filename: syscall.h
|
4 |
|
|
//
|
5 |
|
|
// Project: OpenArty, an entirely open SoC based upon the Arty platform
|
6 |
|
|
//
|
7 |
|
|
// Purpose: User programs often need O/S support. To get such support, they
|
8 |
|
|
// call O/S functions, often named "system calls". These functions
|
9 |
|
|
// run at a different privilege level, and often even within a different
|
10 |
|
|
// address space. Therefore, making a system call usually takes a touch
|
11 |
|
|
// of hardware support. From a hardware standpoint, asking to switch to
|
12 |
|
|
// a higher privilege level is called a "TRAP".
|
13 |
|
|
//
|
14 |
|
|
// For the ZipCPU, a system call is as simple as executing the "TRAP"
|
15 |
|
|
// instruction--one that just clears the GIE bit in the CC register. This
|
16 |
|
|
// can be as simple as "MOV 0,CC", or even "AND ~GIE,CC". Of course, this
|
17 |
|
|
// only works from user mode where the GIE bit is set in the first place.
|
18 |
|
|
// This then transitions the CPU from user to supervisor mode, in a fashion
|
19 |
|
|
// where the supervisor can now examine the user process and tell that it
|
20 |
|
|
// was a trap that caused the return to supervisor mode. To turn this
|
21 |
|
|
// concept into a system call with arguments set and a potential value
|
22 |
|
|
// returned, we place up to four arguments into registers R1-R4, and
|
23 |
|
|
// expect R1 to have any return value.
|
24 |
|
|
//
|
25 |
|
|
// Getting the compiler to do this (place four values into R1-R4 and issue
|
26 |
|
|
// a trap instruction), however, was a nightmare. So, instead, call a
|
27 |
|
|
// function that accepts the same number of arguments (forcing GCC to
|
28 |
|
|
// place them into the registers R1-R4), and we set that function up so
|
29 |
|
|
// that it just does the system call assembly command listed above,
|
30 |
|
|
// followed by a "JMP R0" to return from the system call. This function,
|
31 |
|
|
// because it is so tightly integrated with the compiler and system, is
|
32 |
|
|
// implemented within zipsys as the assembly language routine, system().
|
33 |
|
|
//
|
34 |
|
|
// Here, we just specify what system calls the kernel knows about, what
|
35 |
|
|
// their calling conventions are, etc. In particular, we use R1 (i.e. the
|
36 |
|
|
// first argument) to reference a system call number (a.k.a. trap ID),
|
37 |
|
|
// and the next three arguments can be understood in the context of the
|
38 |
|
|
// system call number.
|
39 |
|
|
//
|
40 |
|
|
// Creator: Dan Gisselquist, Ph.D.
|
41 |
|
|
// Gisselquist Technology, LLC
|
42 |
|
|
//
|
43 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
44 |
|
|
//
|
45 |
|
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
46 |
|
|
//
|
47 |
|
|
// This program is free software (firmware): you can redistribute it and/or
|
48 |
|
|
// modify it under the terms of the GNU General Public License as published
|
49 |
|
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
50 |
|
|
// your option) any later version.
|
51 |
|
|
//
|
52 |
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
53 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
54 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
55 |
|
|
// for more details.
|
56 |
|
|
//
|
57 |
|
|
// You should have received a copy of the GNU General Public License along
|
58 |
|
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
59 |
|
|
// target there if the PDF file isn't present.) If not, see
|
60 |
|
|
// <http://www.gnu.org/licenses/> for a copy.
|
61 |
|
|
//
|
62 |
|
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
63 |
|
|
// http://www.gnu.org/licenses/gpl.html
|
64 |
|
|
//
|
65 |
|
|
//
|
66 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
67 |
|
|
//
|
68 |
|
|
//
|
69 |
|
|
#ifndef SYSCALL_H
|
70 |
|
|
#define SYSCALL_H
|
71 |
|
|
|
72 |
|
|
typedef enum {
|
73 |
|
|
// First two deal with interrupts:
|
74 |
|
|
// syscall(TRAPID_WAIT, intmask, timeout, ?)
|
75 |
|
|
// returns when an interrupt in intmask has taken place.
|
76 |
|
|
// May return immediately if such an interrupt has
|
77 |
|
|
// occurred between the last such syscall and this one
|
78 |
|
|
// If timeout is != 0, specifies the maximum amount of
|
79 |
|
|
// time to wait for the event to occurr.
|
80 |
|
|
// If intmask = 0, then the task will wait for a timeout
|
81 |
|
|
// alone.
|
82 |
|
|
// If the task is stalled for another reason, it may wake
|
83 |
|
|
// early from the trap when the timeout is up.
|
84 |
|
|
// syscall(TRAPID_CLEAR, intmask, timeout, ?)
|
85 |
|
|
// Same thing, except this returns immediately after
|
86 |
|
|
// clearing any potentially pending interrupts
|
87 |
|
|
// If the timeout < 0, clears any pending timeout wakeup
|
88 |
|
|
// If the timeout > 0, sets a pending timeout wakeup and
|
89 |
|
|
// returns.
|
90 |
|
|
// If the timeout == 0, it does nothing with the timeout.
|
91 |
|
|
// syscall(TRAPID_POST, intmask, ?, ?)
|
92 |
|
|
// "Posts" the events in intmask, allowing software
|
93 |
|
|
// "interrupts" to be created. That is, if another
|
94 |
|
|
// piece of software is waiting on an event/interrupt,
|
95 |
|
|
// this can be used to wake up all such pieces of software.
|
96 |
|
|
//
|
97 |
|
|
TRAPID_WAIT, TRAPID_CLEAR, TRAPID_POST,
|
98 |
|
|
//
|
99 |
|
|
// Yield: Yields the processor until the next scheduled time slice.
|
100 |
|
|
// Takes no arguments.
|
101 |
|
|
TRAPID_YIELD,
|
102 |
|
|
//
|
103 |
|
|
// Read/write: Implemented in much the same fashion as the Unix/Posix
|
104 |
|
|
// read/write system calls.
|
105 |
|
|
TRAPID_READ, TRAPID_WRITE,
|
106 |
|
|
//
|
107 |
|
|
// Time: Get the
|
108 |
|
|
TRAPID_TIME,
|
109 |
|
|
//
|
110 |
|
|
// kreturn: Return from a kernel system call. This is necessary if
|
111 |
|
|
// ever an exception triggers a system call. In such cases, it will be
|
112 |
|
|
// impossible to return the caller back to his context in a pristine
|
113 |
|
|
// manner ... without help.
|
114 |
|
|
// TRAPID_KRETURN,
|
115 |
|
|
//
|
116 |
|
|
// Semaphore ID's. These allow us to run the rest of the trap
|
117 |
|
|
// stuffs in kernel space
|
118 |
|
|
TRAPID_SEMGET, TRAPID_SEMPUT, TRAPID_SEMNEW,
|
119 |
|
|
//
|
120 |
|
|
TRAPID_RECV, TRAPID_SEND,
|
121 |
|
|
//
|
122 |
|
|
// Malloc--since we're using a system level malloc, from a system
|
123 |
|
|
// heap for everything, malloc/free require system calls
|
124 |
|
|
// Eventually, this call should be replaced with an sbrk() POSIX
|
125 |
|
|
// system call, but not until a full MMU is implemented and passes
|
126 |
|
|
// testing.
|
127 |
|
|
TRAPID_MALLOC, TRAPID_FREE,
|
128 |
|
|
// EXIT -- end a task
|
129 |
|
|
TRAPID_EXIT
|
130 |
|
|
} TRAPID;
|
131 |
|
|
|
132 |
|
|
extern int syscall(const int id, const int a, const int b, const int c);
|
133 |
|
|
|
134 |
|
|
static inline int read(int fid, void *buf, int ln) {
|
135 |
|
|
return syscall(TRAPID_READ, fid,(int)buf,ln);
|
136 |
|
|
} static inline int write(int fid, const void *buf, int ln) {
|
137 |
|
|
return syscall(TRAPID_WRITE, fid, (int)buf, ln);
|
138 |
|
|
}
|
139 |
|
|
|
140 |
|
|
static inline unsigned time(void) {
|
141 |
|
|
return syscall1(TRAPID_TIME);
|
142 |
|
|
}
|
143 |
|
|
|
144 |
|
|
static inline void yield(void) {
|
145 |
|
|
syscall(TRAPID_YIELD, 0, 0, 0);
|
146 |
|
|
} static inline int wait(unsigned event_mask, int timeout) {
|
147 |
|
|
return syscall(TRAPID_WAIT, (int)event_mask, timeout, 0);
|
148 |
|
|
} static inline int clear(unsigned event, int timeout) {
|
149 |
|
|
return syscall(TRAPID_CLEAR, (int)event, timeout, 0);
|
150 |
|
|
} static inline void post(unsigned event) {
|
151 |
|
|
syscall2(TRAPID_POST, (int)event);
|
152 |
|
|
}
|
153 |
|
|
|
154 |
|
|
|
155 |
|
|
// PORTS:
|
156 |
|
|
// Raw ethernet
|
157 |
|
|
// Just gets sent
|
158 |
|
|
// Raw internet
|
159 |
|
|
// (Needs to MAC via ARP, then IP)
|
160 |
|
|
// UDP ports
|
161 |
|
|
// Adds IP header (sip/dip/dport/sport/etc), sends to raw internet
|
162 |
|
|
// TCP ports
|
163 |
|
|
// Adds IP header (sip/dip/dport/sport/etc), sends to raw internet
|
164 |
|
|
//
|
165 |
|
|
static inline len recv(unsigned port, int buflen, unsigned *buf,
|
166 |
|
|
int timeout) {
|
167 |
|
|
// Timeout = 0 -> wait forever
|
168 |
|
|
// Port = -1 -> system task, receive *any*/all packets
|
169 |
|
|
return syscall5(TRAPID_RECV, port, buflen, buf, timeout);
|
170 |
|
|
}
|
171 |
|
|
|
172 |
|
|
static inline void send(unsigned port, int buflen, unsigned *buf) {
|
173 |
|
|
syscall(TRAPID_SEND, port, buflen, buf);
|
174 |
|
|
}
|
175 |
|
|
|
176 |
|
|
static inline void *malloc(unsigned nbytes) {
|
177 |
|
|
return (void *)syscall2(TRAPID_MALLOC, (int)nbytes0, 0);
|
178 |
|
|
} static inline void free(void *buf) {
|
179 |
|
|
syscall2(TRAPID_FREE,(int)buf);
|
180 |
|
|
}
|
181 |
|
|
|
182 |
|
|
static inline void exit(int status) {
|
183 |
|
|
syscall2(TRAPID_EXIT,status);
|
184 |
|
|
}
|
185 |
|
|
|
186 |
|
|
#endif
|