summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel/osf_sys.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/alpha/kernel/osf_sys.c')
-rw-r--r--arch/alpha/kernel/osf_sys.c73
1 files changed, 54 insertions, 19 deletions
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 67c08778d..38bd43947 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -37,6 +37,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/sysinfo.h>
+#include <asm/hwrpb.h>
extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
extern int do_pipe(int *);
@@ -140,6 +141,7 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent,
struct inode *inode;
struct osf_dirent_callback buf;
+ lock_kernel();
error = -EBADF;
file = fget(fd);
if (!file)
@@ -172,6 +174,7 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent,
out_putf:
fput(file);
out:
+ unlock_kernel();
return error;
}
@@ -317,8 +320,8 @@ static int do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer, unsi
struct super_block * sb = inode->i_sb;
int error;
- error = -ENOSYS;
- if (sb->s_op->statfs) {
+ error = -ENODEV;
+ if (sb && sb->s_op && sb->s_op->statfs) {
set_fs(KERNEL_DS);
error = sb->s_op->statfs(sb, &linux_stat, sizeof(linux_stat));
set_fs(USER_DS);
@@ -762,14 +765,10 @@ asmlinkage long osf_proplist_syscall(enum pl_code code, union pl_args *args)
asmlinkage int osf_sigstack(struct sigstack *uss, struct sigstack *uoss)
{
unsigned long usp = rdusp();
- unsigned long oss_sp, oss_os;
+ unsigned long oss_sp = current->sas_ss_sp + current->sas_ss_size;
+ unsigned long oss_os = on_sig_stack(usp);
int error;
- if (uoss) {
- oss_sp = current->sas_ss_sp + current->sas_ss_size;
- oss_os = on_sig_stack(usp);
- }
-
if (uss) {
void *ss_sp;
@@ -880,11 +879,27 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
int *start, void *arg)
{
unsigned long w;
+ struct percpu_struct *cpu;
switch (op) {
case GSI_IEEE_FP_CONTROL:
/* Return current software fp control & status bits. */
- w = current->tss.flags & IEEE_SW_MASK;
+ /* Note that DU doesn't verify available space here. */
+
+ /* EV6 implements most of the bits in hardware. If
+ UNDZ is not set, UNFD is maintained in software. */
+ if (implver() == IMPLVER_EV6) {
+ unsigned long fpcr = rdfpcr();
+ w = ieee_fpcr_to_swcr(fpcr);
+ if (!(fpcr & FPCR_UNDZ)) {
+ w &= ~IEEE_TRAP_ENABLE_UNF;
+ w |= current->tss.flags & IEEE_TRAP_ENABLE_UNF;
+ }
+ } else {
+ /* Otherwise we are forced to do everything in sw. */
+ w = current->tss.flags & IEEE_SW_MASK;
+ }
+
if (put_user(w, (unsigned long *) buffer))
return -EFAULT;
return 0;
@@ -898,10 +913,28 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
break;
case GSI_UACPROC:
+ if (nbytes < sizeof(unsigned int))
+ return -EINVAL;
w = (current->tss.flags >> UAC_SHIFT) & UAC_BITMASK;
if (put_user(w, (unsigned int *)buffer))
return -EFAULT;
- return 0;
+ return 1;
+
+ case GSI_PROC_TYPE:
+ if (nbytes < sizeof(unsigned long))
+ return -EINVAL;
+ cpu = (struct percpu_struct*)
+ ((char*)hwrpb + hwrpb->processor_offset);
+ if (put_user(w, (unsigned long *)buffer))
+ return -EFAULT;
+ return 1;
+
+ case GSI_GET_HWRPB:
+ if (nbytes < sizeof(*hwrpb))
+ return -EINVAL;
+ if (copy_to_user(buffer, hwrpb, nbytes) != 0)
+ return -EFAULT;
+ return 1;
default:
break;
@@ -916,7 +949,7 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
{
switch (op) {
case SSI_IEEE_FP_CONTROL: {
- unsigned long swcr, fpcr;
+ unsigned long swcr, fpcr, undz;
/*
* Alpha Architecture Handbook 4.7.7.3:
@@ -931,11 +964,12 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
current->tss.flags &= ~IEEE_SW_MASK;
current->tss.flags |= swcr & IEEE_SW_MASK;
- /* Update the real fpcr. For exceptions that are disabled in
- software but have not been seen, enable the exception in
- hardware so that we can update our software status mask. */
- fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK);
- fpcr |= ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
+ /* Update the real fpcr. Keep UNFD off if not UNDZ. */
+ fpcr = rdfpcr();
+ undz = (fpcr & FPCR_UNDZ);
+ fpcr &= ~(FPCR_MASK | FPCR_DYN_MASK | FPCR_UNDZ);
+ fpcr |= ieee_swcr_to_fpcr(swcr);
+ fpcr &= ~(undz << 1);
wrfpcr(fpcr);
return 0;
@@ -1390,8 +1424,9 @@ asmlinkage int sys_old_adjtimex(struct timex32 *txc_p)
copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) -
offsetof(struct timex32, time)))
return -EFAULT;
-
- if ((ret = do_adjtimex(&txc)))
+
+ ret = do_adjtimex(&txc);
+ if (ret < 0)
return ret;
/* copy back to timex32 */
@@ -1401,5 +1436,5 @@ asmlinkage int sys_old_adjtimex(struct timex32 *txc_p)
(put_tv32(&txc_p->time, &txc.time)))
return -EFAULT;
- return 0;
+ return ret;
}