sys_ppc32.c 24.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/*
 * sys_ppc32.c: Conversion between 32bit and 64bit native syscalls.
 *
 * Copyright (C) 2001 IBM
 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
 *
 * These routines maintain argument size conversion between 32bit and 64bit
 * environment.
 *
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 */

#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h> 
#include <linux/mm.h> 
#include <linux/file.h> 
#include <linux/signal.h>
#include <linux/resource.h>
#include <linux/times.h>
#include <linux/utsname.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/poll.h>
#include <linux/personality.h>
#include <linux/stat.h>
#include <linux/mman.h>
#include <linux/in.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
#include <linux/sysctl.h>
#include <linux/binfmts.h>
#include <linux/security.h>
#include <linux/compat.h>
#include <linux/ptrace.h>
#include <linux/elf.h>

#include <asm/ptrace.h>
#include <asm/types.h>
#include <asm/ipc.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/semaphore.h>
#include <asm/time.h>
#include <asm/mmu_context.h>
53
#include <asm/ppc-pci.h>
54
#include <asm/syscalls.h>
L
Linus Torvalds 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67 68

struct old_linux_dirent32 {
	u32		d_ino;
	u32		d_offset;
	unsigned short	d_namlen;
	char		d_name[1];
};

struct readdir_callback32 {
	struct old_linux_dirent32 __user * dirent;
	int count;
};

static int fillonedir(void * __buf, const char * name, int namlen,
69
		                  off_t offset, u64 ino, unsigned int d_type)
L
Linus Torvalds 已提交
70 71 72
{
	struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
	struct old_linux_dirent32 __user * dirent;
73
	ino_t d_ino;
L
Linus Torvalds 已提交
74 75 76

	if (buf->count)
		return -EINVAL;
77 78 79
	d_ino = ino;
	if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
		return -EOVERFLOW;
L
Linus Torvalds 已提交
80 81
	buf->count++;
	dirent = buf->dirent;
82
	put_user(d_ino, &dirent->d_ino);
L
Linus Torvalds 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
	put_user(offset, &dirent->d_offset);
	put_user(namlen, &dirent->d_namlen);
	copy_to_user(dirent->d_name, name, namlen);
	put_user(0, dirent->d_name + namlen);
	return 0;
}

asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 __user *dirent, unsigned int count)
{
	int error = -EBADF;
	struct file * file;
	struct readdir_callback32 buf;

	file = fget(fd);
	if (!file)
		goto out;

	buf.count = 0;
	buf.dirent = dirent;

	error = vfs_readdir(file, (filldir_t)fillonedir, &buf);
	if (error < 0)
		goto out_putf;
	error = buf.count;

out_putf:
	fput(file);
out:
	return error;
}

asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,
		compat_ulong_t __user *outp, compat_ulong_t __user *exp,
		compat_uptr_t tvp_x)
{
	/* sign extend n */
	return compat_sys_select((int)n, inp, outp, exp, compat_ptr(tvp_x));
}

int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
{
124
	compat_ino_t ino;
L
Linus Torvalds 已提交
125 126 127 128 129 130
	long err;

	if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
	    !new_valid_dev(stat->rdev))
		return -EOVERFLOW;

131 132 133 134
	ino = stat->ino;
	if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
		return -EOVERFLOW;

L
Linus Torvalds 已提交
135 136
	err  = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT;
	err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
137
	err |= __put_user(ino, &statbuf->st_ino);
L
Linus Torvalds 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
	err |= __put_user(stat->mode, &statbuf->st_mode);
	err |= __put_user(stat->nlink, &statbuf->st_nlink);
	err |= __put_user(stat->uid, &statbuf->st_uid);
	err |= __put_user(stat->gid, &statbuf->st_gid);
	err |= __put_user(new_encode_dev(stat->rdev), &statbuf->st_rdev);
	err |= __put_user(stat->size, &statbuf->st_size);
	err |= __put_user(stat->atime.tv_sec, &statbuf->st_atime);
	err |= __put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
	err |= __put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
	err |= __put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
	err |= __put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
	err |= __put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
	err |= __put_user(stat->blksize, &statbuf->st_blksize);
	err |= __put_user(stat->blocks, &statbuf->st_blocks);
	err |= __put_user(0, &statbuf->__unused4[0]);
	err |= __put_user(0, &statbuf->__unused4[1]);

	return err;
}

