OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [testsuite/] [test-code-or1k/] [uos/] [uos.c] - Blame information for rev 90

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 90 jeremybenn
/* uos.c.  Microkernel for Or1ksim
2
 
3
   Copyright (C) 2000 Damjan Lampret
4
   Copyright (C) 2010 Embecosm Limited
5
 
6
   Contributor Damjan Lampret <lampret@opencores.org>
7
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
8
 
9
   This file is part of OpenRISC 1000 Architectural Simulator.
10
 
11
   This program is free software; you can redistribute it and/or modify it
12
   under the terms of the GNU General Public License as published by the Free
13
   Software Foundation; either version 3 of the License, or (at your option)
14
   any later version.
15
 
16
   This program is distributed in the hope that it will be useful, but WITHOUT
17
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19
   more details.
20
 
21
   You should have received a copy of the GNU General Public License along
22
   with this program.  If not, see <http:  www.gnu.org/licenses/>.  */
23
 
24
/* ----------------------------------------------------------------------------
25
   This code is commented throughout for use with Doxygen.
26
   --------------------------------------------------------------------------*/
27
 
28
/* This file is part of test microkernel for OpenRISC 1000. */
29
 
30
#include "support.h"
31
#include "spr-defs.h"
32
#include "uos.h"
33
#include "ipc.h"
34
#include "int.h"
35
 
36
/* External functions prototypes */
37
int tick_init(unsigned long period, void (* inf)(void));
38
 
39
/* Pointers to contexts used by except_or32.S routines */
40
unsigned long *task_context;
41
unsigned long *kernel_context;
42
 
43
/* TCBs for all tasks in the system */
44
struct tcb tasks[MAX_TASKS+1];
45
 
46
/* Stacks for the tasks (stacks[0] is kernel stack) */
47
unsigned char stacks[MAX_TASKS+1][STACK_SIZE];
48
 
49
/* MCBs for IPC messages */
50
struct mcb msgs[MAX_MSGS];
51
 
52
/* Pointer to linked list of free MCBs. */
53
struct mcb *free_mcbs;
54
 
55
/* TID of the current user task */
56
tid_t curtask = 0;
57
 
58
/* Statistics */
59
int kernel_sched_cnt = 0;
60
int kernel_syscall_cnt = 0;
61
 
62
/* Timestamp via or1ksim (CPU cycle number). */
63
unsigned long timestamp()
64
{
65
        register unsigned long cycles asm("r3");
66
        asm("l.sys 201");
67
        return cycles;
68
}
69
 
70
/* Standard function for filling memory with a constant byte. */
71
void *memset(void *dst, int c, size_t size)
72
{
73
        char *tmp = dst;
74
 
75
        for(;tmp && (tmp < (char *)dst + size); tmp++)
76
                *(char *)tmp = (char)c;
77
 
78
        return dst;
79
}
80
 
81
/* Traverse linked list of MCBs and show individual messages. */
82
void kernel_show_mcbs(struct mcb *mcb)
83
{
84
        for(;mcb; mcb = mcb->next) {
85
                printf("MCB len=%u origintask=%u ", mcb->length, mcb->origin);
86
                printf("msg:%s\n", mcb->msg);
87
        }
88
}
89
 
