Files
oldlinux-website/Book-Lite/linux-0.12/kernel/math/get_put.c
2024-02-19 01:11:57 -05:00

241 lines
5.0 KiB
C

/*
* linux/kernel/math/get_put.c
*
* (C) 1991 Linus Torvalds
*/
/*
* This file handles all accesses to user memory: getting and putting
* ints/reals/BCD etc. This is the only part that concerns itself with
* other than temporary real format. All other cals are strictly temp_real.
*/
#include <signal.h>
#include <linux/math_emu.h>
#include <linux/kernel.h>
#include <asm/segment.h>
void get_short_real(temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
short_real sr;
addr = ea(info,code);
sr = get_fs_long((unsigned long *) addr);
short_to_temp(&sr,tmp);
}
void get_long_real(temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
long_real lr;
addr = ea(info,code);
lr.a = get_fs_long((unsigned long *) addr);
lr.b = get_fs_long(1 + (unsigned long *) addr);
long_to_temp(&lr,tmp);
}
void get_temp_real(temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
addr = ea(info,code);
tmp->a = get_fs_long((unsigned long *) addr);
tmp->b = get_fs_long(1 + (unsigned long *) addr);
tmp->exponent = get_fs_word(4 + (unsigned short *) addr);
}
void get_short_int(temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
temp_int ti;
addr = ea(info,code);
ti.a = (signed short) get_fs_word((unsigned short *) addr);
ti.b = 0;
if (ti.sign = (ti.a < 0))
ti.a = - ti.a;
int_to_real(&ti,tmp);
}
void get_long_int(temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
temp_int ti;
addr = ea(info,code);
ti.a = get_fs_long((unsigned long *) addr);
ti.b = 0;
if (ti.sign = (ti.a < 0))
ti.a = - ti.a;
int_to_real(&ti,tmp);
}
void get_longlong_int(temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
temp_int ti;
addr = ea(info,code);
ti.a = get_fs_long((unsigned long *) addr);
ti.b = get_fs_long(1 + (unsigned long *) addr);
if (ti.sign = (ti.b < 0))
__asm__("notl %0 ; notl %1\n\t"
"addl $1,%0 ; adcl $0,%1"
:"=r" (ti.a),"=r" (ti.b)
:"0" (ti.a),"1" (ti.b));
int_to_real(&ti,tmp);
}
#define MUL10(low,high) \
__asm__("addl %0,%0 ; adcl %1,%1\n\t" \
"movl %0,%%ecx ; movl %1,%%ebx\n\t" \
"addl %0,%0 ; adcl %1,%1\n\t" \
"addl %0,%0 ; adcl %1,%1\n\t" \
"addl %%ecx,%0 ; adcl %%ebx,%1" \
:"=a" (low),"=d" (high) \
:"0" (low),"1" (high):"cx","bx")
#define ADD64(val,low,high) \
__asm__("addl %4,%0 ; adcl $0,%1":"=r" (low),"=r" (high) \
:"0" (low),"1" (high),"r" ((unsigned long) (val)))
void get_BCD(temp_real * tmp, struct info * info, unsigned short code)
{
int k;
char * addr;
temp_int i;
unsigned char c;
addr = ea(info,code);
addr += 9;
i.sign = 0x80 & get_fs_byte(addr--);
i.a = i.b = 0;
for (k = 0; k < 9; k++) {
c = get_fs_byte(addr--);
MUL10(i.a, i.b);
ADD64((c>>4), i.a, i.b);
MUL10(i.a, i.b);
ADD64((c&0xf), i.a, i.b);
}
int_to_real(&i,tmp);
}
void put_short_real(const temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
short_real sr;
addr = ea(info,code);
verify_area(addr,4);
temp_to_short(tmp,&sr);
put_fs_long(sr,(unsigned long *) addr);
}
void put_long_real(const temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
long_real lr;
addr = ea(info,code);
verify_area(addr,8);
temp_to_long(tmp,&lr);
put_fs_long(lr.a, (unsigned long *) addr);
put_fs_long(lr.b, 1 + (unsigned long *) addr);
}
void put_temp_real(const temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
addr = ea(info,code);
verify_area(addr,10);
put_fs_long(tmp->a, (unsigned long *) addr);
put_fs_long(tmp->b, 1 + (unsigned long *) addr);
put_fs_word(tmp->exponent, 4 + (short *) addr);
}
void put_short_int(const temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
temp_int ti;
addr = ea(info,code);
real_to_int(tmp,&ti);
verify_area(addr,2);
if (ti.sign)
ti.a = -ti.a;
put_fs_word(ti.a,(short *) addr);
}
void put_long_int(const temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
temp_int ti;
addr = ea(info,code);
real_to_int(tmp,&ti);
verify_area(addr,4);
if (ti.sign)
ti.a = -ti.a;
put_fs_long(ti.a,(unsigned long *) addr);
}
void put_longlong_int(const temp_real * tmp,
struct info * info, unsigned short code)
{
char * addr;
temp_int ti;
addr = ea(info,code);
real_to_int(tmp,&ti);
verify_area(addr,8);
if (ti.sign)
__asm__("notl %0 ; notl %1\n\t"
"addl $1,%0 ; adcl $0,%1"
:"=r" (ti.a),"=r" (ti.b)
:"0" (ti.a),"1" (ti.b));
put_fs_long(ti.a,(unsigned long *) addr);
put_fs_long(ti.b,1 + (unsigned long *) addr);
}
#define DIV10(low,high,rem) \
__asm__("divl %6 ; xchgl %1,%2 ; divl %6" \
:"=d" (rem),"=a" (low),"=b" (high) \
:"0" (0),"1" (high),"2" (low),"c" (10))
void put_BCD(const temp_real * tmp,struct info * info, unsigned short code)
{
int k,rem;
char * addr;
temp_int i;
unsigned char c;
addr = ea(info,code);
verify_area(addr,10);
real_to_int(tmp,&i);
if (i.sign)
put_fs_byte(0x80, addr+9);
else
put_fs_byte(0, addr+9);
for (k = 0; k < 9; k++) {
DIV10(i.a,i.b,rem);
c = rem;
DIV10(i.a,i.b,rem);
c += rem<<4;
put_fs_byte(c,addr++);
}
}