/* Note: it is necessary to treat option as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
163
asmlinkage long compat_sys_sysfs(u32 option, u32 arg1, u32 arg2)
L
Linus Torvalds 已提交
164 165 166 167
{
	return sys_sysfs((int)option, arg1, arg2);
}

168
asmlinkage long compat_sys_pause(void)
L
Linus Torvalds 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
{
	current->state = TASK_INTERRUPTIBLE;
	schedule();
	
	return -ERESTARTNOHAND;
}

static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
{
	long usec;

	if (!access_ok(VERIFY_READ, i, sizeof(*i)))
		return -EFAULT;
	if (__get_user(o->tv_sec, &i->tv_sec))
		return -EFAULT;
	if (__get_user(usec, &i->tv_usec))
		return -EFAULT;
	o->tv_nsec = usec * 1000;
	return 0;
}

static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
{
	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
		(__put_user(i->tv_sec, &o->tv_sec) |
		 __put_user(i->tv_usec, &o->tv_usec)));
}




/* Translations due to time_t size differences.  Which affects all
   sorts of things, like timeval and itimerval.  */
extern struct timezone sys_tz;

204
asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
L
Linus Torvalds 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
{
	if (tv) {
		struct timeval ktv;
		do_gettimeofday(&ktv);
		if (put_tv32(tv, &ktv))
			return -EFAULT;
	}
	if (tz) {
		if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
			return -EFAULT;
	}
	
	return 0;
}



222
asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
L
Linus Torvalds 已提交
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
{
	struct timespec kts;
	struct timezone ktz;
	
 	if (tv) {
		if (get_ts32(&kts, tv))
			return -EFAULT;
	}
	if (tz) {
		if (copy_from_user(&ktz, tz, sizeof(ktz)))
			return -EFAULT;
	}

	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
}

#ifdef CONFIG_SYSVIPC
240
long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr,
L
Linus Torvalds 已提交
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	       u32 fifth)
{
	int version;

	version = call >> 16; /* hack for backward compatibility */
	call &= 0xffff;

	switch (call) {

	case SEMTIMEDOP:
		if (fifth)
			/* sign extend semid */
			return compat_sys_semtimedop((int)first,
						     compat_ptr(ptr), second,
						     compat_ptr(fifth));
		/* else fall through for normal semop() */
	case SEMOP:
		/* struct sembuf is the same on 32 and 64bit :)) */
		/* sign extend semid */
		return sys_semtimedop((int)first, compat_ptr(ptr), second,
				      NULL);
	case SEMGET:
		/* sign extend key, nsems */
		return sys_semget((int)first, (int)second, third);
	case SEMCTL:
		/* sign extend semid, semnum */
		return compat_sys_semctl((int)first, (int)second, third,
					 compat_ptr(ptr));

	case MSGSND:
		/* sign extend msqid */
		return compat_sys_msgsnd((int)first, (int)second, third,
					 compat_ptr(ptr));
	case MSGRCV:
		/* sign extend msqid, msgtyp */
		return compat_sys_msgrcv((int)first, second, (int)fifth,
					 third, version, compat_ptr(ptr));
	case MSGGET:
		/* sign extend key */
		return sys_msgget((int)first, second);
	case MSGCTL:
		/* sign extend msqid */
		return compat_sys_msgctl((int)first, second, compat_ptr(ptr));

	case SHMAT:
		/* sign extend shmid */
		return compat_sys_shmat((int)first, second, third, version,
					compat_ptr(ptr));
	case SHMDT:
		return sys_shmdt(compat_ptr(ptr));
	case SHMGET:
		/* sign extend key_t */
		return sys_shmget((int)first, second, third);
	case SHMCTL:
		/* sign extend shmid */
		return compat_sys_shmctl((int)first, second, compat_ptr(ptr));

	default:
		return -ENOSYS;
	}

	return -ENOSYS;
}
#endif