90
/* Show all contexts. */
91
void kernel_show_contexts()
92
{
93
        int i;
94
        tid_t t;
95
 
96
        for(t = 1; t <= MAX_TASKS; t++) {
97
                printf("\ntask TID=%d: PC=0x%x ", t, (unsigned)tasks[t].regs.pc & ~0x3);
98
                printf("SP(r1)=0x%x ", (unsigned)tasks[t].regs.sp);
99
                printf("SR[IEE]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_IEE);
100
                printf("SR[TEE]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_TEE);
101
                printf("SR[SM]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_SM);
102
                for(i = 1; i < GPRS; i++) {
103
                        if (i % 4 == 0)
104
                                printf("\n");
105
                        printf("r%d=0x%.8x ", i, (unsigned)tasks[t].regs.gprs[i]);
106
                }
107
                printf("\n");
108
                kernel_show_mcbs(tasks[t].waiting_msgs);
109
        }
110
        printf("\n");
111
}
112
 
113
/* Simple round-robin scheduler that directly calls dispatcher. It is
114
   called by low level external interrupt exception handler or by
115
   kernel_syscall if KERNEL_SYSCALL_SCHED is defined. */
116
void kernel_sched()
117
{
118
        if ((++curtask > MAX_TASKS) || !(tasks[curtask].regs.pc & ~0x3))
119
                curtask = 1;
120
        task_context = (unsigned long *)&tasks[curtask].regs;
121
 
122
#if KERNEL_OUTPUT
123
        printf("kernel_sched(): entry number %d, ", ++kernel_sched_cnt);
124
        printf("dispatching task TID=%d, time %u cycles", curtask, timestamp());
125
 
126
        kernel_show_contexts();
127
#endif
128
 
129
        dispatch();
130
}
131
 
132
/* System call uos_msgsnd. */
133
void
134
uos_msgsnd(tid_t desttask, char *buf, int len)
135
{
136
        asm("l.sys 1");
137
        asm("l.nop");
138
}
139
 
140
/* System call uos_msgrcv. */
141
void
142
uos_msgrcv(tid_t origintask, char *buf, int len)
143
{
144
        asm("l.sys 2");
145
        asm("l.nop");
146
}
147
 
148
/* Handles system call uos_msgsnd. */
149
void kernel_msgsnd(tid_t tid)
150
{
151
        struct mcb *mcb;
152
        struct mcb **dstmq;
153
        struct tcb *task;
154
 
155
        task = &tasks[tid];
156
 
157
        /* Sanity checks. */
158
 
159
        /* Does destination task exist? */
160
        if (!task->regs.gprs[1] || (task->regs.gprs[1] > MAX_TASKS)) {
161
        task->regs.gprs[9] = IPC_ENOTASK;
162
                return;
163
        }
164
 
165
        /* Are there any free MCBs? */
166
        if (!free_mcbs) {
167
                task->regs.gprs[9] = IPC_EOUTOFMCBS;
168
                return;
169
        }
170
 
171
        /* Is message too big to fit into MCB's message buffer? */
172
        if (task->regs.gprs[3] > MAX_MSGLEN) {
173
                task->regs.gprs[9] = IPC_ETOOBIG;
174
                return;
175
        }
176
 
177
        /* OK, send the message. */
178
 
179
        /* First, allocate MCB. */
180
        mcb = free_mcbs;
181
        free_mcbs = mcb->next;
182
 
183
        /* Second, copy message to the MCB. */
184
        memcpy(mcb->msg, (void *)task->regs.gprs[2], task->regs.gprs[3]);
185
        mcb->origin = tid;
186
        mcb->length = task->regs.gprs[3];
187
        mcb->next = NULL;
188
 
189
        /* Insert MCB into destination task's message queue at
190
           the end. */
191
        dstmq = &tasks[task->regs.gprs[1]].waiting_msgs;
192
        for(;*dstmq;)
193
                dstmq = &((*dstmq)->next);
194
        *dstmq = mcb;
195
 
196
        task->regs.gprs[9] = IPC_NOERR;
197
        return;
198
}
199
 
200
/* Handles system call uos_msgrcv. */
201
void kernel_msgrcv(tid_t tid)
202
{
203
        struct mcb *curmsg, **linkp;
204
        struct tcb *task;
205
 
206
        task = &tasks[tid];
207
 
208
        /* Sanity checks. */
209
 
210
        /* Does origin task exist? */
211
        if (task->regs.gprs[1] > MAX_TASKS) {
212
                task->regs.gprs[9] = IPC_ENOTASK;
213
                return;
214
        }
215
 
216
        /* Are there any messages waiting for reception? */
217
        if (!task->waiting_msgs) {
218
                task->regs.gprs[9] = IPC_ENOMSGS;
219
                return;
220
        }
221
 
222
        /* OK, receive the message. */
223
 
224
        /* Search waiting messages for one coming from origintask. If
225
           origintask is zero then grab the first message. */
226
        curmsg = task->waiting_msgs;
227
        linkp = &task->waiting_msgs;
228
        for(;task->regs.gprs[1] && curmsg->next && curmsg->origin != task->regs.gprs[1];) {
229
                linkp = &curmsg->next;
230
                curmsg = curmsg->next;
231
        }
232
 
233
        /* Is receive buffer too small for receiving message? */
234
        if (task->regs.gprs[3] < curmsg->length) {
235
                task->regs.gprs[9] = IPC_ETOOBIG;
236
                return;
237
        }
238
 
239
        /* Now copy the message from the MCB. */
240
        memcpy((void *)task->regs.gprs[2], curmsg->msg, task->regs.gprs[3]);
241
 
242
        /* Remove MCB from task's waiting queue and place it
243
           back into free MCBs queue. */
244
        *linkp = curmsg->next;
245
        curmsg->next = free_mcbs;
246
        free_mcbs = curmsg;
247
 
248
        task->regs.gprs[9] = IPC_NOERR;
249
        return;
250
}
251
 
252
/* Handles all uOS system calls. It is called by low level system call
253
   exception handler. */
254
void kernel_syscall()
255
{
256
        unsigned short syscall_num;
257
 
258
#if KERNEL_OUTPUT
259
        printf("kernel_syscall(): entry number %d, ", ++kernel_syscall_cnt);
260
        printf("current TID=%d, time %u cycles", curtask, timestamp());
261
 
262
        kernel_show_contexts();
263
#endif  
264
        syscall_num = *(unsigned short *)((tasks[curtask].regs.pc & ~0x3) - 6);
265
 
266
        switch(syscall_num) {
267
                case IPC_MSGSND:
268
                        kernel_msgsnd(curtask);
269
                        break;
270
                case IPC_MSGRCV:
271
                        kernel_msgrcv(curtask);
272
                        break;
273
                default:
274
                        printf("kernel_syscall(): unknown syscall (%u)\n", syscall_num);
275
        }
276
 
277
#if KERNEL_SYSCALL_SCHED
278
        kernel_sched();
279
#endif
280
        dispatch();
281
}
282
 
283
/* Called by reset exception handler to initialize the kernel and start
284
   rolling first task. */
285
void
286
kernel_init()
287
{
288
        tid_t t;
289
        int i;
290
 
291
        printf("Initializing kernel:\n");
292
 
293
        printf("  Clearing kernel structures...\n");
294
        memset(tasks, 0, sizeof(tasks));
295
        memset(stacks, 0, sizeof(stacks));
296
        memset(msgs, 0, sizeof(msgs));
297
 
298
        printf("  Initializing MCBs... %d MCB(s)\n", MAX_MSGS);
299
        for(i = 0; i < (MAX_MSGS - 1); i++)
300
                msgs[i].next = &msgs[i+1];
301
        free_mcbs = &msgs[0];
302
 
303
        printf("  Initializing TCBs... %d user task(s)\n", MAX_TASKS);
304
 
305
        tasks_entries();
306
 
307
        for(t = 0; t <= MAX_TASKS; t++) {
308
                tasks[t].regs.sp = (unsigned long)stacks[t] + STACK_SIZE - 4;
309
                /* Disable EXR for kernel context */
310
                tasks[t].regs.sr |= (t == 0 ? SPR_SR_SM : SPR_SR_TEE | SPR_SR_IEE);
311
                tasks[t].regs.gprs[1] = t;
312
        }
313
 
314
        /* First task runs in seprvisor mode */
315
        tasks[1].regs.sr |= SPR_SR_SM;
316
 
317
        /* TID=0 is reserved for kernel use */
318
        kernel_context = (unsigned long *)&tasks[0].regs;
319
 
320
        /* First task to be scheduled is task TID=1 */
321
        task_context = (unsigned long *)&tasks[1].regs;
322
 
323
        /* Initialize initrrupt controller */
324
        int_init();
325
 
326
        printf("  Exceptions will be enabled when first task is dispatched.\n");
327
        printf("Kernel initalized. Starting first user task.\n");
328
 
329
#if KERNEL_SYSCALL_SCHED
330
        kernel_sched();         /* Lets schedule and dispatch our first task */
331
#else
332
        tick_init(TICK_PERIOD, kernel_sched);
333
        kernel_sched();         /* Lets schedule and dispatch our first task */
334
#endif  
335
        /* ... */               /* We never get here */
336
}
337
 
338
int main ()
339
{
340
  kernel_init();
341
  return 0;
342
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.