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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [mips/] [kernel/] [kspd.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * Copyright (C) 2005 MIPS Technologies, Inc.  All rights reserved.
3
 *
4
 *  This program is free software; you can distribute it and/or modify it
5
 *  under the terms of the GNU General Public License (Version 2) as
6
 *  published by the Free Software Foundation.
7
 *
8
 *  This program is distributed in the hope it will be useful, but WITHOUT
9
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11
 *  for more details.
12
 *
13
 *  You should have received a copy of the GNU General Public License along
14
 *  with this program; if not, write to the Free Software Foundation, Inc.,
15
 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
16
 *
17
 */
18
#include <linux/kernel.h>
19
#include <linux/module.h>
20
#include <linux/sched.h>
21
#include <linux/unistd.h>
22
#include <linux/file.h>
23
#include <linux/fs.h>
24
#include <linux/syscalls.h>
25
#include <linux/workqueue.h>
26
#include <linux/errno.h>
27
#include <linux/list.h>
28
 
29
#include <asm/vpe.h>
30
#include <asm/rtlx.h>
31
#include <asm/kspd.h>
32
 
33
static struct workqueue_struct *workqueue = NULL;
34
static struct work_struct work;
35
 
36
extern unsigned long cpu_khz;
37
 
38
struct mtsp_syscall {
39
        int cmd;
40
        unsigned char abi;
41
        unsigned char size;
42
};
43
 
44
struct mtsp_syscall_ret {
45
        int retval;
46
        int errno;
47
};
48
 
49
struct mtsp_syscall_generic {
50
        int arg0;
51
        int arg1;
52
        int arg2;
53
        int arg3;
54
        int arg4;
55
        int arg5;
56
        int arg6;
57
};
58
 
59
static struct list_head kspd_notifylist;
60
static int sp_stopping = 0;
61
 
62
/* these should match with those in the SDE kit */
63
#define MTSP_SYSCALL_BASE       0
64
#define MTSP_SYSCALL_EXIT       (MTSP_SYSCALL_BASE + 0)
65
#define MTSP_SYSCALL_OPEN       (MTSP_SYSCALL_BASE + 1)
66
#define MTSP_SYSCALL_READ       (MTSP_SYSCALL_BASE + 2)
67
#define MTSP_SYSCALL_WRITE      (MTSP_SYSCALL_BASE + 3)
68
#define MTSP_SYSCALL_CLOSE      (MTSP_SYSCALL_BASE + 4)
69
#define MTSP_SYSCALL_LSEEK32    (MTSP_SYSCALL_BASE + 5)
70
#define MTSP_SYSCALL_ISATTY     (MTSP_SYSCALL_BASE + 6)
71
#define MTSP_SYSCALL_GETTIME    (MTSP_SYSCALL_BASE + 7)
72
#define MTSP_SYSCALL_PIPEFREQ   (MTSP_SYSCALL_BASE + 8)
73
#define MTSP_SYSCALL_GETTOD     (MTSP_SYSCALL_BASE + 9)
74
#define MTSP_SYSCALL_IOCTL     (MTSP_SYSCALL_BASE + 10)
75
 
76
#define MTSP_O_RDONLY           0x0000
77
#define MTSP_O_WRONLY           0x0001
78
#define MTSP_O_RDWR             0x0002
79
#define MTSP_O_NONBLOCK         0x0004
80
#define MTSP_O_APPEND           0x0008
81
#define MTSP_O_SHLOCK           0x0010
82
#define MTSP_O_EXLOCK           0x0020
83
#define MTSP_O_ASYNC            0x0040
84
#define MTSP_O_FSYNC            O_SYNC
85
#define MTSP_O_NOFOLLOW         0x0100
86
#define MTSP_O_SYNC             0x0080
87
#define MTSP_O_CREAT            0x0200
88
#define MTSP_O_TRUNC            0x0400
89
#define MTSP_O_EXCL             0x0800
90
#define MTSP_O_BINARY           0x8000
91
 
92
extern int tclimit;
93
 
94
struct apsp_table  {
95
        int sp;
96
        int ap;
97
};
98
 
99
/* we might want to do the mode flags too */
100
struct apsp_table open_flags_table[] = {
101
        { MTSP_O_RDWR, O_RDWR },
102
        { MTSP_O_WRONLY, O_WRONLY },
103
        { MTSP_O_CREAT, O_CREAT },
104
        { MTSP_O_TRUNC, O_TRUNC },
105
        { MTSP_O_NONBLOCK, O_NONBLOCK },
106
        { MTSP_O_APPEND, O_APPEND },
107
        { MTSP_O_NOFOLLOW, O_NOFOLLOW }
108
};
109
 
110
struct apsp_table syscall_command_table[] = {
111
        { MTSP_SYSCALL_OPEN, __NR_open },
112
        { MTSP_SYSCALL_CLOSE, __NR_close },
113
        { MTSP_SYSCALL_READ, __NR_read },
114
        { MTSP_SYSCALL_WRITE, __NR_write },
115
        { MTSP_SYSCALL_LSEEK32, __NR_lseek },
116
        { MTSP_SYSCALL_IOCTL, __NR_ioctl }
117
};
118
 
119
static int sp_syscall(int num, int arg0, int arg1, int arg2, int arg3)
120
{
121
        register long int _num  __asm__("$2") = num;
122
        register long int _arg0  __asm__("$4") = arg0;
123
        register long int _arg1  __asm__("$5") = arg1;
124
        register long int _arg2  __asm__("$6") = arg2;
125
        register long int _arg3  __asm__("$7") = arg3;
126
 
127
        mm_segment_t old_fs;
128
 
129
        old_fs = get_fs();
130
        set_fs(KERNEL_DS);
131
 
132
        __asm__ __volatile__ (
133
        "       syscall                                 \n"
134
        : "=r" (_num), "=r" (_arg3)
135
        : "r" (_num), "r" (_arg0), "r" (_arg1), "r" (_arg2), "r" (_arg3));
136
 
137
        set_fs(old_fs);
138
 
139
        /* $a3 is error flag */
140
        if (_arg3)
141
                return -_num;
142
 
143
        return _num;
144
}
145
 
146
static int translate_syscall_command(int cmd)
147
{
148
        int i;
149
        int ret = -1;
150
 
151
        for (i = 0; i < ARRAY_SIZE(syscall_command_table); i++) {
152
                if ((cmd == syscall_command_table[i].sp))
153
                        return syscall_command_table[i].ap;
154
        }
155
 
156
        return ret;
157
}
158
 
159
static unsigned int translate_open_flags(int flags)
160
{
161
        int i;
162
        unsigned int ret = 0;
163
 
164
        for (i = 0; i < (sizeof(open_flags_table) / sizeof(struct apsp_table));
165
             i++) {
166
                if( (flags & open_flags_table[i].sp) ) {
167
                        ret |= open_flags_table[i].ap;
168
                }
169
        }
170
 
171
        return ret;
172
}
173
 
174
 
175
static void sp_setfsuidgid( uid_t uid, gid_t gid)
176
{
177
        current->fsuid = uid;
178
        current->fsgid = gid;
179
 
180
        key_fsuid_changed(current);
181
        key_fsgid_changed(current);
182
}
183
 
184
/*
185
 * Expects a request to be on the sysio channel. Reads it.  Decides whether
186
 * its a linux syscall and runs it, or whatever.  Puts the return code back
187
 * into the request and sends the whole thing back.
188
 */
189
void sp_work_handle_request(void)
190
{
191
        struct mtsp_syscall sc;
192
        struct mtsp_syscall_generic generic;
193
        struct mtsp_syscall_ret ret;
194
        struct kspd_notifications *n;
195
        unsigned long written;
196
        mm_segment_t old_fs;
197
        struct timeval tv;
198
        struct timezone tz;
199
        int cmd;
200
 
201
        char *vcwd;
202
        int size;
203
 
204
        ret.retval = -1;
205
 
206
        old_fs = get_fs();
207
        set_fs(KERNEL_DS);
208
 
209
        if (!rtlx_read(RTLX_CHANNEL_SYSIO, &sc, sizeof(struct mtsp_syscall))) {
210
                set_fs(old_fs);
211
                printk(KERN_ERR "Expected request but nothing to read\n");
212
                return;
213
        }
214
 
215
        size = sc.size;
216
 
217
        if (size) {
218
                if (!rtlx_read(RTLX_CHANNEL_SYSIO, &generic, size)) {
219
                        set_fs(old_fs);
220
                        printk(KERN_ERR "Expected request but nothing to read\n");
221
                        return;
222
                }
223
        }
224
 
225
        /* Run the syscall at the priviledge of the user who loaded the
226
           SP program */
227
 
228
        if (vpe_getuid(tclimit))
229
                sp_setfsuidgid(vpe_getuid(tclimit), vpe_getgid(tclimit));
230
 
231
        switch (sc.cmd) {
232
        /* needs the flags argument translating from SDE kit to
233
           linux */
234
        case MTSP_SYSCALL_PIPEFREQ:
235
                ret.retval = cpu_khz * 1000;
236
                ret.errno = 0;
237
                break;
238
 
239
        case MTSP_SYSCALL_GETTOD:
240
                memset(&tz, 0, sizeof(tz));
241
                if ((ret.retval = sp_syscall(__NR_gettimeofday, (int)&tv,
242
                                             (int)&tz, 0, 0)) == 0)
243
                ret.retval = tv.tv_sec;
244
                break;
245
 
246
        case MTSP_SYSCALL_EXIT:
247
                list_for_each_entry(n, &kspd_notifylist, list)
248
                        n->kspd_sp_exit(tclimit);
249
                sp_stopping = 1;
250
 
251
                printk(KERN_DEBUG "KSPD got exit syscall from SP exitcode %d\n",
252
                       generic.arg0);
253
                break;
254
 
255
        case MTSP_SYSCALL_OPEN:
256
                generic.arg1 = translate_open_flags(generic.arg1);
257
 
258
                vcwd = vpe_getcwd(tclimit);
259
 
260
                /* change to the cwd of the process that loaded the SP program */
261
                old_fs = get_fs();
262
                set_fs(KERNEL_DS);
263
                sys_chdir(vcwd);
264
                set_fs(old_fs);
265
 
266
                sc.cmd = __NR_open;
267
 
268
                /* fall through */
269
 
270
        default:
271
                if ((sc.cmd >= __NR_Linux) &&
272
                    (sc.cmd <= (__NR_Linux +  __NR_Linux_syscalls)) )
273
                        cmd = sc.cmd;
274
                else
275
                        cmd = translate_syscall_command(sc.cmd);
276
 
277
                if (cmd >= 0) {
278
                        ret.retval = sp_syscall(cmd, generic.arg0, generic.arg1,
279
                                                generic.arg2, generic.arg3);
280
                } else
281
                        printk(KERN_WARNING
282
                               "KSPD: Unknown SP syscall number %d\n", sc.cmd);
283
                break;
284
        } /* switch */
285
 
286
        if (vpe_getuid(tclimit))
287
                sp_setfsuidgid( 0, 0);
288
 
289
        old_fs = get_fs();
290
        set_fs(KERNEL_DS);
291
        written = rtlx_write(RTLX_CHANNEL_SYSIO, &ret, sizeof(ret));
292
        set_fs(old_fs);
293
        if (written < sizeof(ret))
294
                printk("KSPD: sp_work_handle_request failed to send to SP\n");
295
}
296
 
297
static void sp_cleanup(void)
298
{
299
        struct files_struct *files = current->files;
300
        int i, j;
301
        struct fdtable *fdt;
302
 
303
        j = 0;
304
 
305
        /*
306
         * It is safe to dereference the fd table without RCU or
307
         * ->file_lock
308
         */
309
        fdt = files_fdtable(files);
310
        for (;;) {
311
                unsigned long set;
312
                i = j * __NFDBITS;
313
                if (i >= fdt->max_fds)
314
                        break;
315
                set = fdt->open_fds->fds_bits[j++];
316
                while (set) {
317
                        if (set & 1) {
318
                                struct file * file = xchg(&fdt->fd[i], NULL);
319
                                if (file)
320
                                        filp_close(file, files);
321
                        }
322
                        i++;
323
                        set >>= 1;
324
                }
325
        }
326
}
327
 
328
static int channel_open = 0;
329
 
330
/* the work handler */
331
static void sp_work(struct work_struct *unused)
332
{
333
        if (!channel_open) {
334
                if( rtlx_open(RTLX_CHANNEL_SYSIO, 1) != 0) {
335
                        printk("KSPD: unable to open sp channel\n");
336
                        sp_stopping = 1;
337
                } else {
338
                        channel_open++;
339
                        printk(KERN_DEBUG "KSPD: SP channel opened\n");
340
                }
341
        } else {
342
                /* wait for some data, allow it to sleep */
343
                rtlx_read_poll(RTLX_CHANNEL_SYSIO, 1);
344
 
345
                /* Check we haven't been woken because we are stopping */
346
                if (!sp_stopping)
347
                        sp_work_handle_request();
348
        }
349
 
350
        if (!sp_stopping)
351
                queue_work(workqueue, &work);
352
        else
353
                sp_cleanup();
354
}
355
 
356
static void startwork(int vpe)
357
{
358
        sp_stopping = channel_open = 0;
359
 
360
        if (workqueue == NULL) {
361
                if ((workqueue = create_singlethread_workqueue("kspd")) == NULL) {
362
                        printk(KERN_ERR "unable to start kspd\n");
363
                        return;
364
                }
365
 
366
                INIT_WORK(&work, sp_work);
367
        }
368
 
369
        queue_work(workqueue, &work);
370
}
371
 
372
static void stopwork(int vpe)
373
{
374
        sp_stopping = 1;
375
 
376
        printk(KERN_DEBUG "KSPD: SP stopping\n");
377
}
378
 
379
void kspd_notify(struct kspd_notifications *notify)
380
{
381
        list_add(&notify->list, &kspd_notifylist);
382
}
383
 
384
static struct vpe_notifications notify;
385
static int kspd_module_init(void)
386
{
387
        INIT_LIST_HEAD(&kspd_notifylist);
388
 
389
        notify.start = startwork;
390
        notify.stop = stopwork;
391
        vpe_notify(tclimit, &notify);
392
 
393
        return 0;
394
}
395
 
396
static void kspd_module_exit(void)
397
{
398
 
399
}
400
 
401
module_init(kspd_module_init);
402
module_exit(kspd_module_exit);
403
 
404
MODULE_DESCRIPTION("MIPS KSPD");
405
MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
406
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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