/* Note: it is necessary to treat out_fd and in_fd as unsigned ints, 
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
311
asmlinkage long compat_sys_sendfile(u32 out_fd, u32 in_fd, compat_off_t __user * offset, u32 count)
L
Linus Torvalds 已提交
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
{
	mm_segment_t old_fs = get_fs();
	int ret;
	off_t of;
	off_t __user *up;

	if (offset && get_user(of, offset))
		return -EFAULT;

	/* The __user pointer cast is valid because of the set_fs() */		
	set_fs(KERNEL_DS);
	up = offset ? (off_t __user *) &of : NULL;
	ret = sys_sendfile((int)out_fd, (int)in_fd, up, count);
	set_fs(old_fs);
	
	if (offset && put_user(of, offset))
		return -EFAULT;
		
	return ret;
}

333
asmlinkage int compat_sys_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count)
L
Linus Torvalds 已提交
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
{
	mm_segment_t old_fs = get_fs();
	int ret;
	loff_t lof;
	loff_t __user *up;
	
	if (offset && get_user(lof, offset))
		return -EFAULT;
		
	/* The __user pointer cast is valid because of the set_fs() */		
	set_fs(KERNEL_DS);
	up = offset ? (loff_t __user *) &lof : NULL;
	ret = sys_sendfile64(out_fd, in_fd, up, count);
	set_fs(old_fs);
	
	if (offset && put_user(lof, offset))
		return -EFAULT;
		
	return ret;
}

355
long compat_sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
L
Linus Torvalds 已提交
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
		  unsigned long a3, unsigned long a4, unsigned long a5,
		  struct pt_regs *regs)
{
	int error;
	char * filename;
	
	filename = getname((char __user *) a0);
	error = PTR_ERR(filename);
	if (IS_ERR(filename))
		goto out;
	flush_fp_to_thread(current);
	flush_altivec_to_thread(current);

	error = compat_do_execve(filename, compat_ptr(a1), compat_ptr(a2), regs);

	if (error == 0) {
		task_lock(current);
		current->ptrace &= ~PT_DTRACE;
		task_unlock(current);
	}
	putname(filename);

out:
	return error;
}

/* Note: it is necessary to treat option as an unsigned int, 
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
387
asmlinkage long compat_sys_prctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5)
L
Linus Torvalds 已提交
388 389 390 391 392 393 394 395 396 397 398 399 400
{
	return sys_prctl((int)option,
			 (unsigned long) arg2,
			 (unsigned long) arg3,
			 (unsigned long) arg4,
			 (unsigned long) arg5);
}

/* Note: it is necessary to treat pid as an unsigned int, 
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
401
asmlinkage long compat_sys_sched_rr_get_interval(u32 pid, struct compat_timespec __user *interval)
L
Linus Torvalds 已提交
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
{
	struct timespec t;
	int ret;
	mm_segment_t old_fs = get_fs ();

	/* The __user pointer cast is valid because of the set_fs() */
	set_fs (KERNEL_DS);
	ret = sys_sched_rr_get_interval((int)pid, (struct timespec __user *) &t);
	set_fs (old_fs);
	if (put_compat_timespec(&t, interval))
		return -EFAULT;
	return ret;
}

