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] - Diff between revs 1765 and 1782

Only display areas with differences | Details | Blame | View Log

Rev 1765 Rev 1782
/*
/*
 * linux/kernel/ldt.c
 * linux/kernel/ldt.c
 *
 *
 * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
 * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
 */
 */
 
 
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <asm/segment.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/system.h>
#include <linux/ldt.h>
#include <linux/ldt.h>
#include <asm/ptrace.h>
#include <asm/ptrace.h>
 
 
static int read_ldt(void * ptr, unsigned long bytecount)
static int read_ldt(void * ptr, unsigned long bytecount)
{
{
        int error;
        int error;
        void * address = current->ldt;
        void * address = current->ldt;
        unsigned long size;
        unsigned long size;
 
 
        if (!ptr)
        if (!ptr)
                return -EINVAL;
                return -EINVAL;
        size = LDT_ENTRIES*LDT_ENTRY_SIZE;
        size = LDT_ENTRIES*LDT_ENTRY_SIZE;
        if (!address) {
        if (!address) {
                address = &default_ldt;
                address = &default_ldt;
                size = sizeof(default_ldt);
                size = sizeof(default_ldt);
        }
        }
        if (size > bytecount)
        if (size > bytecount)
                size = bytecount;
                size = bytecount;
        error = verify_area(VERIFY_WRITE, ptr, size);
        error = verify_area(VERIFY_WRITE, ptr, size);
        if (error)
        if (error)
                return error;
                return error;
        memcpy_tofs(ptr, address, size);
        memcpy_tofs(ptr, address, size);
        return size;
        return size;
}
}
 
 
static inline int limits_ok(struct modify_ldt_ldt_s *ldt_info)
static inline int limits_ok(struct modify_ldt_ldt_s *ldt_info)
{
{
        unsigned long base, limit;
        unsigned long base, limit;
        /* linear address of first and last accessible byte */
        /* linear address of first and last accessible byte */
        unsigned long first, last;
        unsigned long first, last;
 
 
        base = ldt_info->base_addr;
        base = ldt_info->base_addr;
        limit = ldt_info->limit;
        limit = ldt_info->limit;
        if (ldt_info->limit_in_pages)
        if (ldt_info->limit_in_pages)
                limit = limit * PAGE_SIZE + PAGE_SIZE - 1;
                limit = limit * PAGE_SIZE + PAGE_SIZE - 1;
 
 
        first = base;
        first = base;
        last = limit + base;
        last = limit + base;
 
 
        /* segment grows down? */
        /* segment grows down? */
        if (ldt_info->contents == 1) {
        if (ldt_info->contents == 1) {
                /* data segment grows down */
                /* data segment grows down */
                first = base+limit+1;
                first = base+limit+1;
                last = base+65535;
                last = base+65535;
                if (ldt_info->seg_32bit)
                if (ldt_info->seg_32bit)
                        last = base-1;
                        last = base-1;
        }
        }
        return (last >= first && last < TASK_SIZE);
        return (last >= first && last < TASK_SIZE);
}
}
 
 
static int write_ldt(struct pt_regs * regs, void * ptr, unsigned long bytecount, int oldmode)
static int write_ldt(struct pt_regs * regs, void * ptr, unsigned long bytecount, int oldmode)
{
{
        struct modify_ldt_ldt_s ldt_info;
        struct modify_ldt_ldt_s ldt_info;
        unsigned long *lp;
        unsigned long *lp;
        int error, i;
        int error, i;
 
 
        if (bytecount != sizeof(ldt_info))
        if (bytecount != sizeof(ldt_info))
                return -EINVAL;
                return -EINVAL;
        error = verify_area(VERIFY_READ, ptr, sizeof(ldt_info));
        error = verify_area(VERIFY_READ, ptr, sizeof(ldt_info));
        if (error)
        if (error)
                return error;
                return error;
 
 
        memcpy_fromfs(&ldt_info, ptr, sizeof(ldt_info));
        memcpy_fromfs(&ldt_info, ptr, sizeof(ldt_info));
 
 
        if ((ldt_info.contents == 3 && (oldmode || ldt_info.seg_not_present == 0)) || ldt_info.entry_number >= LDT_ENTRIES)
        if ((ldt_info.contents == 3 && (oldmode || ldt_info.seg_not_present == 0)) || ldt_info.entry_number >= LDT_ENTRIES)
                return -EINVAL;
                return -EINVAL;
 
 
        if (!limits_ok(&ldt_info) && (oldmode || ldt_info.seg_not_present == 0))
        if (!limits_ok(&ldt_info) && (oldmode || ldt_info.seg_not_present == 0))
                return -EINVAL;
                return -EINVAL;
 
 
        if (!current->ldt) {
        if (!current->ldt) {
                for (i=1 ; i<NR_TASKS ; i++) {
                for (i=1 ; i<NR_TASKS ; i++) {
                        if (task[i] == current) {
                        if (task[i] == current) {
                                if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
                                if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
                                        return -ENOMEM;
                                        return -ENOMEM;
                                memset(current->ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
                                memset(current->ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
                                set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
                                set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
                                load_ldt(i);
                                load_ldt(i);
                        }
                        }
                }
                }
        }
        }
 
 
        lp = (unsigned long *) &current->ldt[ldt_info.entry_number];
        lp = (unsigned long *) &current->ldt[ldt_info.entry_number];
        /* Allow LDTs to be cleared by the user. */
        /* Allow LDTs to be cleared by the user. */
        if (ldt_info.base_addr == 0 && ldt_info.limit == 0
        if (ldt_info.base_addr == 0 && ldt_info.limit == 0
                && (oldmode ||
                && (oldmode ||
                        (  ldt_info.contents == 0
                        (  ldt_info.contents == 0
                        && ldt_info.read_exec_only == 1
                        && ldt_info.read_exec_only == 1
                        && ldt_info.seg_32bit == 0
                        && ldt_info.seg_32bit == 0
                        && ldt_info.limit_in_pages == 0
                        && ldt_info.limit_in_pages == 0
                        && ldt_info.seg_not_present == 1
                        && ldt_info.seg_not_present == 1
                        && ldt_info.useable == 0 )) ) {
                        && ldt_info.useable == 0 )) ) {
                unsigned short sel =(ldt_info.entry_number <<3) | 7;
                unsigned short sel =(ldt_info.entry_number <<3) | 7;
                if (regs->fs == sel  || regs->gs == sel)
                if (regs->fs == sel  || regs->gs == sel)
                        return -EBUSY;
                        return -EBUSY;
                *lp = 0;
                *lp = 0;
                *(lp+1) = 0;
                *(lp+1) = 0;
                return 0;
                return 0;
        }
        }
        *lp = ((ldt_info.base_addr & 0x0000ffff) << 16) |
        *lp = ((ldt_info.base_addr & 0x0000ffff) << 16) |
                  (ldt_info.limit & 0x0ffff);
                  (ldt_info.limit & 0x0ffff);
        *(lp+1) = (ldt_info.base_addr & 0xff000000) |
        *(lp+1) = (ldt_info.base_addr & 0xff000000) |
                  ((ldt_info.base_addr & 0x00ff0000)>>16) |
                  ((ldt_info.base_addr & 0x00ff0000)>>16) |
                  (ldt_info.limit & 0xf0000) |
                  (ldt_info.limit & 0xf0000) |
                  (ldt_info.contents << 10) |
                  (ldt_info.contents << 10) |
                  ((ldt_info.read_exec_only ^ 1) << 9) |
                  ((ldt_info.read_exec_only ^ 1) << 9) |
                  (ldt_info.seg_32bit << 22) |
                  (ldt_info.seg_32bit << 22) |
                  (ldt_info.limit_in_pages << 23) |
                  (ldt_info.limit_in_pages << 23) |
                  ((ldt_info.seg_not_present ^1) << 15) |
                  ((ldt_info.seg_not_present ^1) << 15) |
                  0x7000;
                  0x7000;
        if (!oldmode) *(lp+1) |= (ldt_info.useable << 20);
        if (!oldmode) *(lp+1) |= (ldt_info.useable << 20);
        return 0;
        return 0;
}
}
 
 
asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
{
{
        if (func == 0)
        if (func == 0)
                return read_ldt(ptr, bytecount);
                return read_ldt(ptr, bytecount);
        if (func == 1)
        if (func == 1)
                return write_ldt((struct pt_regs *) &func, ptr, bytecount, 1);
                return write_ldt((struct pt_regs *) &func, ptr, bytecount, 1);
        if (func == 0x11)
        if (func == 0x11)
                return write_ldt((struct pt_regs *) &func, ptr, bytecount, 0);
                return write_ldt((struct pt_regs *) &func, ptr, bytecount, 0);
        return -ENOSYS;
        return -ENOSYS;
}
}
 
 

powered by: WebSVN 2.1.0

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