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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [i386/] [kernel/] [ldt.c] - Blame information for rev 1623

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1623 jcastillo
/*
2
 * linux/kernel/ldt.c
3
 *
4
 * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
5
 */
6
 
7
#include <linux/errno.h>
8
#include <linux/sched.h>
9
#include <linux/string.h>
10
#include <linux/mm.h>
11
#include <asm/segment.h>
12
#include <asm/system.h>
13
#include <linux/ldt.h>
14
#include <asm/ptrace.h>
15
 
16
static int read_ldt(void * ptr, unsigned long bytecount)
17
{
18
        int error;
19
        void * address = current->ldt;
20
        unsigned long size;
21
 
22
        if (!ptr)
23
                return -EINVAL;
24
        size = LDT_ENTRIES*LDT_ENTRY_SIZE;
25
        if (!address) {
26
                address = &default_ldt;
27
                size = sizeof(default_ldt);
28
        }
29
        if (size > bytecount)
30
                size = bytecount;
31
        error = verify_area(VERIFY_WRITE, ptr, size);
32
        if (error)
33
                return error;
34
        memcpy_tofs(ptr, address, size);
35
        return size;
36
}
37
 
38
static inline int limits_ok(struct modify_ldt_ldt_s *ldt_info)
39
{
40
        unsigned long base, limit;
41
        /* linear address of first and last accessible byte */
42
        unsigned long first, last;
43
 
44
        base = ldt_info->base_addr;
45
        limit = ldt_info->limit;
46
        if (ldt_info->limit_in_pages)
47
                limit = limit * PAGE_SIZE + PAGE_SIZE - 1;
48
 
49
        first = base;
50
        last = limit + base;
51
 
52
        /* segment grows down? */
53
        if (ldt_info->contents == 1) {
54
                /* data segment grows down */
55
                first = base+limit+1;
56
                last = base+65535;
57
                if (ldt_info->seg_32bit)
58
                        last = base-1;
59
        }
60
        return (last >= first && last < TASK_SIZE);
61
}
62
 
63
static int write_ldt(struct pt_regs * regs, void * ptr, unsigned long bytecount, int oldmode)
64
{
65
        struct modify_ldt_ldt_s ldt_info;
66
        unsigned long *lp;
67
        int error, i;
68
 
69
        if (bytecount != sizeof(ldt_info))
70
                return -EINVAL;
71
        error = verify_area(VERIFY_READ, ptr, sizeof(ldt_info));
72
        if (error)
73
                return error;
74
 
75
        memcpy_fromfs(&ldt_info, ptr, sizeof(ldt_info));
76
 
77
        if ((ldt_info.contents == 3 && (oldmode || ldt_info.seg_not_present == 0)) || ldt_info.entry_number >= LDT_ENTRIES)
78
                return -EINVAL;
79
 
80
        if (!limits_ok(&ldt_info) && (oldmode || ldt_info.seg_not_present == 0))
81
                return -EINVAL;
82
 
83
        if (!current->ldt) {
84
                for (i=1 ; i<NR_TASKS ; i++) {
85
                        if (task[i] == current) {
86
                                if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
87
                                        return -ENOMEM;
88
                                memset(current->ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
89
                                set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
90
                                load_ldt(i);
91
                        }
92
                }
93
        }
94
 
95
        lp = (unsigned long *) &current->ldt[ldt_info.entry_number];
96
        /* Allow LDTs to be cleared by the user. */
97
        if (ldt_info.base_addr == 0 && ldt_info.limit == 0
98
                && (oldmode ||
99
                        (  ldt_info.contents == 0
100
                        && ldt_info.read_exec_only == 1
101
                        && ldt_info.seg_32bit == 0
102
                        && ldt_info.limit_in_pages == 0
103
                        && ldt_info.seg_not_present == 1
104
                        && ldt_info.useable == 0 )) ) {
105
                unsigned short sel =(ldt_info.entry_number <<3) | 7;
106
                if (regs->fs == sel  || regs->gs == sel)
107
                        return -EBUSY;
108
                *lp = 0;
109
                *(lp+1) = 0;
110
                return 0;
111
        }
112
        *lp = ((ldt_info.base_addr & 0x0000ffff) << 16) |
113
                  (ldt_info.limit & 0x0ffff);
114
        *(lp+1) = (ldt_info.base_addr & 0xff000000) |
115
                  ((ldt_info.base_addr & 0x00ff0000)>>16) |
116
                  (ldt_info.limit & 0xf0000) |
117
                  (ldt_info.contents << 10) |
118
                  ((ldt_info.read_exec_only ^ 1) << 9) |
119
                  (ldt_info.seg_32bit << 22) |
120
                  (ldt_info.limit_in_pages << 23) |
121
                  ((ldt_info.seg_not_present ^1) << 15) |
122
                  0x7000;
123
        if (!oldmode) *(lp+1) |= (ldt_info.useable << 20);
124
        return 0;
125
}
126
 
127
asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
128
{
129
        if (func == 0)
130
                return read_ldt(ptr, bytecount);
131
        if (func == 1)
132
                return write_ldt((struct pt_regs *) &func, ptr, bytecount, 1);
133
        if (func == 0x11)
134
                return write_ldt((struct pt_regs *) &func, ptr, bytecount, 0);
135
        return -ENOSYS;
136
}

powered by: WebSVN 2.1.0

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