/* Note: it is necessary to treat mode as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
421
asmlinkage long compat_sys_access(const char __user * filename, u32 mode)
L
Linus Torvalds 已提交
422 423 424 425 426 427 428 429 430 431
{
	return sys_access(filename, (int)mode);
}


/* Note: it is necessary to treat mode as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
432
asmlinkage long compat_sys_creat(const char __user * pathname, u32 mode)
L
Linus Torvalds 已提交
433 434 435 436 437 438 439 440 441 442
{
	return sys_creat(pathname, (int)mode);
}


/* Note: it is necessary to treat pid and options as unsigned ints,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
443
asmlinkage long compat_sys_waitpid(u32 pid, unsigned int __user * stat_addr, u32 options)
L
Linus Torvalds 已提交
444 445 446 447 448 449 450 451 452 453
{
	return sys_waitpid((int)pid, stat_addr, (int)options);
}


/* Note: it is necessary to treat gidsetsize as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
454
asmlinkage long compat_sys_getgroups(u32 gidsetsize, gid_t __user *grouplist)
L
Linus Torvalds 已提交
455 456 457 458 459 460 461 462 463 464
{
	return sys_getgroups((int)gidsetsize, grouplist);
}


/* Note: it is necessary to treat pid as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
465
asmlinkage long compat_sys_getpgid(u32 pid)
L
Linus Torvalds 已提交
466 467 468 469 470 471 472 473 474 475 476
{
	return sys_getpgid((int)pid);
}



/* Note: it is necessary to treat pid as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
477
asmlinkage long compat_sys_getsid(u32 pid)
L
Linus Torvalds 已提交
478 479 480 481 482 483 484 485 486 487
{
	return sys_getsid((int)pid);
}


/* Note: it is necessary to treat pid and sig as unsigned ints,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
488
asmlinkage long compat_sys_kill(u32 pid, u32 sig)
L
Linus Torvalds 已提交
489 490 491 492 493 494 495 496 497 498
{
	return sys_kill((int)pid, (int)sig);
}


/* Note: it is necessary to treat mode as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
499
asmlinkage long compat_sys_mkdir(const char __user * pathname, u32 mode)
L
Linus Torvalds 已提交
500 501 502 503
{
	return sys_mkdir(pathname, (int)mode);
}

504
long compat_sys_nice(u32 increment)
L
Linus Torvalds 已提交
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
{
	/* sign extend increment */
	return sys_nice((int)increment);
}

off_t ppc32_lseek(unsigned int fd, u32 offset, unsigned int origin)
{
	/* sign extend n */
	return sys_lseek(fd, (int)offset, origin);
}

/* Note: it is necessary to treat bufsiz as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
521
asmlinkage long compat_sys_readlink(const char __user * path, char __user * buf, u32 bufsiz)
L
Linus Torvalds 已提交
522 523 524 525 526 527 528 529 530
{
	return sys_readlink(path, buf, (int)bufsiz);
}

/* Note: it is necessary to treat option as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
531
asmlinkage long compat_sys_sched_get_priority_max(u32 policy)
L
Linus Torvalds 已提交
532 533 534 535 536 537 538 539 540 541
{
	return sys_sched_get_priority_max((int)policy);
}


/* Note: it is necessary to treat policy as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
542
asmlinkage long compat_sys_sched_get_priority_min(u32 policy)
L
Linus Torvalds 已提交
543 544 545 546 547 548 549 550 551 552
{
	return sys_sched_get_priority_min((int)policy);
}


/* Note: it is necessary to treat pid as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
553
asmlinkage long compat_sys_sched_getparam(u32 pid, struct sched_param __user *param)
L
Linus Torvalds 已提交
554 555 556 557 558 559 560 561 562 563
{
	return sys_sched_getparam((int)pid, param);
}


/* Note: it is necessary to treat pid as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
564
asmlinkage long compat_sys_sched_getscheduler(u32 pid)
L
Linus Torvalds 已提交
565 566 567 568 569 570 571 572 573 574
{
	return sys_sched_getscheduler((int)pid);
}


/* Note: it is necessary to treat pid as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
575
asmlinkage long compat_sys_sched_setparam(u32 pid, struct sched_param __user *param)
L
Linus Torvalds 已提交
576 577 578 579 580 581 582 583 584 585
{
	return sys_sched_setparam((int)pid, param);
}


/* Note: it is necessary to treat pid and policy as unsigned ints,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
586
asmlinkage long compat_sys_sched_setscheduler(u32 pid, u32 policy, struct sched_param __user *param)
L
Linus Torvalds 已提交
587 588 589 590 591 592 593 594 595 596
{
	return sys_sched_setscheduler((int)pid, (int)policy, param);
}


/* Note: it is necessary to treat len as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
597
asmlinkage long compat_sys_setdomainname(char __user *name, u32 len)
L
Linus Torvalds 已提交
598 599 600 601 602 603 604 605 606 607
{
	return sys_setdomainname(name, (int)len);
}


/* Note: it is necessary to treat gidsetsize as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
608
asmlinkage long compat_sys_setgroups(u32 gidsetsize, gid_t __user *grouplist)
L
Linus Torvalds 已提交
609 610 611 612 613
{
	return sys_setgroups((int)gidsetsize, grouplist);
}


614
asmlinkage long compat_sys_sethostname(char __user *name, u32 len)
L
Linus Torvalds 已提交
615 616 617 618 619 620 621 622 623 624 625
{
	/* sign extend len */
	return sys_sethostname(name, (int)len);
}


/* Note: it is necessary to treat pid and pgid as unsigned ints,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
626
asmlinkage long compat_sys_setpgid(u32 pid, u32 pgid)
L
Linus Torvalds 已提交
627 628 629 630
{
	return sys_setpgid((int)pid, (int)pgid);
}

631
long compat_sys_getpriority(u32 which, u32 who)
632 633 634 635
{
	/* sign extend which and who */
	return sys_getpriority((int)which, (int)who);
}
L
Linus Torvalds 已提交
636

637
long compat_sys_setpriority(u32 which, u32 who, u32 niceval)
L
Linus Torvalds 已提交
638 639 640 641 642
{
	/* sign extend which, who and niceval */
	return sys_setpriority((int)which, (int)who, (int)niceval);
}

643
long compat_sys_ioprio_get(u32 which, u32 who)
644 645 646 647 648
{
	/* sign extend which and who */
	return sys_ioprio_get((int)which, (int)who);
}

649
long compat_sys_ioprio_set(u32 which, u32 who, u32 ioprio)
650 651 652 653 654
{
	/* sign extend which, who and ioprio */
	return sys_ioprio_set((int)which, (int)who, (int)ioprio);
}

L
Linus Torvalds 已提交
655 656 657 658 659
/* Note: it is necessary to treat newmask as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
660
asmlinkage long compat_sys_ssetmask(u32 newmask)
L
Linus Torvalds 已提交
661 662 663 664
{
	return sys_ssetmask((int) newmask);
}

665
asmlinkage long compat_sys_syslog(u32 type, char __user * buf, u32 len)
L
Linus Torvalds 已提交
666 667 668 669 670 671 672 673 674 675 676
{
	/* sign extend len */
	return sys_syslog(type, buf, (int)len);
}


/* Note: it is necessary to treat mask as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
677
asmlinkage long compat_sys_umask(u32 mask)
L
Linus Torvalds 已提交
678 679 680 681
{
	return sys_umask((int)mask);
}

682
#ifdef CONFIG_SYSCTL_SYSCALL
L
Linus Torvalds 已提交
683 684 685 686 687 688 689 690 691 692
struct __sysctl_args32 {
	u32 name;
	int nlen;
	u32 oldval;
	u32 oldlenp;
	u32 newval;
	u32 newlen;
	u32 __unused[4];
};

693
asmlinkage long compat_sys_sysctl(struct __sysctl_args32 __user *args)
L
Linus Torvalds 已提交
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
{
	struct __sysctl_args32 tmp;
	int error;
	size_t oldlen;
	size_t __user *oldlenp = NULL;
	unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7;

	if (copy_from_user(&tmp, args, sizeof(tmp)))
		return -EFAULT;

	if (tmp.oldval && tmp.oldlenp) {
		/* Duh, this is ugly and might not work if sysctl_args
		   is in read-only memory, but do_sysctl does indirectly
		   a lot of uaccess in both directions and we'd have to
		   basically copy the whole sysctl.c here, and
		   glibc's __sysctl uses rw memory for the structure
		   anyway.  */
		oldlenp = (size_t __user *)addr;
		if (get_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp)) ||
		    put_user(oldlen, oldlenp))
			return -EFAULT;
	}

	lock_kernel();
	error = do_sysctl(compat_ptr(tmp.name), tmp.nlen,
			  compat_ptr(tmp.oldval), oldlenp,
			  compat_ptr(tmp.newval), tmp.newlen);
	unlock_kernel();
	if (oldlenp) {
		if (!error) {
			if (get_user(oldlen, oldlenp) ||
			    put_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp)))
				error = -EFAULT;
		}
		copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
	}
	return error;
}
#endif

734
unsigned long compat_sys_mmap2(unsigned long addr, size_t len,
L
Linus Torvalds 已提交
735 736 737 738 739 740 741
			  unsigned long prot, unsigned long flags,
			  unsigned long fd, unsigned long pgoff)
{
	/* This should remain 12 even if PAGE_SIZE changes */
	return sys_mmap(addr, len, prot, flags, fd, pgoff << 12);
}

742
long compat_sys_tgkill(u32 tgid, u32 pid, int sig)
L
Linus Torvalds 已提交
743 744 745 746 747 748 749 750 751 752
{
	/* sign extend tgid, pid */
	return sys_tgkill((int)tgid, (int)pid, sig);
}

/* 
 * long long munging:
 * The 32 bit ABI passes long longs in an odd even register pair.
 */

753
compat_ssize_t compat_sys_pread64(unsigned int fd, char __user *ubuf, compat_size_t count,
L
Linus Torvalds 已提交
754 755 756 757 758
			     u32 reg6, u32 poshi, u32 poslo)
{
	return sys_pread64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo);
}

759
compat_ssize_t compat_sys_pwrite64(unsigned int fd, char __user *ubuf, compat_size_t count,
L
Linus Torvalds 已提交
760 761 762 763 764
			      u32 reg6, u32 poshi, u32 poslo)
{
	return sys_pwrite64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo);
}

765
compat_ssize_t compat_sys_readahead(int fd, u32 r4, u32 offhi, u32 offlo, u32 count)
L
Linus Torvalds 已提交
766 767 768 769
{
	return sys_readahead(fd, ((loff_t)offhi << 32) | offlo, count);
}

770
asmlinkage int compat_sys_truncate64(const char __user * path, u32 reg4,
L
Linus Torvalds 已提交
771 772 773 774 775
				unsigned long high, unsigned long low)
{
	return sys_truncate(path, (high << 32) | low);
}

776
asmlinkage int compat_sys_ftruncate64(unsigned int fd, u32 reg4, unsigned long high,
L
Linus Torvalds 已提交
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
				 unsigned long low)
{
	return sys_ftruncate(fd, (high << 32) | low);
}

long ppc32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf,
			  size_t len)
{
	return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
				  buf, len);
}

long ppc32_fadvise64(int fd, u32 unused, u32 offset_high, u32 offset_low,
		     size_t len, int advice)
{
	return sys_fadvise64(fd, (u64)offset_high << 32 | offset_low, len,
			     advice);
}

796
asmlinkage long compat_sys_add_key(const char __user *_type,
L
Linus Torvalds 已提交
797 798 799 800 801 802 803 804
			      const char __user *_description,
			      const void __user *_payload,
			      u32 plen,
			      u32 ringid)
{
	return sys_add_key(_type, _description, _payload, plen, ringid);
}

805
asmlinkage long compat_sys_request_key(const char __user *_type,
L
Linus Torvalds 已提交
806 807 808 809 810 811 812
				  const char __user *_description,
				  const char __user *_callout_info,
				  u32 destringid)
{
	return sys_request_key(_type, _description, _callout_info, destringid);
}