clang-format
This commit is contained in:
parent
53c617d779
commit
d66450e427
2
.clang-format
Normal file
2
.clang-format
Normal file
@ -0,0 +1,2 @@
|
||||
IncludeBlocks: Preserve
|
||||
SortIncludes: Never
|
@ -43,14 +43,12 @@
|
||||
* is less than either x or y (the choice to compare with x or y is
|
||||
* arbitrary).
|
||||
*/
|
||||
long long
|
||||
__adddi3(long long a, long long b)
|
||||
{
|
||||
union uu aa, bb, sum;
|
||||
long long __adddi3(long long a, long long b) {
|
||||
union uu aa, bb, sum;
|
||||
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
sum.ui[L] = aa.ui[L] + bb.ui[L];
|
||||
sum.ui[H] = aa.ui[H] + bb.ui[H] + (sum.ui[L] < bb.ui[L]);
|
||||
return (sum.ll);
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
sum.ui[L] = aa.ui[L] + bb.ui[L];
|
||||
sum.ui[H] = aa.ui[H] + bb.ui[H] + (sum.ui[L] < bb.ui[L]);
|
||||
return (sum.ll);
|
||||
}
|
||||
|
@ -40,14 +40,12 @@
|
||||
/*
|
||||
* Return a & b, in long long.
|
||||
*/
|
||||
long long
|
||||
__anddi3(long long a, long long b)
|
||||
{
|
||||
union uu aa, bb;
|
||||
long long __anddi3(long long a, long long b) {
|
||||
union uu aa, bb;
|
||||
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
aa.ui[0] &= bb.ui[0];
|
||||
aa.ui[1] &= bb.ui[1];
|
||||
return (aa.ll);
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
aa.ui[0] &= bb.ui[0];
|
||||
aa.ui[1] &= bb.ui[1];
|
||||
return (aa.ll);
|
||||
}
|
||||
|
@ -41,21 +41,18 @@
|
||||
* Shift a (signed) long long value left (arithmetic shift left).
|
||||
* This is the same as logical shift left!
|
||||
*/
|
||||
long long
|
||||
__ashldi3(long long a, unsigned int shift)
|
||||
{
|
||||
union uu aa;
|
||||
long long __ashldi3(long long a, unsigned int shift) {
|
||||
union uu aa;
|
||||
|
||||
if (shift == 0)
|
||||
return(a);
|
||||
aa.ll = a;
|
||||
if (shift >= INT_BITS) {
|
||||
aa.ui[H] = aa.ui[L] << (shift - INT_BITS);
|
||||
aa.ui[L] = 0;
|
||||
} else {
|
||||
aa.ui[H] = (aa.ui[H] << shift) |
|
||||
(aa.ui[L] >> (INT_BITS - shift));
|
||||
aa.ui[L] <<= shift;
|
||||
}
|
||||
return (aa.ll);
|
||||
if (shift == 0)
|
||||
return (a);
|
||||
aa.ll = a;
|
||||
if (shift >= INT_BITS) {
|
||||
aa.ui[H] = aa.ui[L] << (shift - INT_BITS);
|
||||
aa.ui[L] = 0;
|
||||
} else {
|
||||
aa.ui[H] = (aa.ui[H] << shift) | (aa.ui[L] >> (INT_BITS - shift));
|
||||
aa.ui[L] <<= shift;
|
||||
}
|
||||
return (aa.ll);
|
||||
}
|
||||
|
@ -40,34 +40,31 @@
|
||||
/*
|
||||
* Shift a (signed) long long value right (arithmetic shift right).
|
||||
*/
|
||||
long long
|
||||
__ashrdi3(long long a, unsigned int shift)
|
||||
{
|
||||
union uu aa;
|
||||
long long __ashrdi3(long long a, unsigned int shift) {
|
||||
union uu aa;
|
||||
|
||||
if (shift == 0)
|
||||
return(a);
|
||||
aa.ll = a;
|
||||
if (shift >= INT_BITS) {
|
||||
int s;
|
||||
if (shift == 0)
|
||||
return (a);
|
||||
aa.ll = a;
|
||||
if (shift >= INT_BITS) {
|
||||
int s;
|
||||
|
||||
/*
|
||||
* Smear bits rightward using the machine's right-shift
|
||||
* method, whether that is sign extension or zero fill,
|
||||
* to get the `sign word' s. Note that shifting by
|
||||
* INT_BITS is undefined, so we shift (INT_BITS-1),
|
||||
* then 1 more, to get our answer.
|
||||
*/
|
||||
/* LINTED inherits machine dependency */
|
||||
s = (aa.si[H] >> (INT_BITS - 1)) >> 1;
|
||||
/* LINTED inherits machine dependency*/
|
||||
aa.ui[L] = aa.si[H] >> (shift - INT_BITS);
|
||||
aa.ui[H] = s;
|
||||
} else {
|
||||
aa.ui[L] = (aa.ui[L] >> shift) |
|
||||
(aa.ui[H] << (INT_BITS - shift));
|
||||
/* LINTED inherits machine dependency */
|
||||
aa.si[H] >>= shift;
|
||||
}
|
||||
return (aa.ll);
|
||||
/*
|
||||
* Smear bits rightward using the machine's right-shift
|
||||
* method, whether that is sign extension or zero fill,
|
||||
* to get the `sign word' s. Note that shifting by
|
||||
* INT_BITS is undefined, so we shift (INT_BITS-1),
|
||||
* then 1 more, to get our answer.
|
||||
*/
|
||||
/* LINTED inherits machine dependency */
|
||||
s = (aa.si[H] >> (INT_BITS - 1)) >> 1;
|
||||
/* LINTED inherits machine dependency*/
|
||||
aa.ui[L] = aa.si[H] >> (shift - INT_BITS);
|
||||
aa.ui[H] = s;
|
||||
} else {
|
||||
aa.ui[L] = (aa.ui[L] >> shift) | (aa.ui[H] << (INT_BITS - shift));
|
||||
/* LINTED inherits machine dependency */
|
||||
aa.si[H] >>= shift;
|
||||
}
|
||||
return (aa.ll);
|
||||
}
|
||||
|
@ -42,13 +42,14 @@
|
||||
* Both a and b are considered signed---which means only the high word is
|
||||
* signed.
|
||||
*/
|
||||
int
|
||||
__cmpdi2(long long a, long long b)
|
||||
{
|
||||
union uu aa, bb;
|
||||
int __cmpdi2(long long a, long long b) {
|
||||
union uu aa, bb;
|
||||
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
return (aa.si[H] < bb.si[H] ? 0 : aa.si[H] > bb.si[H] ? 2 :
|
||||
aa.ui[L] < bb.ui[L] ? 0 : aa.ui[L] > bb.ui[L] ? 2 : 1);
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
return (aa.si[H] < bb.si[H] ? 0
|
||||
: aa.si[H] > bb.si[H] ? 2
|
||||
: aa.ui[L] < bb.ui[L] ? 0
|
||||
: aa.ui[L] > bb.ui[L] ? 2
|
||||
: 1);
|
||||
}
|
||||
|
@ -41,22 +41,20 @@
|
||||
* Divide two signed long longs.
|
||||
* ??? if -1/2 should produce -1 on this machine, this code is wrong
|
||||
*/
|
||||
long long
|
||||
__divdi3(long long a, long long b)
|
||||
{
|
||||
unsigned long long ua, ub, uq;
|
||||
int neg = 0;
|
||||
long long __divdi3(long long a, long long b) {
|
||||
unsigned long long ua, ub, uq;
|
||||
int neg = 0;
|
||||
|
||||
ua = a;
|
||||
ub = b;
|
||||
ua = a;
|
||||
ub = b;
|
||||
|
||||
if (a < 0)
|
||||
ua = -ua, neg ^= 1;
|
||||
if (b < 0)
|
||||
ub = -ub, neg ^= 1;
|
||||
if (a < 0)
|
||||
ua = -ua, neg ^= 1;
|
||||
if (b < 0)
|
||||
ub = -ub, neg ^= 1;
|
||||
|
||||
uq = __qdivrem(ua, ub, NULL);
|
||||
if (neg)
|
||||
uq = - uq;
|
||||
return uq;
|
||||
uq = __qdivrem(ua, ub, NULL);
|
||||
if (neg)
|
||||
uq = -uq;
|
||||
return uq;
|
||||
}
|
||||
|
@ -40,14 +40,12 @@
|
||||
/*
|
||||
* Return a | b, in long long.
|
||||
*/
|
||||
long long
|
||||
__iordi3(long long a, long long b)
|
||||
{
|
||||
union uu aa, bb;
|
||||
long long __iordi3(long long a, long long b) {
|
||||
union uu aa, bb;
|
||||
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
aa.ui[0] |= bb.ui[0];
|
||||
aa.ui[1] |= bb.ui[1];
|
||||
return (aa.ll);
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
aa.ui[0] |= bb.ui[0];
|
||||
aa.ui[1] |= bb.ui[1];
|
||||
return (aa.ll);
|
||||
}
|
||||
|
@ -68,10 +68,10 @@
|
||||
* one or more of the following formats.
|
||||
*/
|
||||
union uu {
|
||||
long long ll; /* as a (signed) long long */
|
||||
unsigned long long ull; /* as an unsigned long long */
|
||||
int si[2]; /* as two (signed) ints */
|
||||
unsigned int ui[2]; /* as two unsigned ints */
|
||||
long long ll; /* as a (signed) long long */
|
||||
unsigned long long ull; /* as an unsigned long long */
|
||||
int si[2]; /* as two (signed) ints */
|
||||
unsigned int ui[2]; /* as two unsigned ints */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -87,15 +87,14 @@ union uu {
|
||||
#define L 1
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Total number of bits in a long long and in the pieces that make it up.
|
||||
* These are used for shifting, and also below for halfword extraction
|
||||
* and assembly.
|
||||
*/
|
||||
#define LONGLONG_BITS (sizeof(long long) * CHAR_BIT)
|
||||
#define INT_BITS (sizeof(int) * CHAR_BIT)
|
||||
#define HALF_BITS (sizeof(int) * CHAR_BIT / 2)
|
||||
#define LONGLONG_BITS (sizeof(long long) * CHAR_BIT)
|
||||
#define INT_BITS (sizeof(int) * CHAR_BIT)
|
||||
#define HALF_BITS (sizeof(int) * CHAR_BIT / 2)
|
||||
|
||||
/*
|
||||
* Extract high and low shortwords from longword, and move low shortword of
|
||||
@ -107,38 +106,38 @@ union uu {
|
||||
* and lower halves, and to reassemble a product as a long long, shifted
|
||||
* left (sizeof(int)*CHAR_BIT/2).
|
||||
*/
|
||||
#define HHALF(x) ((unsigned int)(x) >> HALF_BITS)
|
||||
#define LHALF(x) ((unsigned int)(x) & (((int)1 << HALF_BITS) - 1))
|
||||
#define LHUP(x) ((unsigned int)(x) << HALF_BITS)
|
||||
#define HHALF(x) ((unsigned int)(x) >> HALF_BITS)
|
||||
#define LHALF(x) ((unsigned int)(x) & (((int)1 << HALF_BITS) - 1))
|
||||
#define LHUP(x) ((unsigned int)(x) << HALF_BITS)
|
||||
|
||||
long long __adddi3 ( long long, long long);
|
||||
long long __anddi3 ( long long, long long);
|
||||
long long __ashldi3 ( long long, unsigned int);
|
||||
long long __ashrdi3 ( long long, unsigned int);
|
||||
int __cmpdi2 ( long long, long long);
|
||||
long long __divdi3 ( long long, long long);
|
||||
long long __iordi3 ( long long, long long);
|
||||
long long __lshldi3 ( long long, unsigned int);
|
||||
long long __lshrdi3 ( long long, unsigned int);
|
||||
long long __moddi3 ( long long, long long);
|
||||
long long __muldi3 ( long long, long long);
|
||||
long long __negdi2 ( long long);
|
||||
long long __one_cmpldi2 ( long long);
|
||||
long long __subdi3 ( long long, long long);
|
||||
int __ucmpdi2 (unsigned long long, unsigned long long);
|
||||
unsigned long long __udivdi3 (unsigned long long, unsigned long long);
|
||||
unsigned long long __umoddi3 (unsigned long long, unsigned long long);
|
||||
long long __xordi3 ( long long, long long);
|
||||
long long __adddi3(long long, long long);
|
||||
long long __anddi3(long long, long long);
|
||||
long long __ashldi3(long long, unsigned int);
|
||||
long long __ashrdi3(long long, unsigned int);
|
||||
int __cmpdi2(long long, long long);
|
||||
long long __divdi3(long long, long long);
|
||||
long long __iordi3(long long, long long);
|
||||
long long __lshldi3(long long, unsigned int);
|
||||
long long __lshrdi3(long long, unsigned int);
|
||||
long long __moddi3(long long, long long);
|
||||
long long __muldi3(long long, long long);
|
||||
long long __negdi2(long long);
|
||||
long long __one_cmpldi2(long long);
|
||||
long long __subdi3(long long, long long);
|
||||
int __ucmpdi2(unsigned long long, unsigned long long);
|
||||
unsigned long long __udivdi3(unsigned long long, unsigned long long);
|
||||
unsigned long long __umoddi3(unsigned long long, unsigned long long);
|
||||
long long __xordi3(long long, long long);
|
||||
|
||||
#ifndef _KERNEL
|
||||
long long __fixdfdi (double);
|
||||
long long __fixsfdi (float);
|
||||
unsigned long long __fixunsdfdi (double);
|
||||
unsigned long long __fixunssfdi (float);
|
||||
double __floatdidf (long long);
|
||||
float __floatdisf (long long);
|
||||
double __floatunsdidf(unsigned long long);
|
||||
long long __fixdfdi(double);
|
||||
long long __fixsfdi(float);
|
||||
unsigned long long __fixunsdfdi(double);
|
||||
unsigned long long __fixunssfdi(float);
|
||||
double __floatdidf(long long);
|
||||
float __floatdisf(long long);
|
||||
double __floatunsdidf(unsigned long long);
|
||||
#endif
|
||||
|
||||
unsigned long long __qdivrem (unsigned long long, unsigned long long,
|
||||
unsigned long long *);
|
||||
unsigned long long __qdivrem(unsigned long long, unsigned long long,
|
||||
unsigned long long *);
|
||||
|
@ -41,21 +41,18 @@
|
||||
* Shift an (unsigned) long long value left (logical shift left).
|
||||
* This is the same as arithmetic shift left!
|
||||
*/
|
||||
long long
|
||||
__lshldi3(long long a, unsigned int shift)
|
||||
{
|
||||
union uu aa;
|
||||
long long __lshldi3(long long a, unsigned int shift) {
|
||||
union uu aa;
|
||||
|
||||
if (shift == 0)
|
||||
return(a);
|
||||
aa.ll = a;
|
||||
if (shift >= INT_BITS) {
|
||||
aa.ui[H] = aa.ui[L] << (shift - INT_BITS);
|
||||
aa.ui[L] = 0;
|
||||
} else {
|
||||
aa.ui[H] = (aa.ui[H] << shift) |
|
||||
(aa.ui[L] >> (INT_BITS - shift));
|
||||
aa.ui[L] <<= shift;
|
||||
}
|
||||
return (aa.ll);
|
||||
if (shift == 0)
|
||||
return (a);
|
||||
aa.ll = a;
|
||||
if (shift >= INT_BITS) {
|
||||
aa.ui[H] = aa.ui[L] << (shift - INT_BITS);
|
||||
aa.ui[L] = 0;
|
||||
} else {
|
||||
aa.ui[H] = (aa.ui[H] << shift) | (aa.ui[L] >> (INT_BITS - shift));
|
||||
aa.ui[L] <<= shift;
|
||||
}
|
||||
return (aa.ll);
|
||||
}
|
||||
|
@ -40,21 +40,18 @@
|
||||
/*
|
||||
* Shift an (unsigned) long long value right (logical shift right).
|
||||
*/
|
||||
long long
|
||||
__lshrdi3(long long a, unsigned int shift)
|
||||
{
|
||||
union uu aa;
|
||||
long long __lshrdi3(long long a, unsigned int shift) {
|
||||
union uu aa;
|
||||
|
||||
if (shift == 0)
|
||||
return(a);
|
||||
aa.ll = a;
|
||||
if (shift >= INT_BITS) {
|
||||
aa.ui[L] = aa.ui[H] >> (shift - INT_BITS);
|
||||
aa.ui[H] = 0;
|
||||
} else {
|
||||
aa.ui[L] = (aa.ui[L] >> shift) |
|
||||
(aa.ui[H] << (INT_BITS - shift));
|
||||
aa.ui[H] >>= shift;
|
||||
}
|
||||
return (aa.ll);
|
||||
if (shift == 0)
|
||||
return (a);
|
||||
aa.ll = a;
|
||||
if (shift >= INT_BITS) {
|
||||
aa.ui[L] = aa.ui[H] >> (shift - INT_BITS);
|
||||
aa.ui[H] = 0;
|
||||
} else {
|
||||
aa.ui[L] = (aa.ui[L] >> shift) | (aa.ui[H] << (INT_BITS - shift));
|
||||
aa.ui[H] >>= shift;
|
||||
}
|
||||
return (aa.ll);
|
||||
}
|
||||
|
@ -42,21 +42,19 @@
|
||||
*
|
||||
* XXX we assume a % b < 0 iff a < 0, but this is actually machine-dependent.
|
||||
*/
|
||||
long long
|
||||
__moddi3(long long a, long long b)
|
||||
{
|
||||
unsigned long long ua, ub, ur;
|
||||
int neg = 0;
|
||||
long long __moddi3(long long a, long long b) {
|
||||
unsigned long long ua, ub, ur;
|
||||
int neg = 0;
|
||||
|
||||
ua = a;
|
||||
ub = b;
|
||||
ua = a;
|
||||
ub = b;
|
||||
|
||||
if (a < 0)
|
||||
ua = -ua, neg ^= 1;
|
||||
if (b < 0)
|
||||
ub = -ub;
|
||||
(void)__qdivrem(ua, ub, &ur);
|
||||
if (neg)
|
||||
ur = -ur;
|
||||
return (ur);
|
||||
if (a < 0)
|
||||
ua = -ua, neg ^= 1;
|
||||
if (b < 0)
|
||||
ub = -ub;
|
||||
(void)__qdivrem(ua, ub, &ur);
|
||||
if (neg)
|
||||
ur = -ur;
|
||||
return (ur);
|
||||
}
|
||||
|
@ -96,67 +96,64 @@
|
||||
*/
|
||||
static long long __lmulq(unsigned int, unsigned int);
|
||||
|
||||
long long
|
||||
__muldi3(long long a, long long b)
|
||||
{
|
||||
union uu u, v, low, prod;
|
||||
unsigned int high, mid, udiff, vdiff;
|
||||
int negall, negmid;
|
||||
#define u1 u.ui[H]
|
||||
#define u0 u.ui[L]
|
||||
#define v1 v.ui[H]
|
||||
#define v0 v.ui[L]
|
||||
long long __muldi3(long long a, long long b) {
|
||||
union uu u, v, low, prod;
|
||||
unsigned int high, mid, udiff, vdiff;
|
||||
int negall, negmid;
|
||||
#define u1 u.ui[H]
|
||||
#define u0 u.ui[L]
|
||||
#define v1 v.ui[H]
|
||||
#define v0 v.ui[L]
|
||||
|
||||
/*
|
||||
* Get u and v such that u, v >= 0. When this is finished,
|
||||
* u1, u0, v1, and v0 will be directly accessible through the
|
||||
* int fields.
|
||||
*/
|
||||
if (a >= 0)
|
||||
u.ll = a, negall = 0;
|
||||
else
|
||||
u.ll = -a, negall = 1;
|
||||
if (b >= 0)
|
||||
v.ll = b;
|
||||
else
|
||||
v.ll = -b, negall ^= 1;
|
||||
/*
|
||||
* Get u and v such that u, v >= 0. When this is finished,
|
||||
* u1, u0, v1, and v0 will be directly accessible through the
|
||||
* int fields.
|
||||
*/
|
||||
if (a >= 0)
|
||||
u.ll = a, negall = 0;
|
||||
else
|
||||
u.ll = -a, negall = 1;
|
||||
if (b >= 0)
|
||||
v.ll = b;
|
||||
else
|
||||
v.ll = -b, negall ^= 1;
|
||||
|
||||
if (u1 == 0 && v1 == 0) {
|
||||
/*
|
||||
* An (I hope) important optimization occurs when u1 and v1
|
||||
* are both 0. This should be common since most numbers
|
||||
* are small. Here the product is just u0*v0.
|
||||
*/
|
||||
prod.ll = __lmulq(u0, v0);
|
||||
} else {
|
||||
/*
|
||||
* Compute the three intermediate products, remembering
|
||||
* whether the middle term is negative. We can discard
|
||||
* any upper bits in high and mid, so we can use native
|
||||
* unsigned int * unsigned int => unsigned int arithmetic.
|
||||
*/
|
||||
low.ll = __lmulq(u0, v0);
|
||||
if (u1 == 0 && v1 == 0) {
|
||||
/*
|
||||
* An (I hope) important optimization occurs when u1 and v1
|
||||
* are both 0. This should be common since most numbers
|
||||
* are small. Here the product is just u0*v0.
|
||||
*/
|
||||
prod.ll = __lmulq(u0, v0);
|
||||
} else {
|
||||
/*
|
||||
* Compute the three intermediate products, remembering
|
||||
* whether the middle term is negative. We can discard
|
||||
* any upper bits in high and mid, so we can use native
|
||||
* unsigned int * unsigned int => unsigned int arithmetic.
|
||||
*/
|
||||
low.ll = __lmulq(u0, v0);
|
||||
|
||||
if (u1 >= u0)
|
||||
negmid = 0, udiff = u1 - u0;
|
||||
else
|
||||
negmid = 1, udiff = u0 - u1;
|
||||
if (v0 >= v1)
|
||||
vdiff = v0 - v1;
|
||||
else
|
||||
vdiff = v1 - v0, negmid ^= 1;
|
||||
mid = udiff * vdiff;
|
||||
if (u1 >= u0)
|
||||
negmid = 0, udiff = u1 - u0;
|
||||
else
|
||||
negmid = 1, udiff = u0 - u1;
|
||||
if (v0 >= v1)
|
||||
vdiff = v0 - v1;
|
||||
else
|
||||
vdiff = v1 - v0, negmid ^= 1;
|
||||
mid = udiff * vdiff;
|
||||
|
||||
high = u1 * v1;
|
||||
high = u1 * v1;
|
||||
|
||||
/*
|
||||
* Assemble the final product.
|
||||
*/
|
||||
prod.ui[H] = high + (negmid ? -mid : mid) + low.ui[L] +
|
||||
low.ui[H];
|
||||
prod.ui[L] = low.ui[L];
|
||||
}
|
||||
return (negall ? -prod.ll : prod.ll);
|
||||
/*
|
||||
* Assemble the final product.
|
||||
*/
|
||||
prod.ui[H] = high + (negmid ? -mid : mid) + low.ui[L] + low.ui[H];
|
||||
prod.ui[L] = low.ui[L];
|
||||
}
|
||||
return (negall ? -prod.ll : prod.ll);
|
||||
#undef u1
|
||||
#undef u0
|
||||
#undef v1
|
||||
@ -180,62 +177,60 @@ __muldi3(long long a, long long b)
|
||||
*
|
||||
* splits into high and low ints as HHALF(l) and LHUP(l) respectively.
|
||||
*/
|
||||
static long long
|
||||
__lmulq(unsigned int u, unsigned int v)
|
||||
{
|
||||
unsigned int u1, u0, v1, v0, udiff, vdiff, high, mid, low;
|
||||
unsigned int prodh, prodl, was;
|
||||
union uu prod;
|
||||
int neg;
|
||||
static long long __lmulq(unsigned int u, unsigned int v) {
|
||||
unsigned int u1, u0, v1, v0, udiff, vdiff, high, mid, low;
|
||||
unsigned int prodh, prodl, was;
|
||||
union uu prod;
|
||||
int neg;
|
||||
|
||||
u1 = HHALF(u);
|
||||
u0 = LHALF(u);
|
||||
v1 = HHALF(v);
|
||||
v0 = LHALF(v);
|
||||
u1 = HHALF(u);
|
||||
u0 = LHALF(u);
|
||||
v1 = HHALF(v);
|
||||
v0 = LHALF(v);
|
||||
|
||||
low = u0 * v0;
|
||||
low = u0 * v0;
|
||||
|
||||
/* This is the same small-number optimization as before. */
|
||||
if (u1 == 0 && v1 == 0)
|
||||
return (low);
|
||||
/* This is the same small-number optimization as before. */
|
||||
if (u1 == 0 && v1 == 0)
|
||||
return (low);
|
||||
|
||||
if (u1 >= u0)
|
||||
udiff = u1 - u0, neg = 0;
|
||||
else
|
||||
udiff = u0 - u1, neg = 1;
|
||||
if (v0 >= v1)
|
||||
vdiff = v0 - v1;
|
||||
else
|
||||
vdiff = v1 - v0, neg ^= 1;
|
||||
mid = udiff * vdiff;
|
||||
if (u1 >= u0)
|
||||
udiff = u1 - u0, neg = 0;
|
||||
else
|
||||
udiff = u0 - u1, neg = 1;
|
||||
if (v0 >= v1)
|
||||
vdiff = v0 - v1;
|
||||
else
|
||||
vdiff = v1 - v0, neg ^= 1;
|
||||
mid = udiff * vdiff;
|
||||
|
||||
high = u1 * v1;
|
||||
high = u1 * v1;
|
||||
|
||||
/* prod = (high << 2N) + (high << N); */
|
||||
prodh = high + HHALF(high);
|
||||
prodl = LHUP(high);
|
||||
/* prod = (high << 2N) + (high << N); */
|
||||
prodh = high + HHALF(high);
|
||||
prodl = LHUP(high);
|
||||
|
||||
/* if (neg) prod -= mid << N; else prod += mid << N; */
|
||||
if (neg) {
|
||||
was = prodl;
|
||||
prodl -= LHUP(mid);
|
||||
prodh -= HHALF(mid) + (prodl > was);
|
||||
} else {
|
||||
was = prodl;
|
||||
prodl += LHUP(mid);
|
||||
prodh += HHALF(mid) + (prodl < was);
|
||||
}
|
||||
/* if (neg) prod -= mid << N; else prod += mid << N; */
|
||||
if (neg) {
|
||||
was = prodl;
|
||||
prodl -= LHUP(mid);
|
||||
prodh -= HHALF(mid) + (prodl > was);
|
||||
} else {
|
||||
was = prodl;
|
||||
prodl += LHUP(mid);
|
||||
prodh += HHALF(mid) + (prodl < was);
|
||||
}
|
||||
|
||||
/* prod += low << N */
|
||||
was = prodl;
|
||||
prodl += LHUP(low);
|
||||
prodh += HHALF(low) + (prodl < was);
|
||||
/* ... + low; */
|
||||
if ((prodl += low) < low)
|
||||
prodh++;
|
||||
/* prod += low << N */
|
||||
was = prodl;
|
||||
prodl += LHUP(low);
|
||||
prodh += HHALF(low) + (prodl < was);
|
||||
/* ... + low; */
|
||||
if ((prodl += low) < low)
|
||||
prodh++;
|
||||
|
||||
/* return 4N-bit product */
|
||||
prod.ui[H] = prodh;
|
||||
prod.ui[L] = prodl;
|
||||
return (prod.ll);
|
||||
/* return 4N-bit product */
|
||||
prod.ui[H] = prodh;
|
||||
prod.ui[L] = prodl;
|
||||
return (prod.ll);
|
||||
}
|
||||
|
@ -40,13 +40,11 @@
|
||||
/*
|
||||
* Return -a (or, equivalently, 0 - a), in long long. See subdi3.c.
|
||||
*/
|
||||
long long
|
||||
__negdi2(long long a)
|
||||
{
|
||||
union uu aa, res;
|
||||
long long __negdi2(long long a) {
|
||||
union uu aa, res;
|
||||
|
||||
aa.ll = a;
|
||||
res.ui[L] = -aa.ui[L];
|
||||
res.ui[H] = -aa.ui[H] - (res.ui[L] > 0);
|
||||
return (res.ll);
|
||||
aa.ll = a;
|
||||
res.ui[L] = -aa.ui[L];
|
||||
res.ui[H] = -aa.ui[H] - (res.ui[L] > 0);
|
||||
return (res.ll);
|
||||
}
|
||||
|
@ -41,13 +41,11 @@
|
||||
* Return ~a. For some reason gcc calls this `one's complement' rather
|
||||
* than `not'.
|
||||
*/
|
||||
long long
|
||||
__one_cmpldi2(long long a)
|
||||
{
|
||||
union uu aa;
|
||||
long long __one_cmpldi2(long long a) {
|
||||
union uu aa;
|
||||
|
||||
aa.ll = a;
|
||||
aa.ui[0] = ~aa.ui[0];
|
||||
aa.ui[1] = ~aa.ui[1];
|
||||
return (aa.ll);
|
||||
aa.ll = a;
|
||||
aa.ui[0] = ~aa.ui[0];
|
||||
aa.ui[1] = ~aa.ui[1];
|
||||
return (aa.ll);
|
||||
}
|
||||
|
@ -42,10 +42,10 @@
|
||||
|
||||
#include "longlong.h"
|
||||
|
||||
#define B ((int)1 << HALF_BITS) /* digit base */
|
||||
#define B ((int)1 << HALF_BITS) /* digit base */
|
||||
|
||||
/* Combine two `digits' to make a single two-digit number. */
|
||||
#define COMBINE(a, b) (((unsigned int)(a) << HALF_BITS) | (b))
|
||||
#define COMBINE(a, b) (((unsigned int)(a) << HALF_BITS) | (b))
|
||||
|
||||
/* select a type for digits in base B: use unsigned short if they fit */
|
||||
#if UINT_MAX == 0xffffffffU && USHRT_MAX >= 0xffff
|
||||
@ -64,202 +64,199 @@ static void shl(digit *p, int len, int sh);
|
||||
* length dividend and divisor are 4 `digits' in this base (they are
|
||||
* shorter if they have leading zeros).
|
||||
*/
|
||||
unsigned long long
|
||||
__qdivrem(unsigned long long ull, unsigned long long vll,
|
||||
unsigned long long *arq)
|
||||
{
|
||||
union uu tmp;
|
||||
digit *u, *v, *q;
|
||||
digit v1, v2;
|
||||
unsigned int qhat, rhat, t;
|
||||
int m, n, d, j, i;
|
||||
digit uspace[5], vspace[5], qspace[5];
|
||||
unsigned long long __qdivrem(unsigned long long ull, unsigned long long vll,
|
||||
unsigned long long *arq) {
|
||||
union uu tmp;
|
||||
digit *u, *v, *q;
|
||||
digit v1, v2;
|
||||
unsigned int qhat, rhat, t;
|
||||
int m, n, d, j, i;
|
||||
digit uspace[5], vspace[5], qspace[5];
|
||||
|
||||
/*
|
||||
* Take care of special cases: divide by zero, and u < v.
|
||||
*/
|
||||
if (vll == 0) {
|
||||
/* divide by zero. */
|
||||
static volatile const unsigned int zero = 0;
|
||||
/*
|
||||
* Take care of special cases: divide by zero, and u < v.
|
||||
*/
|
||||
if (vll == 0) {
|
||||
/* divide by zero. */
|
||||
static volatile const unsigned int zero = 0;
|
||||
|
||||
tmp.ui[H] = tmp.ui[L] = 1 / zero;
|
||||
if (arq)
|
||||
*arq = ull;
|
||||
return (tmp.ll);
|
||||
}
|
||||
if (ull < vll) {
|
||||
if (arq)
|
||||
*arq = ull;
|
||||
return (0);
|
||||
}
|
||||
u = &uspace[0];
|
||||
v = &vspace[0];
|
||||
q = &qspace[0];
|
||||
tmp.ui[H] = tmp.ui[L] = 1 / zero;
|
||||
if (arq)
|
||||
*arq = ull;
|
||||
return (tmp.ll);
|
||||
}
|
||||
if (ull < vll) {
|
||||
if (arq)
|
||||
*arq = ull;
|
||||
return (0);
|
||||
}
|
||||
u = &uspace[0];
|
||||
v = &vspace[0];
|
||||
q = &qspace[0];
|
||||
|
||||
/*
|
||||
* Break dividend and divisor into digits in base B, then
|
||||
* count leading zeros to determine m and n. When done, we
|
||||
* will have:
|
||||
* u = (u[1]u[2]...u[m+n]) sub B
|
||||
* v = (v[1]v[2]...v[n]) sub B
|
||||
* v[1] != 0
|
||||
* 1 < n <= 4 (if n = 1, we use a different division algorithm)
|
||||
* m >= 0 (otherwise u < v, which we already checked)
|
||||
* m + n = 4
|
||||
* and thus
|
||||
* m = 4 - n <= 2
|
||||
*/
|
||||
tmp.ull = ull;
|
||||
u[0] = 0;
|
||||
u[1] = (digit)HHALF(tmp.ui[H]);
|
||||
u[2] = (digit)LHALF(tmp.ui[H]);
|
||||
u[3] = (digit)HHALF(tmp.ui[L]);
|
||||
u[4] = (digit)LHALF(tmp.ui[L]);
|
||||
tmp.ull = vll;
|
||||
v[1] = (digit)HHALF(tmp.ui[H]);
|
||||
v[2] = (digit)LHALF(tmp.ui[H]);
|
||||
v[3] = (digit)HHALF(tmp.ui[L]);
|
||||
v[4] = (digit)LHALF(tmp.ui[L]);
|
||||
for (n = 4; v[1] == 0; v++) {
|
||||
if (--n == 1) {
|
||||
unsigned int rbj; /* r*B+u[j] (not root boy jim) */
|
||||
digit q1, q2, q3, q4;
|
||||
/*
|
||||
* Break dividend and divisor into digits in base B, then
|
||||
* count leading zeros to determine m and n. When done, we
|
||||
* will have:
|
||||
* u = (u[1]u[2]...u[m+n]) sub B
|
||||
* v = (v[1]v[2]...v[n]) sub B
|
||||
* v[1] != 0
|
||||
* 1 < n <= 4 (if n = 1, we use a different division algorithm)
|
||||
* m >= 0 (otherwise u < v, which we already checked)
|
||||
* m + n = 4
|
||||
* and thus
|
||||
* m = 4 - n <= 2
|
||||
*/
|
||||
tmp.ull = ull;
|
||||
u[0] = 0;
|
||||
u[1] = (digit)HHALF(tmp.ui[H]);
|
||||
u[2] = (digit)LHALF(tmp.ui[H]);
|
||||
u[3] = (digit)HHALF(tmp.ui[L]);
|
||||
u[4] = (digit)LHALF(tmp.ui[L]);
|
||||
tmp.ull = vll;
|
||||
v[1] = (digit)HHALF(tmp.ui[H]);
|
||||
v[2] = (digit)LHALF(tmp.ui[H]);
|
||||
v[3] = (digit)HHALF(tmp.ui[L]);
|
||||
v[4] = (digit)LHALF(tmp.ui[L]);
|
||||
for (n = 4; v[1] == 0; v++) {
|
||||
if (--n == 1) {
|
||||
unsigned int rbj; /* r*B+u[j] (not root boy jim) */
|
||||
digit q1, q2, q3, q4;
|
||||
|
||||
/*
|
||||
* Change of plan, per exercise 16.
|
||||
* r = 0;
|
||||
* for j = 1..4:
|
||||
* q[j] = floor((r*B + u[j]) / v),
|
||||
* r = (r*B + u[j]) % v;
|
||||
* We unroll this completely here.
|
||||
*/
|
||||
t = v[2]; /* nonzero, by definition */
|
||||
q1 = (digit)(u[1] / t);
|
||||
rbj = COMBINE(u[1] % t, u[2]);
|
||||
q2 = (digit)(rbj / t);
|
||||
rbj = COMBINE(rbj % t, u[3]);
|
||||
q3 = (digit)(rbj / t);
|
||||
rbj = COMBINE(rbj % t, u[4]);
|
||||
q4 = (digit)(rbj / t);
|
||||
if (arq)
|
||||
*arq = rbj % t;
|
||||
tmp.ui[H] = COMBINE(q1, q2);
|
||||
tmp.ui[L] = COMBINE(q3, q4);
|
||||
return (tmp.ll);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Change of plan, per exercise 16.
|
||||
* r = 0;
|
||||
* for j = 1..4:
|
||||
* q[j] = floor((r*B + u[j]) / v),
|
||||
* r = (r*B + u[j]) % v;
|
||||
* We unroll this completely here.
|
||||
*/
|
||||
t = v[2]; /* nonzero, by definition */
|
||||
q1 = (digit)(u[1] / t);
|
||||
rbj = COMBINE(u[1] % t, u[2]);
|
||||
q2 = (digit)(rbj / t);
|
||||
rbj = COMBINE(rbj % t, u[3]);
|
||||
q3 = (digit)(rbj / t);
|
||||
rbj = COMBINE(rbj % t, u[4]);
|
||||
q4 = (digit)(rbj / t);
|
||||
if (arq)
|
||||
*arq = rbj % t;
|
||||
tmp.ui[H] = COMBINE(q1, q2);
|
||||
tmp.ui[L] = COMBINE(q3, q4);
|
||||
return (tmp.ll);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* By adjusting q once we determine m, we can guarantee that
|
||||
* there is a complete four-digit quotient at &qspace[1] when
|
||||
* we finally stop.
|
||||
*/
|
||||
for (m = 4 - n; u[1] == 0; u++)
|
||||
m--;
|
||||
for (i = 4 - m; --i >= 0;)
|
||||
q[i] = 0;
|
||||
q += 4 - m;
|
||||
/*
|
||||
* By adjusting q once we determine m, we can guarantee that
|
||||
* there is a complete four-digit quotient at &qspace[1] when
|
||||
* we finally stop.
|
||||
*/
|
||||
for (m = 4 - n; u[1] == 0; u++)
|
||||
m--;
|
||||
for (i = 4 - m; --i >= 0;)
|
||||
q[i] = 0;
|
||||
q += 4 - m;
|
||||
|
||||
/*
|
||||
* Here we run Program D, translated from MIX to C and acquiring
|
||||
* a few minor changes.
|
||||
*
|
||||
* D1: choose multiplier 1 << d to ensure v[1] >= B/2.
|
||||
*/
|
||||
d = 0;
|
||||
for (t = v[1]; t < B / 2; t <<= 1)
|
||||
d++;
|
||||
if (d > 0) {
|
||||
shl(&u[0], m + n, d); /* u <<= d */
|
||||
shl(&v[1], n - 1, d); /* v <<= d */
|
||||
}
|
||||
/*
|
||||
* D2: j = 0.
|
||||
*/
|
||||
j = 0;
|
||||
v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
|
||||
v2 = v[2]; /* for D3 */
|
||||
do {
|
||||
digit uj0, uj1, uj2;
|
||||
/*
|
||||
* Here we run Program D, translated from MIX to C and acquiring
|
||||
* a few minor changes.
|
||||
*
|
||||
* D1: choose multiplier 1 << d to ensure v[1] >= B/2.
|
||||
*/
|
||||
d = 0;
|
||||
for (t = v[1]; t < B / 2; t <<= 1)
|
||||
d++;
|
||||
if (d > 0) {
|
||||
shl(&u[0], m + n, d); /* u <<= d */
|
||||
shl(&v[1], n - 1, d); /* v <<= d */
|
||||
}
|
||||
/*
|
||||
* D2: j = 0.
|
||||
*/
|
||||
j = 0;
|
||||
v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
|
||||
v2 = v[2]; /* for D3 */
|
||||
do {
|
||||
digit uj0, uj1, uj2;
|
||||
|
||||
/*
|
||||
* D3: Calculate qhat (\^q, in TeX notation).
|
||||
* Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
|
||||
* let rhat = (u[j]*B + u[j+1]) mod v[1].
|
||||
* While rhat < B and v[2]*qhat > rhat*B+u[j+2],
|
||||
* decrement qhat and increase rhat correspondingly.
|
||||
* Note that if rhat >= B, v[2]*qhat < rhat*B.
|
||||
*/
|
||||
uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
|
||||
uj1 = u[j + 1]; /* for D3 only */
|
||||
uj2 = u[j + 2]; /* for D3 only */
|
||||
if (uj0 == v1) {
|
||||
qhat = B;
|
||||
rhat = uj1;
|
||||
goto qhat_too_big;
|
||||
} else {
|
||||
unsigned int nn = COMBINE(uj0, uj1);
|
||||
qhat = nn / v1;
|
||||
rhat = nn % v1;
|
||||
}
|
||||
while (v2 * qhat > COMBINE(rhat, uj2)) {
|
||||
qhat_too_big:
|
||||
qhat--;
|
||||
if ((rhat += v1) >= B)
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* D4: Multiply and subtract.
|
||||
* The variable `t' holds any borrows across the loop.
|
||||
* We split this up so that we do not require v[0] = 0,
|
||||
* and to eliminate a final special case.
|
||||
*/
|
||||
for (t = 0, i = n; i > 0; i--) {
|
||||
t = u[i + j] - v[i] * qhat - t;
|
||||
u[i + j] = (digit)LHALF(t);
|
||||
t = (B - HHALF(t)) & (B - 1);
|
||||
}
|
||||
t = u[j] - t;
|
||||
u[j] = (digit)LHALF(t);
|
||||
/*
|
||||
* D5: test remainder.
|
||||
* There is a borrow if and only if HHALF(t) is nonzero;
|
||||
* in that (rare) case, qhat was too large (by exactly 1).
|
||||
* Fix it by adding v[1..n] to u[j..j+n].
|
||||
*/
|
||||
if (HHALF(t)) {
|
||||
qhat--;
|
||||
for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
|
||||
t += u[i + j] + v[i];
|
||||
u[i + j] = (digit)LHALF(t);
|
||||
t = HHALF(t);
|
||||
}
|
||||
u[j] = (digit)LHALF(u[j] + t);
|
||||
}
|
||||
q[j] = (digit)qhat;
|
||||
} while (++j <= m); /* D7: loop on j. */
|
||||
/*
|
||||
* D3: Calculate qhat (\^q, in TeX notation).
|
||||
* Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
|
||||
* let rhat = (u[j]*B + u[j+1]) mod v[1].
|
||||
* While rhat < B and v[2]*qhat > rhat*B+u[j+2],
|
||||
* decrement qhat and increase rhat correspondingly.
|
||||
* Note that if rhat >= B, v[2]*qhat < rhat*B.
|
||||
*/
|
||||
uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
|
||||
uj1 = u[j + 1]; /* for D3 only */
|
||||
uj2 = u[j + 2]; /* for D3 only */
|
||||
if (uj0 == v1) {
|
||||
qhat = B;
|
||||
rhat = uj1;
|
||||
goto qhat_too_big;
|
||||
} else {
|
||||
unsigned int nn = COMBINE(uj0, uj1);
|
||||
qhat = nn / v1;
|
||||
rhat = nn % v1;
|
||||
}
|
||||
while (v2 * qhat > COMBINE(rhat, uj2)) {
|
||||
qhat_too_big:
|
||||
qhat--;
|
||||
if ((rhat += v1) >= B)
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* D4: Multiply and subtract.
|
||||
* The variable `t' holds any borrows across the loop.
|
||||
* We split this up so that we do not require v[0] = 0,
|
||||
* and to eliminate a final special case.
|
||||
*/
|
||||
for (t = 0, i = n; i > 0; i--) {
|
||||
t = u[i + j] - v[i] * qhat - t;
|
||||
u[i + j] = (digit)LHALF(t);
|
||||
t = (B - HHALF(t)) & (B - 1);
|
||||
}
|
||||
t = u[j] - t;
|
||||
u[j] = (digit)LHALF(t);
|
||||
/*
|
||||
* D5: test remainder.
|
||||
* There is a borrow if and only if HHALF(t) is nonzero;
|
||||
* in that (rare) case, qhat was too large (by exactly 1).
|
||||
* Fix it by adding v[1..n] to u[j..j+n].
|
||||
*/
|
||||
if (HHALF(t)) {
|
||||
qhat--;
|
||||
for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
|
||||
t += u[i + j] + v[i];
|
||||
u[i + j] = (digit)LHALF(t);
|
||||
t = HHALF(t);
|
||||
}
|
||||
u[j] = (digit)LHALF(u[j] + t);
|
||||
}
|
||||
q[j] = (digit)qhat;
|
||||
} while (++j <= m); /* D7: loop on j. */
|
||||
|
||||
/*
|
||||
* If caller wants the remainder, we have to calculate it as
|
||||
* u[m..m+n] >> d (this is at most n digits and thus fits in
|
||||
* u[m+1..m+n], but we may need more source digits).
|
||||
*/
|
||||
if (arq) {
|
||||
if (d) {
|
||||
for (i = m + n; i > m; --i)
|
||||
u[i] = (digit)(((unsigned int)u[i] >> d) |
|
||||
LHALF((unsigned int)u[i - 1] <<
|
||||
(HALF_BITS - d)));
|
||||
u[i] = 0;
|
||||
}
|
||||
tmp.ui[H] = COMBINE(uspace[1], uspace[2]);
|
||||
tmp.ui[L] = COMBINE(uspace[3], uspace[4]);
|
||||
*arq = tmp.ll;
|
||||
}
|
||||
/*
|
||||
* If caller wants the remainder, we have to calculate it as
|
||||
* u[m..m+n] >> d (this is at most n digits and thus fits in
|
||||
* u[m+1..m+n], but we may need more source digits).
|
||||
*/
|
||||
if (arq) {
|
||||
if (d) {
|
||||
for (i = m + n; i > m; --i)
|
||||
u[i] = (digit)(((unsigned int)u[i] >> d) |
|
||||
LHALF((unsigned int)u[i - 1] << (HALF_BITS - d)));
|
||||
u[i] = 0;
|
||||
}
|
||||
tmp.ui[H] = COMBINE(uspace[1], uspace[2]);
|
||||
tmp.ui[L] = COMBINE(uspace[3], uspace[4]);
|
||||
*arq = tmp.ll;
|
||||
}
|
||||
|
||||
tmp.ui[H] = COMBINE(qspace[1], qspace[2]);
|
||||
tmp.ui[L] = COMBINE(qspace[3], qspace[4]);
|
||||
return (tmp.ll);
|
||||
tmp.ui[H] = COMBINE(qspace[1], qspace[2]);
|
||||
tmp.ui[L] = COMBINE(qspace[3], qspace[4]);
|
||||
return (tmp.ll);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -267,13 +264,11 @@ __qdivrem(unsigned long long ull, unsigned long long vll,
|
||||
* `fall out' the left (there never will be any such anyway).
|
||||
* We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
|
||||
*/
|
||||
static void
|
||||
shl(digit *p, int len, int sh)
|
||||
{
|
||||
int i;
|
||||
static void shl(digit *p, int len, int sh) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
p[i] = (digit)(LHALF((unsigned int)p[i] << sh) |
|
||||
((unsigned int)p[i + 1] >> (HALF_BITS - sh)));
|
||||
p[i] = (digit)(LHALF((unsigned int)p[i] << sh));
|
||||
for (i = 0; i < len; i++)
|
||||
p[i] = (digit)(LHALF((unsigned int)p[i] << sh) |
|
||||
((unsigned int)p[i + 1] >> (HALF_BITS - sh)));
|
||||
p[i] = (digit)(LHALF((unsigned int)p[i] << sh));
|
||||
}
|
||||
|
@ -42,14 +42,12 @@
|
||||
* carry from a single unsigned int difference x-y occurs if and only
|
||||
* if (x-y) > x.
|
||||
*/
|
||||
long long
|
||||
__subdi3(long long a, long long b)
|
||||
{
|
||||
union uu aa, bb, diff;
|
||||
long long __subdi3(long long a, long long b) {
|
||||
union uu aa, bb, diff;
|
||||
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
diff.ui[L] = aa.ui[L] - bb.ui[L];
|
||||
diff.ui[H] = aa.ui[H] - bb.ui[H] - (diff.ui[L] > aa.ui[L]);
|
||||
return (diff.ll);
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
diff.ui[L] = aa.ui[L] - bb.ui[L];
|
||||
diff.ui[H] = aa.ui[H] - bb.ui[H] - (diff.ui[L] > aa.ui[L]);
|
||||
return (diff.ll);
|
||||
}
|
||||
|
@ -41,13 +41,14 @@
|
||||
* Return 0, 1, or 2 as a <, =, > b respectively.
|
||||
* Neither a nor b are considered signed.
|
||||
*/
|
||||
int
|
||||
__ucmpdi2(unsigned long long a, unsigned long long b)
|
||||
{
|
||||
union uu aa, bb;
|
||||
int __ucmpdi2(unsigned long long a, unsigned long long b) {
|
||||
union uu aa, bb;
|
||||
|
||||
aa.ull = a;
|
||||
bb.ull = b;
|
||||
return (aa.ui[H] < bb.ui[H] ? 0 : aa.ui[H] > bb.ui[H] ? 2 :
|
||||
aa.ui[L] < bb.ui[L] ? 0 : aa.ui[L] > bb.ui[L] ? 2 : 1);
|
||||
aa.ull = a;
|
||||
bb.ull = b;
|
||||
return (aa.ui[H] < bb.ui[H] ? 0
|
||||
: aa.ui[H] > bb.ui[H] ? 2
|
||||
: aa.ui[L] < bb.ui[L] ? 0
|
||||
: aa.ui[L] > bb.ui[L] ? 2
|
||||
: 1);
|
||||
}
|
||||
|
@ -40,9 +40,7 @@
|
||||
/*
|
||||
* Divide two unsigned long longs.
|
||||
*/
|
||||
unsigned long long
|
||||
__udivdi3(unsigned long long a, unsigned long long b)
|
||||
{
|
||||
unsigned long long __udivdi3(unsigned long long a, unsigned long long b) {
|
||||
|
||||
return __qdivrem(a, b, NULL);
|
||||
return __qdivrem(a, b, NULL);
|
||||
}
|
||||
|
@ -40,11 +40,9 @@
|
||||
/*
|
||||
* Return remainder after dividing two unsigned long longs.
|
||||
*/
|
||||
unsigned long long
|
||||
__umoddi3(unsigned long long a, unsigned long long b)
|
||||
{
|
||||
unsigned long long r;
|
||||
unsigned long long __umoddi3(unsigned long long a, unsigned long long b) {
|
||||
unsigned long long r;
|
||||
|
||||
(void)__qdivrem(a, b, &r);
|
||||
return (r);
|
||||
(void)__qdivrem(a, b, &r);
|
||||
return (r);
|
||||
}
|
||||
|
@ -40,14 +40,12 @@
|
||||
/*
|
||||
* Return a ^ b, in long long.
|
||||
*/
|
||||
long long
|
||||
__xordi3(long long a, long long b)
|
||||
{
|
||||
union uu aa, bb;
|
||||
long long __xordi3(long long a, long long b) {
|
||||
union uu aa, bb;
|
||||
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
aa.ui[0] ^= bb.ui[0];
|
||||
aa.ui[1] ^= bb.ui[1];
|
||||
return (aa.ll);
|
||||
aa.ll = a;
|
||||
bb.ll = b;
|
||||
aa.ui[0] ^= bb.ui[0];
|
||||
aa.ui[1] ^= bb.ui[1];
|
||||
return (aa.ll);
|
||||
}
|
||||
|
@ -52,7 +52,6 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
/*
|
||||
* Do we want to support "long long" types with %lld?
|
||||
*
|
||||
@ -67,12 +66,11 @@
|
||||
* Define a type that holds the longest signed integer we intend to support.
|
||||
*/
|
||||
#ifdef USE_LONGLONG
|
||||
#define INTTYPE long long
|
||||
#define INTTYPE long long
|
||||
#else
|
||||
#define INTTYPE long
|
||||
#define INTTYPE long
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Space for a long long in base 8, plus a NUL, plus one
|
||||
* character extra for slop.
|
||||
@ -87,52 +85,52 @@
|
||||
* Structure holding the state for printf.
|
||||
*/
|
||||
typedef struct {
|
||||
/* Callback for sending printed string data */
|
||||
void (*sendfunc)(void *clientdata, const char *str, size_t len);
|
||||
void *clientdata;
|
||||
/* Callback for sending printed string data */
|
||||
void (*sendfunc)(void *clientdata, const char *str, size_t len);
|
||||
void *clientdata;
|
||||
|
||||
/* The varargs argument pointer */
|
||||
va_list ap;
|
||||
/* The varargs argument pointer */
|
||||
va_list ap;
|
||||
|
||||
/* Total count of characters printed */
|
||||
int charcount;
|
||||
/* Total count of characters printed */
|
||||
int charcount;
|
||||
|
||||
/* Flag that's true if we are currently looking in a %-format */
|
||||
int in_pct;
|
||||
/* Flag that's true if we are currently looking in a %-format */
|
||||
int in_pct;
|
||||
|
||||
/* Size of the integer argument to retrieve */
|
||||
enum {
|
||||
INTSZ,
|
||||
LONGSZ,
|
||||
/* Size of the integer argument to retrieve */
|
||||
enum {
|
||||
INTSZ,
|
||||
LONGSZ,
|
||||
#ifdef USE_LONGLONG
|
||||
LLONGSZ,
|
||||
LLONGSZ,
|
||||
#endif
|
||||
SIZETSZ,
|
||||
} size;
|
||||
SIZETSZ,
|
||||
} size;
|
||||
|
||||
/* The value of the integer argument retrieved */
|
||||
unsigned INTTYPE num;
|
||||
/* The value of the integer argument retrieved */
|
||||
unsigned INTTYPE num;
|
||||
|
||||
/* Sign of the integer argument (0 = positive; -1 = negative) */
|
||||
int sign;
|
||||
/* Sign of the integer argument (0 = positive; -1 = negative) */
|
||||
int sign;
|
||||
|
||||
/* Field width (number of spaces) */
|
||||
int spacing;
|
||||
/* Field width (number of spaces) */
|
||||
int spacing;
|
||||
|
||||
/* Flag: align to left in field instead of right */
|
||||
int rightspc;
|
||||
/* Flag: align to left in field instead of right */
|
||||
int rightspc;
|
||||
|
||||
/* Character to pad to field size with (space or 0) */
|
||||
int fillchar;
|
||||
/* Character to pad to field size with (space or 0) */
|
||||
int fillchar;
|
||||
|
||||
/* Number base to print the integer argument in (8, 10, 16) */
|
||||
int base;
|
||||
/* Number base to print the integer argument in (8, 10, 16) */
|
||||
int base;
|
||||
|
||||
/* Flag: if set, print 0x before hex and 0 before octal numbers */
|
||||
int baseprefix;
|
||||
/* Flag: if set, print 0x before hex and 0 before octal numbers */
|
||||
int baseprefix;
|
||||
|
||||
/* Flag: alternative output format selected with %#... */
|
||||
int altformat;
|
||||
/* Flag: alternative output format selected with %#... */
|
||||
int altformat;
|
||||
} PF;
|
||||
|
||||
/*
|
||||
@ -141,31 +139,25 @@ typedef struct {
|
||||
* We count the total length we send out so we can return it from __vprintf,
|
||||
* since that's what most printf-like functions want to return.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__pf_print(PF *pf, const char *txt, size_t len)
|
||||
{
|
||||
pf->sendfunc(pf->clientdata, txt, len);
|
||||
pf->charcount += len;
|
||||
static void __pf_print(PF *pf, const char *txt, size_t len) {
|
||||
pf->sendfunc(pf->clientdata, txt, len);
|
||||
pf->charcount += len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the state for the next %-field.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__pf_endfield(PF *pf)
|
||||
{
|
||||
pf->in_pct = 0;
|
||||
pf->size = INTSZ;
|
||||
pf->num = 0;
|
||||
pf->sign = 0;
|
||||
pf->spacing = 0;
|
||||
pf->rightspc = 0;
|
||||
pf->fillchar = ' ';
|
||||
pf->base = 0;
|
||||
pf->baseprefix = 0;
|
||||
pf->altformat = 0;
|
||||
static void __pf_endfield(PF *pf) {
|
||||
pf->in_pct = 0;
|
||||
pf->size = INTSZ;
|
||||
pf->num = 0;
|
||||
pf->sign = 0;
|
||||
pf->spacing = 0;
|
||||
pf->rightspc = 0;
|
||||
pf->fillchar = ' ';
|
||||
pf->base = 0;
|
||||
pf->baseprefix = 0;
|
||||
pf->altformat = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -177,59 +169,54 @@ __pf_endfield(PF *pf)
|
||||
* 0-9 field width
|
||||
* leading 0 pad with zeros instead of spaces
|
||||
*/
|
||||
static
|
||||
void
|
||||
__pf_modifier(PF *pf, int ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case '#':
|
||||
pf->altformat = 1;
|
||||
break;
|
||||
case '-':
|
||||
pf->rightspc = 1;
|
||||
break;
|
||||
case 'l':
|
||||
if (pf->size==LONGSZ) {
|
||||
static void __pf_modifier(PF *pf, int ch) {
|
||||
switch (ch) {
|
||||
case '#':
|
||||
pf->altformat = 1;
|
||||
break;
|
||||
case '-':
|
||||
pf->rightspc = 1;
|
||||
break;
|
||||
case 'l':
|
||||
if (pf->size == LONGSZ) {
|
||||
#ifdef USE_LONGLONG
|
||||
pf->size = LLONGSZ;
|
||||
pf->size = LLONGSZ;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
pf->size = LONGSZ;
|
||||
}
|
||||
break;
|
||||
case 'z':
|
||||
pf->size = SIZETSZ;
|
||||
break;
|
||||
case '0':
|
||||
if (pf->spacing>0) {
|
||||
/*
|
||||
* Already seen some digits; this is part of the
|
||||
* field size.
|
||||
*/
|
||||
pf->spacing = pf->spacing*10;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Leading zero; set the padding character to 0.
|
||||
*/
|
||||
pf->fillchar = '0';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Invalid characters should be filtered out by a
|
||||
* higher-level function, so if this assert goes off
|
||||
* it's our fault.
|
||||
*/
|
||||
assert(ch>'0' && ch<='9');
|
||||
} else {
|
||||
pf->size = LONGSZ;
|
||||
}
|
||||
break;
|
||||
case 'z':
|
||||
pf->size = SIZETSZ;
|
||||
break;
|
||||
case '0':
|
||||
if (pf->spacing > 0) {
|
||||
/*
|
||||
* Already seen some digits; this is part of the
|
||||
* field size.
|
||||
*/
|
||||
pf->spacing = pf->spacing * 10;
|
||||
} else {
|
||||
/*
|
||||
* Leading zero; set the padding character to 0.
|
||||
*/
|
||||
pf->fillchar = '0';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Invalid characters should be filtered out by a
|
||||
* higher-level function, so if this assert goes off
|
||||
* it's our fault.
|
||||
*/
|
||||
assert(ch > '0' && ch <= '9');
|
||||
|
||||
/*
|
||||
* Got a digit; accumulate the field size.
|
||||
*/
|
||||
pf->spacing = pf->spacing*10 + (ch-'0');
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Got a digit; accumulate the field size.
|
||||
*/
|
||||
pf->spacing = pf->spacing * 10 + (ch - '0');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -237,77 +224,71 @@ __pf_modifier(PF *pf, int ch)
|
||||
* in pf->num, according to the size recorded in pf->size and using
|
||||
* the numeric type specified by ch.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__pf_getnum(PF *pf, int ch)
|
||||
{
|
||||
if (ch=='p') {
|
||||
/*
|
||||
* Pointer.
|
||||
*
|
||||
* uintptr_t is a C99 standard type that's an unsigned
|
||||
* integer the same size as a pointer.
|
||||
*/
|
||||
pf->num = (uintptr_t) va_arg(pf->ap, void *);
|
||||
}
|
||||
else if (ch=='d') {
|
||||
/* signed integer */
|
||||
INTTYPE signednum=0;
|
||||
switch (pf->size) {
|
||||
case INTSZ:
|
||||
/* %d */
|
||||
signednum = va_arg(pf->ap, int);
|
||||
break;
|
||||
case LONGSZ:
|
||||
/* %ld */
|
||||
signednum = va_arg(pf->ap, long);
|
||||
break;
|
||||
static void __pf_getnum(PF *pf, int ch) {
|
||||
if (ch == 'p') {
|
||||
/*
|
||||
* Pointer.
|
||||
*
|
||||
* uintptr_t is a C99 standard type that's an unsigned
|
||||
* integer the same size as a pointer.
|
||||
*/
|
||||
pf->num = (uintptr_t)va_arg(pf->ap, void *);
|
||||
} else if (ch == 'd') {
|
||||
/* signed integer */
|
||||
INTTYPE signednum = 0;
|
||||
switch (pf->size) {
|
||||
case INTSZ:
|
||||
/* %d */
|
||||
signednum = va_arg(pf->ap, int);
|
||||
break;
|
||||
case LONGSZ:
|
||||
/* %ld */
|
||||
signednum = va_arg(pf->ap, long);
|
||||
break;
|
||||
#ifdef USE_LONGLONG
|
||||
case LLONGSZ:
|
||||
/* %lld */
|
||||
signednum = va_arg(pf->ap, long long);
|
||||
break;
|
||||
case LLONGSZ:
|
||||
/* %lld */
|
||||
signednum = va_arg(pf->ap, long long);
|
||||
break;
|
||||
#endif
|
||||
case SIZETSZ:
|
||||
/* %zd */
|
||||
signednum = va_arg(pf->ap, ssize_t);
|
||||
break;
|
||||
}
|
||||
case SIZETSZ:
|
||||
/* %zd */
|
||||
signednum = va_arg(pf->ap, ssize_t);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for negative numbers.
|
||||
*/
|
||||
if (signednum < 0) {
|
||||
pf->sign = -1;
|
||||
pf->num = -signednum;
|
||||
}
|
||||
else {
|
||||
pf->num = signednum;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* unsigned integer */
|
||||
switch (pf->size) {
|
||||
case INTSZ:
|
||||
/* %u (or %o, %x) */
|
||||
pf->num = va_arg(pf->ap, unsigned int);
|
||||
break;
|
||||
case LONGSZ:
|
||||
/* %lu (or %lo, %lx) */
|
||||
pf->num = va_arg(pf->ap, unsigned long);
|
||||
break;
|
||||
/*
|
||||
* Check for negative numbers.
|
||||
*/
|
||||
if (signednum < 0) {
|
||||
pf->sign = -1;
|
||||
pf->num = -signednum;
|
||||
} else {
|
||||
pf->num = signednum;
|
||||
}
|
||||
} else {
|
||||
/* unsigned integer */
|
||||
switch (pf->size) {
|
||||
case INTSZ:
|
||||
/* %u (or %o, %x) */
|
||||
pf->num = va_arg(pf->ap, unsigned int);
|
||||
break;
|
||||
case LONGSZ:
|
||||
/* %lu (or %lo, %lx) */
|
||||
pf->num = va_arg(pf->ap, unsigned long);
|
||||
break;
|
||||
#ifdef USE_LONGLONG
|
||||
case LLONGSZ:
|
||||
/* %llu, %llo, %llx */
|
||||
pf->num = va_arg(pf->ap, unsigned long long);
|
||||
break;
|
||||
case LLONGSZ:
|
||||
/* %llu, %llo, %llx */
|
||||
pf->num = va_arg(pf->ap, unsigned long long);
|
||||
break;
|
||||
#endif
|
||||
case SIZETSZ:
|
||||
/* %zu, %zo, %zx */
|
||||
pf->num = va_arg(pf->ap, size_t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case SIZETSZ:
|
||||
/* %zu, %zo, %zx */
|
||||
pf->num = va_arg(pf->ap, size_t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -320,40 +301,34 @@ __pf_getnum(PF *pf, int ch)
|
||||
* If the "alternate format" was requested, or always for pointers,
|
||||
* note to print the C prefix for the type.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__pf_setbase(PF *pf, int ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
case 'u':
|
||||
pf->base = 10;
|
||||
break;
|
||||
case 'x':
|
||||
case 'p':
|
||||
pf->base = 16;
|
||||
break;
|
||||
case 'o':
|
||||
pf->base = 8;
|
||||
break;
|
||||
}
|
||||
if (pf->altformat || ch=='p') {
|
||||
pf->baseprefix = 1;
|
||||
}
|
||||
static void __pf_setbase(PF *pf, int ch) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
case 'u':
|
||||
pf->base = 10;
|
||||
break;
|
||||
case 'x':
|
||||
case 'p':
|
||||
pf->base = 16;
|
||||
break;
|
||||
case 'o':
|
||||
pf->base = 8;
|
||||
break;
|
||||
}
|
||||
if (pf->altformat || ch == 'p') {
|
||||
pf->baseprefix = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to print "spc" instances of the fill character.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__pf_fill(PF *pf, int spc)
|
||||
{
|
||||
char f = pf->fillchar;
|
||||
int i;
|
||||
for (i=0; i<spc; i++) {
|
||||
__pf_print(pf, &f, 1);
|
||||
}
|
||||
static void __pf_fill(PF *pf, int spc) {
|
||||
char f = pf->fillchar;
|
||||
int i;
|
||||
for (i = 0; i < spc; i++) {
|
||||
__pf_print(pf, &f, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -362,45 +337,40 @@ __pf_fill(PF *pf, int spc)
|
||||
* and the other is the sign) get printed *after* space padding but
|
||||
* *before* zero padding, if padding is on the left.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__pf_printstuff(PF *pf,
|
||||
const char *prefix, const char *prefix2,
|
||||
const char *stuff)
|
||||
{
|
||||
/* Total length to print. */
|
||||
int len = strlen(prefix)+strlen(prefix2)+strlen(stuff);
|
||||
static void __pf_printstuff(PF *pf, const char *prefix, const char *prefix2,
|
||||
const char *stuff) {
|
||||
/* Total length to print. */
|
||||
int len = strlen(prefix) + strlen(prefix2) + strlen(stuff);
|
||||
|
||||
/* Get field width and compute amount of padding in "spc". */
|
||||
int spc = pf->spacing;
|
||||
if (spc > len) {
|
||||
spc -= len;
|
||||
}
|
||||
else {
|
||||
spc = 0;
|
||||
}
|
||||
/* Get field width and compute amount of padding in "spc". */
|
||||
int spc = pf->spacing;
|
||||
if (spc > len) {
|
||||
spc -= len;
|
||||
} else {
|
||||
spc = 0;
|
||||
}
|
||||
|
||||
/* If padding on left and the fill char is not 0, pad first. */
|
||||
if (spc > 0 && pf->rightspc==0 && pf->fillchar!='0') {
|
||||
__pf_fill(pf, spc);
|
||||
}
|
||||
/* If padding on left and the fill char is not 0, pad first. */
|
||||
if (spc > 0 && pf->rightspc == 0 && pf->fillchar != '0') {
|
||||
__pf_fill(pf, spc);
|
||||
}
|
||||
|
||||
/* Print the prefixes. */
|
||||
__pf_print(pf, prefix, strlen(prefix));
|
||||
__pf_print(pf, prefix2, strlen(prefix2));
|
||||
/* Print the prefixes. */
|
||||
__pf_print(pf, prefix, strlen(prefix));
|
||||
__pf_print(pf, prefix2, strlen(prefix2));
|
||||
|
||||
/* If padding on left and the fill char *is* 0, pad here. */
|
||||
if (spc > 0 && pf->rightspc==0 && pf->fillchar=='0') {
|
||||
__pf_fill(pf, spc);
|
||||
}
|
||||
/* If padding on left and the fill char *is* 0, pad here. */
|
||||
if (spc > 0 && pf->rightspc == 0 && pf->fillchar == '0') {
|
||||
__pf_fill(pf, spc);
|
||||
}
|
||||
|
||||
/* Print the actual string. */
|
||||
__pf_print(pf, stuff, strlen(stuff));
|
||||
/* Print the actual string. */
|
||||
__pf_print(pf, stuff, strlen(stuff));
|
||||
|
||||
/* If padding on the right, pad afterwards. */
|
||||
if (spc > 0 && pf->rightspc!=0) {
|
||||
__pf_fill(pf, spc);
|
||||
}
|
||||
/* If padding on the right, pad afterwards. */
|
||||
if (spc > 0 && pf->rightspc != 0) {
|
||||
__pf_fill(pf, spc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -410,156 +380,142 @@ __pf_printstuff(PF *pf,
|
||||
* NUMBER_BUF_SIZE is set so that the longest number string we can
|
||||
* generate (a long long printed in octal) will fit. See above.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__pf_printnum(PF *pf)
|
||||
{
|
||||
/* Digits to print with. */
|
||||
const char *const digits = "0123456789abcdef";
|
||||
static void __pf_printnum(PF *pf) {
|
||||
/* Digits to print with. */
|
||||
const char *const digits = "0123456789abcdef";
|
||||
|
||||
char buf[NUMBER_BUF_SIZE]; /* Accumulation buffer for string. */
|
||||
char *x; /* Current pointer into buf. */
|
||||
unsigned INTTYPE xnum; /* Current value to print. */
|
||||
const char *bprefix; /* Base prefix (0, 0x, or nothing) */
|
||||
const char *sprefix; /* Sign prefix (- or nothing) */
|
||||
char buf[NUMBER_BUF_SIZE]; /* Accumulation buffer for string. */
|
||||
char *x; /* Current pointer into buf. */
|
||||
unsigned INTTYPE xnum; /* Current value to print. */
|
||||
const char *bprefix; /* Base prefix (0, 0x, or nothing) */
|
||||
const char *sprefix; /* Sign prefix (- or nothing) */
|
||||
|
||||
/* Start in the last slot of the buffer. */
|
||||
x = buf+sizeof(buf)-1;
|
||||
/* Start in the last slot of the buffer. */
|
||||
x = buf + sizeof(buf) - 1;
|
||||
|
||||
/* Insert null terminator. */
|
||||
*x-- = 0;
|
||||
/* Insert null terminator. */
|
||||
*x-- = 0;
|
||||
|
||||
/* Initialize value. */
|
||||
xnum = pf->num;
|
||||
/* Initialize value. */
|
||||
xnum = pf->num;
|
||||
|
||||
/*
|
||||
* Convert a single digit.
|
||||
* Do this loop at least once - that way 0 prints as 0 and not "".
|
||||
*/
|
||||
do {
|
||||
/*
|
||||
* Get the digit character for the least significant
|
||||
* part of xnum.
|
||||
*/
|
||||
*x = digits[xnum % pf->base];
|
||||
/*
|
||||
* Convert a single digit.
|
||||
* Do this loop at least once - that way 0 prints as 0 and not "".
|
||||
*/
|
||||
do {
|
||||
/*
|
||||
* Get the digit character for the least significant
|
||||
* part of xnum.
|
||||
*/
|
||||
*x = digits[xnum % pf->base];
|
||||
|
||||
/*
|
||||
* Back up the pointer to point to the next space to the left.
|
||||
*/
|
||||
x--;
|
||||
/*
|
||||
* Back up the pointer to point to the next space to the left.
|
||||
*/
|
||||
x--;
|
||||
|
||||
/*
|
||||
* Drop the value of the digit we just printed from xnum.
|
||||
*/
|
||||
xnum = xnum / pf->base;
|
||||
/*
|
||||
* Drop the value of the digit we just printed from xnum.
|
||||
*/
|
||||
xnum = xnum / pf->base;
|
||||
|
||||
/*
|
||||
* If xnum hits 0 there's no more number left.
|
||||
*/
|
||||
} while (xnum > 0);
|
||||
/*
|
||||
* If xnum hits 0 there's no more number left.
|
||||
*/
|
||||
} while (xnum > 0);
|
||||
|
||||
/*
|
||||
* x points to the *next* slot in the buffer to use.
|
||||
* However, we're done printing the number. So it's pointing
|
||||
* one slot *before* the start of the actual number text.
|
||||
* So advance it by one so it actually points at the number.
|
||||
*/
|
||||
x++;
|
||||
/*
|
||||
* x points to the *next* slot in the buffer to use.
|
||||
* However, we're done printing the number. So it's pointing
|
||||
* one slot *before* the start of the actual number text.
|
||||
* So advance it by one so it actually points at the number.
|
||||
*/
|
||||
x++;
|
||||
|
||||
/*
|
||||
* If a base prefix was requested, select it.
|
||||
*/
|
||||
if (pf->baseprefix && pf->base==16) {
|
||||
bprefix = "0x";
|
||||
}
|
||||
else if (pf->baseprefix && pf->base==8) {
|
||||
bprefix = "0";
|
||||
}
|
||||
else {
|
||||
bprefix = "";
|
||||
}
|
||||
/*
|
||||
* If a base prefix was requested, select it.
|
||||
*/
|
||||
if (pf->baseprefix && pf->base == 16) {
|
||||
bprefix = "0x";
|
||||
} else if (pf->baseprefix && pf->base == 8) {
|
||||
bprefix = "0";
|
||||
} else {
|
||||
bprefix = "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Choose the sign prefix.
|
||||
*/
|
||||
sprefix = pf->sign ? "-" : "";
|
||||
/*
|
||||
* Choose the sign prefix.
|
||||
*/
|
||||
sprefix = pf->sign ? "-" : "";
|
||||
|
||||
/*
|
||||
* Now actually print the string we just generated.
|
||||
*/
|
||||
__pf_printstuff(pf, sprefix, bprefix, x);
|
||||
/*
|
||||
* Now actually print the string we just generated.
|
||||
*/
|
||||
__pf_printstuff(pf, sprefix, bprefix, x);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a single character out of the format string.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__pf_send(PF *pf, int ch)
|
||||
{
|
||||
/* Cannot get NULs here. */
|
||||
assert(ch!=0);
|
||||
static void __pf_send(PF *pf, int ch) {
|
||||
/* Cannot get NULs here. */
|
||||
assert(ch != 0);
|
||||
|
||||
if (pf->in_pct==0 && ch!='%') {
|
||||
/*
|
||||
* Not currently in a format, and not a %. Just send
|
||||
* the character on through.
|
||||
*/
|
||||
char c = ch;
|
||||
__pf_print(pf, &c, 1);
|
||||
}
|
||||
else if (pf->in_pct==0) {
|
||||
/*
|
||||
* Not in a format, but got a %. Start a format.
|
||||
*/
|
||||
pf->in_pct = 1;
|
||||
}
|
||||
else if (strchr("#-lz0123456789", ch)) {
|
||||
/*
|
||||
* These are the modifier characters we recognize.
|
||||
* (These are the characters between the % and the type.)
|
||||
*/
|
||||
__pf_modifier(pf, ch);
|
||||
}
|
||||
else if (strchr("doupx", ch)) {
|
||||
/*
|
||||
* Integer types.
|
||||
* Fetch the number, set the base, print it, then
|
||||
* reset for the next format.
|
||||
*/
|
||||
__pf_getnum(pf, ch);
|
||||
__pf_setbase(pf, ch);
|
||||
__pf_printnum(pf);
|
||||
__pf_endfield(pf);
|
||||
}
|
||||
else if (ch=='s') {
|
||||
/*
|
||||
* Print a string.
|
||||
*/
|
||||
const char *str = va_arg(pf->ap, const char *);
|
||||
if (str==NULL) {
|
||||
str = "(null)";
|
||||
}
|
||||
__pf_printstuff(pf, "", "", str);
|
||||
__pf_endfield(pf);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* %%, %c, or illegal character.
|
||||
* Illegal characters are printed like %%.
|
||||
* for example, %5k prints " k".
|
||||
*/
|
||||
char x[2];
|
||||
if (ch=='c') {
|
||||
x[0] = va_arg(pf->ap, int);
|
||||
}
|
||||
else {
|
||||
x[0] = ch;
|
||||
}
|
||||
x[1] = 0;
|
||||
__pf_printstuff(pf, "", "", x);
|
||||
__pf_endfield(pf);
|
||||
}
|
||||
if (pf->in_pct == 0 && ch != '%') {
|
||||
/*
|
||||
* Not currently in a format, and not a %. Just send
|
||||
* the character on through.
|
||||
*/
|
||||
char c = ch;
|
||||
__pf_print(pf, &c, 1);
|
||||
} else if (pf->in_pct == 0) {
|
||||
/*
|
||||
* Not in a format, but got a %. Start a format.
|
||||
*/
|
||||
pf->in_pct = 1;
|
||||
} else if (strchr("#-lz0123456789", ch)) {
|
||||
/*
|
||||
* These are the modifier characters we recognize.
|
||||
* (These are the characters between the % and the type.)
|
||||
*/
|
||||
__pf_modifier(pf, ch);
|
||||
} else if (strchr("doupx", ch)) {
|
||||
/*
|
||||
* Integer types.
|
||||
* Fetch the number, set the base, print it, then
|
||||
* reset for the next format.
|
||||
*/
|
||||
__pf_getnum(pf, ch);
|
||||
__pf_setbase(pf, ch);
|
||||
__pf_printnum(pf);
|
||||
__pf_endfield(pf);
|
||||
} else if (ch == 's') {
|
||||
/*
|
||||
* Print a string.
|
||||
*/
|
||||
const char *str = va_arg(pf->ap, const char *);
|
||||
if (str == NULL) {
|
||||
str = "(null)";
|
||||
}
|
||||
__pf_printstuff(pf, "", "", str);
|
||||
__pf_endfield(pf);
|
||||
} else {
|
||||
/*
|
||||
* %%, %c, or illegal character.
|
||||
* Illegal characters are printed like %%.
|
||||
* for example, %5k prints " k".
|
||||
*/
|
||||
char x[2];
|
||||
if (ch == 'c') {
|
||||
x[0] = va_arg(pf->ap, int);
|
||||
} else {
|
||||
x[0] = ch;
|
||||
}
|
||||
x[1] = 0;
|
||||
__pf_printstuff(pf, "", "", x);
|
||||
__pf_endfield(pf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -567,26 +523,24 @@ __pf_send(PF *pf, int ch)
|
||||
* Create and initialize a printf state object,
|
||||
* then send it each character from the format string.
|
||||
*/
|
||||
int
|
||||
__vprintf(void (*func)(void *clientdata, const char *str, size_t len),
|
||||
void *clientdata, const char *format, va_list ap)
|
||||
{
|
||||
PF pf;
|
||||
int i;
|
||||
int __vprintf(void (*func)(void *clientdata, const char *str, size_t len),
|
||||
void *clientdata, const char *format, va_list ap) {
|
||||
PF pf;
|
||||
int i;
|
||||
|
||||
pf.sendfunc = func;
|
||||
pf.clientdata = clientdata;
|
||||
pf.sendfunc = func;
|
||||
pf.clientdata = clientdata;
|
||||
#ifdef va_copy
|
||||
va_copy(pf.ap, ap);
|
||||
va_copy(pf.ap, ap);
|
||||
#else
|
||||
pf.ap = ap;
|
||||
pf.ap = ap;
|
||||
#endif
|
||||
pf.charcount = 0;
|
||||
__pf_endfield(&pf);
|
||||
pf.charcount = 0;
|
||||
__pf_endfield(&pf);
|
||||
|
||||
for (i=0; format[i]; i++) {
|
||||
__pf_send(&pf, format[i]);
|
||||
}
|
||||
for (i = 0; format[i]; i++) {
|
||||
__pf_send(&pf, format[i]);
|
||||
}
|
||||
|
||||
return pf.charcount;
|
||||
return pf.charcount;
|
||||
}
|
||||
|
@ -47,7 +47,6 @@
|
||||
* Standard C string/IO function: printf into a character buffer.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Context structure for snprintf: buffer to print into, maximum
|
||||
* length, and index of the next character to write.
|
||||
@ -58,9 +57,9 @@
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
size_t bufpos;
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
size_t bufpos;
|
||||
} SNP;
|
||||
|
||||
/*
|
||||
@ -70,88 +69,79 @@ typedef struct {
|
||||
* null-terminated.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
__snprintf_send(void *mydata, const char *data, size_t len)
|
||||
{
|
||||
SNP *snp = mydata;
|
||||
unsigned i;
|
||||
static void __snprintf_send(void *mydata, const char *data, size_t len) {
|
||||
SNP *snp = mydata;
|
||||
unsigned i;
|
||||
|
||||
/* For each character we're sent... */
|
||||
for (i=0; i<len; i++) {
|
||||
/* For each character we're sent... */
|
||||
for (i = 0; i < len; i++) {
|
||||
|
||||
/* If we aren't past the length, */
|
||||
if (snp->bufpos < snp->buflen) {
|
||||
/* If we aren't past the length, */
|
||||
if (snp->bufpos < snp->buflen) {
|
||||
|
||||
/* store the character */
|
||||
snp->buf[snp->bufpos] = data[i];
|
||||
/* store the character */
|
||||
snp->buf[snp->bufpos] = data[i];
|
||||
|
||||
/* and increment the position. */
|
||||
snp->bufpos++;
|
||||
}
|
||||
}
|
||||
/* and increment the position. */
|
||||
snp->bufpos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The va_list version of snprintf.
|
||||
*/
|
||||
int
|
||||
vsnprintf(char *buf, size_t len, const char *fmt, va_list ap)
|
||||
{
|
||||
int chars;
|
||||
SNP snp;
|
||||
int vsnprintf(char *buf, size_t len, const char *fmt, va_list ap) {
|
||||
int chars;
|
||||
SNP snp;
|
||||
|
||||
/*
|
||||
* Fill in the context structure.
|
||||
* We set snp.buflen to the number of characters that can be
|
||||
* written (excluding the null terminator) so as not to have
|
||||
* to special-case the possibility that we got passed a length
|
||||
* of zero elsewhere.
|
||||
*/
|
||||
snp.buf = buf;
|
||||
if (len==0) {
|
||||
snp.buflen = 0;
|
||||
}
|
||||
else {
|
||||
snp.buflen = len-1;
|
||||
}
|
||||
snp.bufpos = 0;
|
||||
/*
|
||||
* Fill in the context structure.
|
||||
* We set snp.buflen to the number of characters that can be
|
||||
* written (excluding the null terminator) so as not to have
|
||||
* to special-case the possibility that we got passed a length
|
||||
* of zero elsewhere.
|
||||
*/
|
||||
snp.buf = buf;
|
||||
if (len == 0) {
|
||||
snp.buflen = 0;
|
||||
} else {
|
||||
snp.buflen = len - 1;
|
||||
}
|
||||
snp.bufpos = 0;
|
||||
|
||||
/* Call __vprintf to do the actual work. */
|
||||
chars = __vprintf(__snprintf_send, &snp, fmt, ap);
|
||||
/* Call __vprintf to do the actual work. */
|
||||
chars = __vprintf(__snprintf_send, &snp, fmt, ap);
|
||||
|
||||
/*
|
||||
* Add a null terminator. If the length *we were passed* is greater
|
||||
* than zero, we reserved a space in the buffer for the terminator,
|
||||
* so this won't overflow. If the length we were passed is zero,
|
||||
* nothing will have been or should be written anyway, and buf
|
||||
* might even be NULL. (C99 explicitly endorses this possibility.)
|
||||
*/
|
||||
if (len > 0) {
|
||||
buf[snp.bufpos] = 0;
|
||||
}
|
||||
/*
|
||||
* Add a null terminator. If the length *we were passed* is greater
|
||||
* than zero, we reserved a space in the buffer for the terminator,
|
||||
* so this won't overflow. If the length we were passed is zero,
|
||||
* nothing will have been or should be written anyway, and buf
|
||||
* might even be NULL. (C99 explicitly endorses this possibility.)
|
||||
*/
|
||||
if (len > 0) {
|
||||
buf[snp.bufpos] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of characters __vprintf processed.
|
||||
* According to C99, snprintf should return this number, not
|
||||
* the number of characters actually stored, and should not
|
||||
* return -1 on overflow but only on other errors. (All none
|
||||
* of them since we don't do multibyte characters...)
|
||||
*/
|
||||
return chars;
|
||||
/*
|
||||
* Return the number of characters __vprintf processed.
|
||||
* According to C99, snprintf should return this number, not
|
||||
* the number of characters actually stored, and should not
|
||||
* return -1 on overflow but only on other errors. (All none
|
||||
* of them since we don't do multibyte characters...)
|
||||
*/
|
||||
return chars;
|
||||
}
|
||||
|
||||
/*
|
||||
* snprintf - hand off to vsnprintf.
|
||||
*/
|
||||
int
|
||||
snprintf(char *buf, size_t len, const char *fmt, ...)
|
||||
{
|
||||
int chars;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
chars = vsnprintf(buf, len, fmt, ap);
|
||||
va_end(ap);
|
||||
return chars;
|
||||
int snprintf(char *buf, size_t len, const char *fmt, ...) {
|
||||
int chars;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
chars = vsnprintf(buf, len, fmt, ap);
|
||||
va_end(ap);
|
||||
return chars;
|
||||
}
|
||||
|
||||
|
@ -46,56 +46,53 @@
|
||||
* really report syntax errors or overflow in any useful way.
|
||||
*/
|
||||
|
||||
int
|
||||
atoi(const char *s)
|
||||
{
|
||||
static const char digits[] = "0123456789"; /* legal digits in order */
|
||||
unsigned val=0; /* value we're accumulating */
|
||||
int neg=0; /* set to true if we see a minus sign */
|
||||
int atoi(const char *s) {
|
||||
static const char digits[] = "0123456789"; /* legal digits in order */
|
||||
unsigned val = 0; /* value we're accumulating */
|
||||
int neg = 0; /* set to true if we see a minus sign */
|
||||
|
||||
/* skip whitespace */
|
||||
while (*s==' ' || *s=='\t') {
|
||||
s++;
|
||||
}
|
||||
/* skip whitespace */
|
||||
while (*s == ' ' || *s == '\t') {
|
||||
s++;
|
||||
}
|
||||
|
||||
/* check for sign */
|
||||
if (*s=='-') {
|
||||
neg=1;
|
||||
s++;
|
||||
}
|
||||
else if (*s=='+') {
|
||||
s++;
|
||||
}
|
||||
/* check for sign */
|
||||
if (*s == '-') {
|
||||
neg = 1;
|
||||
s++;
|
||||
} else if (*s == '+') {
|
||||
s++;
|
||||
}
|
||||
|
||||
/* process each digit */
|
||||
while (*s) {
|
||||
const char *where;
|
||||
unsigned digit;
|
||||
/* process each digit */
|
||||
while (*s) {
|
||||
const char *where;
|
||||
unsigned digit;
|
||||
|
||||
/* look for the digit in the list of digits */
|
||||
where = strchr(digits, *s);
|
||||
if (where==NULL) {
|
||||
/* not found; not a digit, so stop */
|
||||
break;
|
||||
}
|
||||
/* look for the digit in the list of digits */
|
||||
where = strchr(digits, *s);
|
||||
if (where == NULL) {
|
||||
/* not found; not a digit, so stop */
|
||||
break;
|
||||
}
|
||||
|
||||
/* get the index into the digit list, which is the value */
|
||||
digit = (where - digits);
|
||||
/* get the index into the digit list, which is the value */
|
||||
digit = (where - digits);
|
||||
|
||||
/* could (should?) check for overflow here */
|
||||
/* could (should?) check for overflow here */
|
||||
|
||||
/* shift the number over and add in the new digit */
|
||||
val = val*10 + digit;
|
||||
/* shift the number over and add in the new digit */
|
||||
val = val * 10 + digit;
|
||||
|
||||
/* look at the next character */
|
||||
s++;
|
||||
}
|
||||
/* look at the next character */
|
||||
s++;
|
||||
}
|
||||
|
||||
/* handle negative numbers */
|
||||
if (neg) {
|
||||
return -val;
|
||||
}
|
||||
/* handle negative numbers */
|
||||
if (neg) {
|
||||
return -val;
|
||||
}
|
||||
|
||||
/* done */
|
||||
return val;
|
||||
/* done */
|
||||
return val;
|
||||
}
|
||||
|
@ -45,32 +45,28 @@
|
||||
* memory.
|
||||
*/
|
||||
|
||||
void
|
||||
bzero(void *vblock, size_t len)
|
||||
{
|
||||
char *block = vblock;
|
||||
size_t i;
|
||||
void bzero(void *vblock, size_t len) {
|
||||
char *block = vblock;
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* For performance, optimize the common case where the pointer
|
||||
* and the length are word-aligned, and write word-at-a-time
|
||||
* instead of byte-at-a-time. Otherwise, write bytes.
|
||||
*
|
||||
* The alignment logic here should be portable. We rely on the
|
||||
* compiler to be reasonably intelligent about optimizing the
|
||||
* divides and moduli out. Fortunately, it is.
|
||||
*/
|
||||
/*
|
||||
* For performance, optimize the common case where the pointer
|
||||
* and the length are word-aligned, and write word-at-a-time
|
||||
* instead of byte-at-a-time. Otherwise, write bytes.
|
||||
*
|
||||
* The alignment logic here should be portable. We rely on the
|
||||
* compiler to be reasonably intelligent about optimizing the
|
||||
* divides and moduli out. Fortunately, it is.
|
||||
*/
|
||||
|
||||
if ((uintptr_t)block % sizeof(long) == 0 &&
|
||||
len % sizeof(long) == 0) {
|
||||
long *lb = (long *)block;
|
||||
for (i=0; i<len/sizeof(long); i++) {
|
||||
lb[i] = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i=0; i<len; i++) {
|
||||
block[i] = 0;
|
||||
}
|
||||
}
|
||||
if ((uintptr_t)block % sizeof(long) == 0 && len % sizeof(long) == 0) {
|
||||
long *lb = (long *)block;
|
||||
for (i = 0; i < len / sizeof(long); i++) {
|
||||
lb[i] = 0;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < len; i++) {
|
||||
block[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,43 +44,39 @@
|
||||
* C standard function - copy a block of memory.
|
||||
*/
|
||||
|
||||
void *
|
||||
memcpy(void *dst, const void *src, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
void *memcpy(void *dst, const void *src, size_t len) {
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* memcpy does not support overlapping buffers, so always do it
|
||||
* forwards. (Don't change this without adjusting memmove.)
|
||||
*
|
||||
* For speedy copying, optimize the common case where both pointers
|
||||
* and the length are word-aligned, and copy word-at-a-time instead
|
||||
* of byte-at-a-time. Otherwise, copy by bytes.
|
||||
*
|
||||
* The alignment logic below should be portable. We rely on
|
||||
* the compiler to be reasonably intelligent about optimizing
|
||||
* the divides and modulos out. Fortunately, it is.
|
||||
*/
|
||||
/*
|
||||
* memcpy does not support overlapping buffers, so always do it
|
||||
* forwards. (Don't change this without adjusting memmove.)
|
||||
*
|
||||
* For speedy copying, optimize the common case where both pointers
|
||||
* and the length are word-aligned, and copy word-at-a-time instead
|
||||
* of byte-at-a-time. Otherwise, copy by bytes.
|
||||
*
|
||||
* The alignment logic below should be portable. We rely on
|
||||
* the compiler to be reasonably intelligent about optimizing
|
||||
* the divides and modulos out. Fortunately, it is.
|
||||
*/
|
||||
|
||||
if ((uintptr_t)dst % sizeof(long) == 0 &&
|
||||
(uintptr_t)src % sizeof(long) == 0 &&
|
||||
len % sizeof(long) == 0) {
|
||||
if ((uintptr_t)dst % sizeof(long) == 0 &&
|
||||
(uintptr_t)src % sizeof(long) == 0 && len % sizeof(long) == 0) {
|
||||
|
||||
long *d = dst;
|
||||
const long *s = src;
|
||||
long *d = dst;
|
||||
const long *s = src;
|
||||
|
||||
for (i=0; i<len/sizeof(long); i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
for (i = 0; i < len / sizeof(long); i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
} else {
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
return dst;
|
||||
}
|
||||
|
@ -45,73 +45,69 @@
|
||||
* regions correctly.
|
||||
*/
|
||||
|
||||
void *
|
||||
memmove(void *dst, const void *src, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
void *memmove(void *dst, const void *src, size_t len) {
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* If the buffers don't overlap, it doesn't matter what direction
|
||||
* we copy in. If they do, it does, so just assume they always do.
|
||||
* We don't concern ourselves with the possibility that the region
|
||||
* to copy might roll over across the top of memory, because it's
|
||||
* not going to happen.
|
||||
*
|
||||
* If the destination is above the source, we have to copy
|
||||
* back to front to avoid overwriting the data we want to
|
||||
* copy.
|
||||
*
|
||||
* dest: dddddddd
|
||||
* src: ssssssss ^
|
||||
* | ^ |___|
|
||||
* |___|
|
||||
*
|
||||
* If the destination is below the source, we have to copy
|
||||
* front to back.
|
||||
*
|
||||
* dest: dddddddd
|
||||
* src: ^ ssssssss
|
||||
* |___| ^ |
|
||||
* |___|
|
||||
*/
|
||||
/*
|
||||
* If the buffers don't overlap, it doesn't matter what direction
|
||||
* we copy in. If they do, it does, so just assume they always do.
|
||||
* We don't concern ourselves with the possibility that the region
|
||||
* to copy might roll over across the top of memory, because it's
|
||||
* not going to happen.
|
||||
*
|
||||
* If the destination is above the source, we have to copy
|
||||
* back to front to avoid overwriting the data we want to
|
||||
* copy.
|
||||
*
|
||||
* dest: dddddddd
|
||||
* src: ssssssss ^
|
||||
* | ^ |___|
|
||||
* |___|
|
||||
*
|
||||
* If the destination is below the source, we have to copy
|
||||
* front to back.
|
||||
*
|
||||
* dest: dddddddd
|
||||
* src: ^ ssssssss
|
||||
* |___| ^ |
|
||||
* |___|
|
||||
*/
|
||||
|
||||
if ((uintptr_t)dst < (uintptr_t)src) {
|
||||
/*
|
||||
* As author/maintainer of libc, take advantage of the
|
||||
* fact that we know memcpy copies forwards.
|
||||
*/
|
||||
return memcpy(dst, src, len);
|
||||
}
|
||||
if ((uintptr_t)dst < (uintptr_t)src) {
|
||||
/*
|
||||
* As author/maintainer of libc, take advantage of the
|
||||
* fact that we know memcpy copies forwards.
|
||||
*/
|
||||
return memcpy(dst, src, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy by words in the common case. Look in memcpy.c for more
|
||||
* information.
|
||||
*/
|
||||
/*
|
||||
* Copy by words in the common case. Look in memcpy.c for more
|
||||
* information.
|
||||
*/
|
||||
|
||||
if ((uintptr_t)dst % sizeof(long) == 0 &&
|
||||
(uintptr_t)src % sizeof(long) == 0 &&
|
||||
len % sizeof(long) == 0) {
|
||||
if ((uintptr_t)dst % sizeof(long) == 0 &&
|
||||
(uintptr_t)src % sizeof(long) == 0 && len % sizeof(long) == 0) {
|
||||
|
||||
long *d = dst;
|
||||
const long *s = src;
|
||||
long *d = dst;
|
||||
const long *s = src;
|
||||
|
||||
/*
|
||||
* The reason we copy index i-1 and test i>0 is that
|
||||
* i is unsigned -- so testing i>=0 doesn't work.
|
||||
*/
|
||||
/*
|
||||
* The reason we copy index i-1 and test i>0 is that
|
||||
* i is unsigned -- so testing i>=0 doesn't work.
|
||||
*/
|
||||
|
||||
for (i=len/sizeof(long); i>0; i--) {
|
||||
d[i-1] = s[i-1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
for (i = len / sizeof(long); i > 0; i--) {
|
||||
d[i - 1] = s[i - 1];
|
||||
}
|
||||
} else {
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
|
||||
for (i=len; i>0; i--) {
|
||||
d[i-1] = s[i-1];
|
||||
}
|
||||
}
|
||||
for (i = len; i > 0; i--) {
|
||||
d[i - 1] = s[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
return dst;
|
||||
}
|
||||
|
@ -38,15 +38,13 @@
|
||||
* C standard function - initialize a block of memory
|
||||
*/
|
||||
|
||||
void *
|
||||
memset(void *ptr, int ch, size_t len)
|
||||
{
|
||||
char *p = ptr;
|
||||
size_t i;
|
||||
void *memset(void *ptr, int ch, size_t len) {
|
||||
char *p = ptr;
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
p[i] = ch;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
p[i] = ch;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
return ptr;
|
||||
}
|
||||
|
@ -43,12 +43,10 @@
|
||||
* Standard C string function: append one string to another.
|
||||
*/
|
||||
|
||||
char *
|
||||
strcat(char *dest, const char *src)
|
||||
{
|
||||
size_t offset;
|
||||
char *strcat(char *dest, const char *src) {
|
||||
size_t offset;
|
||||
|
||||
offset = strlen(dest);
|
||||
strcpy(dest+offset, src);
|
||||
return dest;
|
||||
offset = strlen(dest);
|
||||
strcpy(dest + offset, src);
|
||||
return dest;
|
||||
}
|
||||
|
@ -43,26 +43,24 @@
|
||||
* C standard string function: find leftmost instance of a character
|
||||
* in a string.
|
||||
*/
|
||||
char *
|
||||
strchr(const char *s, int ch_arg)
|
||||
{
|
||||
/* avoid sign-extension problems */
|
||||
const char ch = ch_arg;
|
||||
char *strchr(const char *s, int ch_arg) {
|
||||
/* avoid sign-extension problems */
|
||||
const char ch = ch_arg;
|
||||
|
||||
/* scan from left to right */
|
||||
while (*s) {
|
||||
/* if we hit it, return it */
|
||||
if (*s == ch) {
|
||||
return (char *)s;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
/* scan from left to right */
|
||||
while (*s) {
|
||||
/* if we hit it, return it */
|
||||
if (*s == ch) {
|
||||
return (char *)s;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
/* if we were looking for the 0, return that */
|
||||
if (*s == ch) {
|
||||
return (char *)s;
|
||||
}
|
||||
/* if we were looking for the 0, return that */
|
||||
if (*s == ch) {
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
/* didn't find it */
|
||||
return NULL;
|
||||
/* didn't find it */
|
||||
return NULL;
|
||||
}
|
||||
|
@ -44,47 +44,44 @@
|
||||
* sort order.
|
||||
*/
|
||||
|
||||
int
|
||||
strcmp(const char *a, const char *b)
|
||||
{
|
||||
size_t i;
|
||||
int strcmp(const char *a, const char *b) {
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* Walk down both strings until either they're different
|
||||
* or we hit the end of A.
|
||||
*
|
||||
* If A and B strings are not the same length, when the
|
||||
* shorter one ends, the two will be different, and we'll
|
||||
* stop before running off the end of either.
|
||||
*
|
||||
* If they *are* the same length, it's sufficient to check
|
||||
* that we haven't run off the end of A, because that's the
|
||||
* same as checking to make sure we haven't run off the end of
|
||||
* B.
|
||||
*/
|
||||
/*
|
||||
* Walk down both strings until either they're different
|
||||
* or we hit the end of A.
|
||||
*
|
||||
* If A and B strings are not the same length, when the
|
||||
* shorter one ends, the two will be different, and we'll
|
||||
* stop before running off the end of either.
|
||||
*
|
||||
* If they *are* the same length, it's sufficient to check
|
||||
* that we haven't run off the end of A, because that's the
|
||||
* same as checking to make sure we haven't run off the end of
|
||||
* B.
|
||||
*/
|
||||
|
||||
for (i=0; a[i]!=0 && a[i]==b[i]; i++) {
|
||||
/* nothing */
|
||||
}
|
||||
for (i = 0; a[i] != 0 && a[i] == b[i]; i++) {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
/*
|
||||
* If A is greater than B, return 1. If A is less than B,
|
||||
* return -1. If they're the same, return 0. Since we have
|
||||
* stopped at the first character of difference (or the end of
|
||||
* both strings) checking the character under I accomplishes
|
||||
* this.
|
||||
*
|
||||
* Note that strcmp does not handle accented characters,
|
||||
* internationalization, or locale sort order; strcoll() does
|
||||
* that.
|
||||
*
|
||||
* The rules say we compare order in terms of *unsigned* char.
|
||||
*/
|
||||
if ((unsigned char)a[i] > (unsigned char)b[i]) {
|
||||
return 1;
|
||||
}
|
||||
else if (a[i] == b[i]) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
/*
|
||||
* If A is greater than B, return 1. If A is less than B,
|
||||
* return -1. If they're the same, return 0. Since we have
|
||||
* stopped at the first character of difference (or the end of
|
||||
* both strings) checking the character under I accomplishes
|
||||
* this.
|
||||
*
|
||||
* Note that strcmp does not handle accented characters,
|
||||
* internationalization, or locale sort order; strcoll() does
|
||||
* that.
|
||||
*
|
||||
* The rules say we compare order in terms of *unsigned* char.
|
||||
*/
|
||||
if ((unsigned char)a[i] > (unsigned char)b[i]) {
|
||||
return 1;
|
||||
} else if (a[i] == b[i]) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -42,22 +42,20 @@
|
||||
/*
|
||||
* Standard C string function: copy one string to another.
|
||||
*/
|
||||
char *
|
||||
strcpy(char *dest, const char *src)
|
||||
{
|
||||
size_t i;
|
||||
char *strcpy(char *dest, const char *src) {
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* Copy characters until we hit the null terminator.
|
||||
*/
|
||||
for (i=0; src[i]; i++) {
|
||||
dest[i] = src[i];
|
||||
}
|
||||
/*
|
||||
* Copy characters until we hit the null terminator.
|
||||
*/
|
||||
for (i = 0; src[i]; i++) {
|
||||
dest[i] = src[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* Add null terminator to result.
|
||||
*/
|
||||
dest[i] = 0;
|
||||
/*
|
||||
* Add null terminator to result.
|
||||
*/
|
||||
dest[i] = 0;
|
||||
|
||||
return dest;
|
||||
return dest;
|
||||
}
|
||||
|
@ -43,13 +43,11 @@
|
||||
* C standard string function: get length of a string
|
||||
*/
|
||||
|
||||
size_t
|
||||
strlen(const char *str)
|
||||
{
|
||||
size_t ret = 0;
|
||||
size_t strlen(const char *str) {
|
||||
size_t ret = 0;
|
||||
|
||||
while (str[ret]) {
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
while (str[ret]) {
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -43,27 +43,25 @@
|
||||
* C standard string function: find rightmost instance of a character
|
||||
* in a string.
|
||||
*/
|
||||
char *
|
||||
strrchr(const char *s, int ch_arg)
|
||||
{
|
||||
/* avoid sign-extension problems */
|
||||
const char ch = ch_arg;
|
||||
char *strrchr(const char *s, int ch_arg) {
|
||||
/* avoid sign-extension problems */
|
||||
const char ch = ch_arg;
|
||||
|
||||
/* start one past the last character INCLUDING NULL TERMINATOR */
|
||||
size_t i = strlen(s)+1;
|
||||
/* start one past the last character INCLUDING NULL TERMINATOR */
|
||||
size_t i = strlen(s) + 1;
|
||||
|
||||
/* go from right to left; stop at 0 */
|
||||
while (i > 0) {
|
||||
/* go from right to left; stop at 0 */
|
||||
while (i > 0) {
|
||||
|
||||
/* decrement first */
|
||||
i--;
|
||||
/* decrement first */
|
||||
i--;
|
||||
|
||||
/* now check the character we're over */
|
||||
if (s[i] == ch) {
|
||||
return (char *)(s+i);
|
||||
}
|
||||
}
|
||||
/* now check the character we're over */
|
||||
if (s[i] == ch) {
|
||||
return (char *)(s + i);
|
||||
}
|
||||
}
|
||||
|
||||
/* didn't find it */
|
||||
return NULL;
|
||||
/* didn't find it */
|
||||
return NULL;
|
||||
}
|
||||
|
@ -46,51 +46,48 @@
|
||||
* The "context" argument should point to a "char *" that is preserved
|
||||
* between calls to strtok_r that wish to operate on same string.
|
||||
*/
|
||||
char *
|
||||
strtok_r(char *string, const char *seps, char **context)
|
||||
{
|
||||
char *head; /* start of word */
|
||||
char *tail; /* end of word */
|
||||
char *strtok_r(char *string, const char *seps, char **context) {
|
||||
char *head; /* start of word */
|
||||
char *tail; /* end of word */
|
||||
|
||||
/* If we're starting up, initialize context */
|
||||
if (string) {
|
||||
*context = string;
|
||||
}
|
||||
/* If we're starting up, initialize context */
|
||||
if (string) {
|
||||
*context = string;
|
||||
}
|
||||
|
||||
/* Get potential start of this next word */
|
||||
head = *context;
|
||||
if (head == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
/* Get potential start of this next word */
|
||||
head = *context;
|
||||
if (head == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Skip any leading separators */
|
||||
while (*head && strchr(seps, *head)) {
|
||||
head++;
|
||||
}
|
||||
/* Skip any leading separators */
|
||||
while (*head && strchr(seps, *head)) {
|
||||
head++;
|
||||
}
|
||||
|
||||
/* Did we hit the end? */
|
||||
if (*head == 0) {
|
||||
/* Nothing left */
|
||||
*context = NULL;
|
||||
return NULL;
|
||||
}
|
||||
/* Did we hit the end? */
|
||||
if (*head == 0) {
|
||||
/* Nothing left */
|
||||
*context = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* skip over word */
|
||||
tail = head;
|
||||
while (*tail && !strchr(seps, *tail)) {
|
||||
tail++;
|
||||
}
|
||||
/* skip over word */
|
||||
tail = head;
|
||||
while (*tail && !strchr(seps, *tail)) {
|
||||
tail++;
|
||||
}
|
||||
|
||||
/* Save head for next time in context */
|
||||
if (*tail == 0) {
|
||||
*context = NULL;
|
||||
}
|
||||
else {
|
||||
*tail = 0;
|
||||
tail++;
|
||||
*context = tail;
|
||||
}
|
||||
/* Save head for next time in context */
|
||||
if (*tail == 0) {
|
||||
*context = NULL;
|
||||
} else {
|
||||
*tail = 0;
|
||||
tail++;
|
||||
*context = tail;
|
||||
}
|
||||
|
||||
/* Return current word */
|
||||
return head;
|
||||
/* Return current word */
|
||||
return head;
|
||||
}
|
||||
|
@ -30,7 +30,6 @@
|
||||
#ifndef _MIPS_CURRENT_H_
|
||||
#define _MIPS_CURRENT_H_
|
||||
|
||||
|
||||
/*
|
||||
* Macro for current thread, or current cpu.
|
||||
*
|
||||
@ -60,7 +59,7 @@
|
||||
*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
register struct thread *curthread __asm("$23"); /* s7 register */
|
||||
register struct thread *curthread __asm("$23"); /* s7 register */
|
||||
#else
|
||||
#error "Don't know how to declare curthread in this compiler"
|
||||
#endif
|
||||
|
@ -34,25 +34,23 @@
|
||||
* MIPS machine-dependent definitions for the ELF binary format.
|
||||
*/
|
||||
|
||||
|
||||
/* The ELF executable type. */
|
||||
#define EM_MACHINE EM_MIPS
|
||||
#define EM_MACHINE EM_MIPS
|
||||
|
||||
/* Linker relocation codes. SIZE DESCRIPTION */
|
||||
#define R_MIPS_NONE 0 /* --- nop */
|
||||
#define R_MIPS_16 1 /* u16 value */
|
||||
#define R_MIPS_32 2 /* u32 value */
|
||||
#define R_MIPS_REL32 3 /* u32 value relative to patched address */
|
||||
#define R_MIPS_26 4 /* u26 j/jal instruction address field */
|
||||
#define R_MIPS_HI16 5 /* u16 %hi(sym) as below */
|
||||
#define R_MIPS_LO16 6 /* s16 %lo(sym) as below */
|
||||
#define R_MIPS_GPREL16 7 /* s16 offset from GP register */
|
||||
#define R_MIPS_LITERAL 8 /* s16 GPREL16 for file-local symbols (?) */
|
||||
#define R_MIPS_GOT16 9 /* u16 offset into global offset table */
|
||||
#define R_MIPS_PC16 10 /* s16 PC-relative reference */
|
||||
#define R_MIPS_CALL16 11 /* u16 call through global offset table */
|
||||
#define R_MIPS_GPREL32 12 /* s32 offset from GP register */
|
||||
#define R_MIPS_NONE 0 /* --- nop */
|
||||
#define R_MIPS_16 1 /* u16 value */
|
||||
#define R_MIPS_32 2 /* u32 value */
|
||||
#define R_MIPS_REL32 3 /* u32 value relative to patched address */
|
||||
#define R_MIPS_26 4 /* u26 j/jal instruction address field */
|
||||
#define R_MIPS_HI16 5 /* u16 %hi(sym) as below */
|
||||
#define R_MIPS_LO16 6 /* s16 %lo(sym) as below */
|
||||
#define R_MIPS_GPREL16 7 /* s16 offset from GP register */
|
||||
#define R_MIPS_LITERAL 8 /* s16 GPREL16 for file-local symbols (?) */
|
||||
#define R_MIPS_GOT16 9 /* u16 offset into global offset table */
|
||||
#define R_MIPS_PC16 10 /* s16 PC-relative reference */
|
||||
#define R_MIPS_CALL16 11 /* u16 call through global offset table */
|
||||
#define R_MIPS_GPREL32 12 /* s32 offset from GP register */
|
||||
/* %hi/%lo are defined so %hi(sym) << 16 + %lo(sym) = sym */
|
||||
|
||||
|
||||
#endif /* _MIPS_ELF_H_ */
|
||||
|
@ -36,39 +36,37 @@
|
||||
#ifndef _KERN_MIPS_REGDEFS_H_
|
||||
#define _KERN_MIPS_REGDEFS_H_
|
||||
|
||||
|
||||
#define z0 $0 /* always zero register */
|
||||
#define AT $1 /* assembler temp register */
|
||||
#define v0 $2 /* value 0 */
|
||||
#define v1 $3 /* value 1 */
|
||||
#define a0 $4 /* argument 0 */
|
||||
#define a1 $5 /* argument 1 */
|
||||
#define a2 $6 /* argument 2 */
|
||||
#define a3 $7 /* argument 3 */
|
||||
#define t0 $8 /* temporary (caller-save) 0 */
|
||||
#define t1 $9 /* temporary (caller-save) 1 */
|
||||
#define t2 $10 /* temporary (caller-save) 2 */
|
||||
#define t3 $11 /* temporary (caller-save) 3 */
|
||||
#define t4 $12 /* temporary (caller-save) 4 */
|
||||
#define t5 $13 /* temporary (caller-save) 5 */
|
||||
#define t6 $14 /* temporary (caller-save) 6 */
|
||||
#define t7 $15 /* temporary (caller-save) 7 */
|
||||
#define s0 $16 /* saved (callee-save) 0 */
|
||||
#define s1 $17 /* saved (callee-save) 1 */
|
||||
#define s2 $18 /* saved (callee-save) 2 */
|
||||
#define s3 $19 /* saved (callee-save) 3 */
|
||||
#define s4 $20 /* saved (callee-save) 4 */
|
||||
#define s5 $21 /* saved (callee-save) 5 */
|
||||
#define s6 $22 /* saved (callee-save) 6 */
|
||||
#define s7 $23 /* saved (callee-save) 7 */
|
||||
#define t8 $24 /* temporary (caller-save) 8 */
|
||||
#define t9 $25 /* temporary (caller-save) 9 */
|
||||
#define k0 $26 /* kernel temporary 0 */
|
||||
#define k1 $27 /* kernel temporary 1 */
|
||||
#define gp $28 /* global pointer */
|
||||
#define sp $29 /* stack pointer */
|
||||
#define s8 $30 /* saved (callee-save) 8 = frame pointer */
|
||||
#define ra $31 /* return address */
|
||||
|
||||
#define z0 $0 /* always zero register */
|
||||
#define AT $1 /* assembler temp register */
|
||||
#define v0 $2 /* value 0 */
|
||||
#define v1 $3 /* value 1 */
|
||||
#define a0 $4 /* argument 0 */
|
||||
#define a1 $5 /* argument 1 */
|
||||
#define a2 $6 /* argument 2 */
|
||||
#define a3 $7 /* argument 3 */
|
||||
#define t0 $8 /* temporary (caller-save) 0 */
|
||||
#define t1 $9 /* temporary (caller-save) 1 */
|
||||
#define t2 $10 /* temporary (caller-save) 2 */
|
||||
#define t3 $11 /* temporary (caller-save) 3 */
|
||||
#define t4 $12 /* temporary (caller-save) 4 */
|
||||
#define t5 $13 /* temporary (caller-save) 5 */
|
||||
#define t6 $14 /* temporary (caller-save) 6 */
|
||||
#define t7 $15 /* temporary (caller-save) 7 */
|
||||
#define s0 $16 /* saved (callee-save) 0 */
|
||||
#define s1 $17 /* saved (callee-save) 1 */
|
||||
#define s2 $18 /* saved (callee-save) 2 */
|
||||
#define s3 $19 /* saved (callee-save) 3 */
|
||||
#define s4 $20 /* saved (callee-save) 4 */
|
||||
#define s5 $21 /* saved (callee-save) 5 */
|
||||
#define s6 $22 /* saved (callee-save) 6 */
|
||||
#define s7 $23 /* saved (callee-save) 7 */
|
||||
#define t8 $24 /* temporary (caller-save) 8 */
|
||||
#define t9 $25 /* temporary (caller-save) 9 */
|
||||
#define k0 $26 /* kernel temporary 0 */
|
||||
#define k1 $27 /* kernel temporary 1 */
|
||||
#define gp $28 /* global pointer */
|
||||
#define sp $29 /* stack pointer */
|
||||
#define s8 $30 /* saved (callee-save) 8 = frame pointer */
|
||||
#define ra $31 /* return address */
|
||||
|
||||
#endif /* _KERN_MIPS_REGDEFS_H_ */
|
||||
|
@ -38,10 +38,9 @@
|
||||
* Must save: s0-s8, sp, ra (11 registers)
|
||||
* Don't change __JB_REGS without adjusting mips_setjmp.S accordingly.
|
||||
*/
|
||||
#define __JB_REGS 11
|
||||
#define __JB_REGS 11
|
||||
|
||||
/* A jmp_buf is an array of __JB_REGS registers */
|
||||
typedef uint32_t jmp_buf[__JB_REGS];
|
||||
|
||||
|
||||
#endif /* _MIPS_SETJMP_H_ */
|
||||
|
@ -27,7 +27,6 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _KERN_MIPS_SIGNAL_H_
|
||||
#define _KERN_MIPS_SIGNAL_H_
|
||||
|
||||
@ -39,7 +38,7 @@
|
||||
* probably won't.)
|
||||
*/
|
||||
struct sigcontext {
|
||||
/* Dummy. */
|
||||
/* Dummy. */
|
||||
};
|
||||
|
||||
#endif /* _KERN_MIPS_SIGNAL_H_ */
|
||||
|
@ -38,21 +38,20 @@
|
||||
* See kern/types.h for an explanation of the underscores.
|
||||
*/
|
||||
|
||||
|
||||
/* Sized integer types, with convenient short names */
|
||||
typedef char __i8; /* 8-bit signed integer */
|
||||
typedef short __i16; /* 16-bit signed integer */
|
||||
typedef int __i32; /* 32-bit signed integer */
|
||||
typedef long long __i64; /* 64-bit signed integer */
|
||||
typedef char __i8; /* 8-bit signed integer */
|
||||
typedef short __i16; /* 16-bit signed integer */
|
||||
typedef int __i32; /* 32-bit signed integer */
|
||||
typedef long long __i64; /* 64-bit signed integer */
|
||||
|
||||
typedef unsigned char __u8; /* 8-bit unsigned integer */
|
||||
typedef unsigned short __u16; /* 16-bit unsigned integer */
|
||||
typedef unsigned int __u32; /* 32-bit unsigned integer */
|
||||
typedef unsigned long long __u64; /* 64-bit unsigned integer */
|
||||
typedef unsigned char __u8; /* 8-bit unsigned integer */
|
||||
typedef unsigned short __u16; /* 16-bit unsigned integer */
|
||||
typedef unsigned int __u32; /* 32-bit unsigned integer */
|
||||
typedef unsigned long long __u64; /* 64-bit unsigned integer */
|
||||
|
||||
/* Further standard C types */
|
||||
typedef long __intptr_t; /* Signed pointer-sized integer */
|
||||
typedef unsigned long __uintptr_t; /* Unsigned pointer-sized integer */
|
||||
typedef long __intptr_t; /* Signed pointer-sized integer */
|
||||
typedef unsigned long __uintptr_t; /* Unsigned pointer-sized integer */
|
||||
|
||||
/*
|
||||
* Since we're a 32-bit platform, size_t, ssize_t, and ptrdiff_t can
|
||||
@ -62,17 +61,16 @@ typedef unsigned long __uintptr_t; /* Unsigned pointer-sized integer */
|
||||
* errors involving size_t, try changing this.
|
||||
*/
|
||||
#if 1
|
||||
typedef unsigned __size_t; /* Size of a memory region */
|
||||
typedef int __ssize_t; /* Signed type of same size */
|
||||
typedef int __ptrdiff_t; /* Difference of two pointers */
|
||||
typedef unsigned __size_t; /* Size of a memory region */
|
||||
typedef int __ssize_t; /* Signed type of same size */
|
||||
typedef int __ptrdiff_t; /* Difference of two pointers */
|
||||
#else
|
||||
typedef unsigned long __size_t; /* Size of a memory region */
|
||||
typedef long __ssize_t; /* Signed type of same size */
|
||||
typedef long __ptrdiff_t; /* Difference of two pointers */
|
||||
typedef unsigned long __size_t; /* Size of a memory region */
|
||||
typedef long __ssize_t; /* Signed type of same size */
|
||||
typedef long __ptrdiff_t; /* Difference of two pointers */
|
||||
#endif
|
||||
|
||||
/* Number of bits per byte. */
|
||||
#define __CHAR_BIT 8
|
||||
|
||||
#define __CHAR_BIT 8
|
||||
|
||||
#endif /* _KERN_MIPS_TYPES_H_ */
|
||||
|
@ -41,17 +41,14 @@
|
||||
*/
|
||||
|
||||
MEMBAR_INLINE
|
||||
void
|
||||
membar_any_any(void)
|
||||
{
|
||||
__asm volatile(
|
||||
".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow MIPS32 instructions */
|
||||
"sync;" /* do it */
|
||||
".set pop" /* restore assembler mode */
|
||||
: /* no outputs */
|
||||
: /* no inputs */
|
||||
: "memory"); /* "changes" memory */
|
||||
void membar_any_any(void) {
|
||||
__asm volatile(".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow MIPS32 instructions */
|
||||
"sync;" /* do it */
|
||||
".set pop" /* restore assembler mode */
|
||||
: /* no outputs */
|
||||
: /* no inputs */
|
||||
: "memory"); /* "changes" memory */
|
||||
}
|
||||
|
||||
MEMBAR_INLINE void membar_load_load(void) { membar_any_any(); }
|
||||
@ -59,5 +56,4 @@ MEMBAR_INLINE void membar_store_store(void) { membar_any_any(); }
|
||||
MEMBAR_INLINE void membar_store_any(void) { membar_any_any(); }
|
||||
MEMBAR_INLINE void membar_any_store(void) { membar_any_any(); }
|
||||
|
||||
|
||||
#endif /* _MIPS_MEMBAR_H_ */
|
||||
|
@ -30,62 +30,61 @@
|
||||
#ifndef _MIPS_SPECIALREG_H_
|
||||
#define _MIPS_SPECIALREG_H_
|
||||
|
||||
|
||||
/*
|
||||
* Coprocessor 0 (system processor) register numbers
|
||||
*/
|
||||
#define c0_index $0 /* TLB entry index register */
|
||||
#define c0_random $1 /* TLB random slot register */
|
||||
#define c0_entrylo $2 /* TLB entry contents (low-order half) */
|
||||
/* c0_entrylo0 $2 */ /* MIPS-II and up only */
|
||||
/* c0_entrylo1 $3 */ /* MIPS-II and up only */
|
||||
#define c0_context $4 /* some precomputed pagetable stuff */
|
||||
/* c0_pagemask $5 */ /* MIPS-II and up only */
|
||||
/* c0_wired $6 */ /* MIPS-II and up only */
|
||||
#define c0_vaddr $8 /* virtual addr of failing memory access */
|
||||
#define c0_count $9 /* cycle counter (MIPS-II and up) */
|
||||
#define c0_entryhi $10 /* TLB entry contents (high-order half) */
|
||||
#define c0_compare $11 /* on-chip timer control (MIPS-II and up) */
|
||||
#define c0_status $12 /* processor status register */
|
||||
#define c0_cause $13 /* exception cause register */
|
||||
#define c0_epc $14 /* exception PC register */
|
||||
#define c0_prid $15 /* processor ID register */
|
||||
/* c0_config $16 */ /* MIPS-II and up only */
|
||||
/* c0_lladdr $17 */ /* MIPS-II and up only */
|
||||
/* c0_watchlo $18 */ /* MIPS-II and up only */
|
||||
/* c0_watchhi $19 */ /* MIPS-II and up only */
|
||||
#define c0_index $0 /* TLB entry index register */
|
||||
#define c0_random $1 /* TLB random slot register */
|
||||
#define c0_entrylo $2 /* TLB entry contents (low-order half) */
|
||||
/* c0_entrylo0 $2 */ /* MIPS-II and up only */
|
||||
/* c0_entrylo1 $3 */ /* MIPS-II and up only */
|
||||
#define c0_context $4 /* some precomputed pagetable stuff */
|
||||
/* c0_pagemask $5 */ /* MIPS-II and up only */
|
||||
/* c0_wired $6 */ /* MIPS-II and up only */
|
||||
#define c0_vaddr $8 /* virtual addr of failing memory access */
|
||||
#define c0_count $9 /* cycle counter (MIPS-II and up) */
|
||||
#define c0_entryhi $10 /* TLB entry contents (high-order half) */
|
||||
#define c0_compare $11 /* on-chip timer control (MIPS-II and up) */
|
||||
#define c0_status $12 /* processor status register */
|
||||
#define c0_cause $13 /* exception cause register */
|
||||
#define c0_epc $14 /* exception PC register */
|
||||
#define c0_prid $15 /* processor ID register */
|
||||
/* c0_config $16 */ /* MIPS-II and up only */
|
||||
/* c0_lladdr $17 */ /* MIPS-II and up only */
|
||||
/* c0_watchlo $18 */ /* MIPS-II and up only */
|
||||
/* c0_watchhi $19 */ /* MIPS-II and up only */
|
||||
|
||||
/*
|
||||
* Mode bits in c0_status
|
||||
*/
|
||||
#define CST_IEc 0x00000001 /* current: interrupt enable */
|
||||
#define CST_KUc 0x00000002 /* current: user mode */
|
||||
#define CST_IEp 0x00000004 /* previous: interrupt enable */
|
||||
#define CST_KUp 0x00000008 /* previous: user mode */
|
||||
#define CST_IEo 0x00000010 /* old: interrupt enable */
|
||||
#define CST_KUo 0x00000020 /* old: user mode */
|
||||
#define CST_IEc 0x00000001 /* current: interrupt enable */
|
||||
#define CST_KUc 0x00000002 /* current: user mode */
|
||||
#define CST_IEp 0x00000004 /* previous: interrupt enable */
|
||||
#define CST_KUp 0x00000008 /* previous: user mode */
|
||||
#define CST_IEo 0x00000010 /* old: interrupt enable */
|
||||
#define CST_KUo 0x00000020 /* old: user mode */
|
||||
#define CST_MODEMASK 0x0000003f /* mask for the above */
|
||||
#define CST_IRQMASK 0x0000ff00 /* mask for the individual irq enable bits */
|
||||
#define CST_BEV 0x00400000 /* bootstrap exception vectors flag */
|
||||
#define CST_IRQMASK 0x0000ff00 /* mask for the individual irq enable bits */
|
||||
#define CST_BEV 0x00400000 /* bootstrap exception vectors flag */
|
||||
|
||||
/*
|
||||
* Fields of the c0_cause register
|
||||
*/
|
||||
#define CCA_UTLB 0x00000001 /* true if UTLB exception (set by our asm) */
|
||||
#define CCA_CODE 0x0000003c /* EX_foo in trapframe.h */
|
||||
#define CCA_IRQS 0x0000ff00 /* Currently pending interrupts */
|
||||
#define CCA_COPN 0x30000000 /* Coprocessor number for EX_CPU */
|
||||
#define CCA_JD 0x80000000 /* True if exception happened in jump delay */
|
||||
#define CCA_UTLB 0x00000001 /* true if UTLB exception (set by our asm) */
|
||||
#define CCA_CODE 0x0000003c /* EX_foo in trapframe.h */
|
||||
#define CCA_IRQS 0x0000ff00 /* Currently pending interrupts */
|
||||
#define CCA_COPN 0x30000000 /* Coprocessor number for EX_CPU */
|
||||
#define CCA_JD 0x80000000 /* True if exception happened in jump delay */
|
||||
|
||||
#define CCA_CODESHIFT 2 /* shift for CCA_CODE field */
|
||||
#define CCA_CODESHIFT 2 /* shift for CCA_CODE field */
|
||||
|
||||
/*
|
||||
* Fields of the c0_index register
|
||||
*/
|
||||
#define CIN_P 0x80000000 /* nonzero -> TLB probe found nothing */
|
||||
#define CIN_INDEX 0x00003f00 /* 6-bit index into TLB */
|
||||
#define CIN_P 0x80000000 /* nonzero -> TLB probe found nothing */
|
||||
#define CIN_INDEX 0x00003f00 /* 6-bit index into TLB */
|
||||
|
||||
#define CIN_INDEXSHIFT 8 /* shift for CIN_INDEX field */
|
||||
#define CIN_INDEXSHIFT 8 /* shift for CIN_INDEX field */
|
||||
|
||||
/*
|
||||
* Fields of the c0_context register
|
||||
@ -102,16 +101,15 @@
|
||||
* there's no other good place in the chip to put it. See discussions
|
||||
* elsewhere.
|
||||
*/
|
||||
#define CTX_VSHIFT 0x001ffffc /* shifted/masked copy of c0_vaddr */
|
||||
#define CTX_PTBASE 0xffe00000 /* page table base address */
|
||||
#define CTX_VSHIFT 0x001ffffc /* shifted/masked copy of c0_vaddr */
|
||||
#define CTX_PTBASE 0xffe00000 /* page table base address */
|
||||
|
||||
#define CTX_PTBASESHIFT 21 /* shift for CTX_PBASE field */
|
||||
#define CTX_PTBASESHIFT 21 /* shift for CTX_PBASE field */
|
||||
|
||||
/*
|
||||
* Hardwired exception handler addresses.
|
||||
*/
|
||||
#define EXADDR_UTLB 0x80000000
|
||||
#define EXADDR_GENERAL 0x80000080
|
||||
|
||||
#define EXADDR_UTLB 0x80000000
|
||||
#define EXADDR_GENERAL 0x80000080
|
||||
|
||||
#endif /* _MIPS_SPECIALREG_H_ */
|
||||
|
@ -32,12 +32,11 @@
|
||||
|
||||
#include <cdefs.h>
|
||||
|
||||
|
||||
/* Type of value needed to actually spin on */
|
||||
typedef unsigned spinlock_data_t;
|
||||
|
||||
/* Initializer for use by SPINLOCK_INITIALIZER */
|
||||
#define SPINLOCK_DATA_INITIALIZER 0
|
||||
#define SPINLOCK_DATA_INITIALIZER 0
|
||||
|
||||
/* Atomic operations on spinlock_data_t */
|
||||
SPINLOCK_INLINE
|
||||
@ -55,10 +54,8 @@ spinlock_data_t spinlock_data_testandset(volatile spinlock_data_t *sd);
|
||||
* memory.
|
||||
*/
|
||||
SPINLOCK_INLINE
|
||||
void
|
||||
spinlock_data_set(volatile spinlock_data_t *sd, unsigned val)
|
||||
{
|
||||
*sd = val;
|
||||
void spinlock_data_set(volatile spinlock_data_t *sd, unsigned val) {
|
||||
*sd = val;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -66,11 +63,7 @@ spinlock_data_set(volatile spinlock_data_t *sd, unsigned val)
|
||||
* instruction, and instructions are atomic with respect to memory.
|
||||
*/
|
||||
SPINLOCK_INLINE
|
||||
spinlock_data_t
|
||||
spinlock_data_get(volatile spinlock_data_t *sd)
|
||||
{
|
||||
return *sd;
|
||||
}
|
||||
spinlock_data_t spinlock_data_get(volatile spinlock_data_t *sd) { return *sd; }
|
||||
|
||||
/*
|
||||
* Test-and-set a spinlock_data_t. Use the LL/SC instructions to
|
||||
@ -86,37 +79,34 @@ spinlock_data_get(volatile spinlock_data_t *sd)
|
||||
* to atomically update one machine word.
|
||||
*/
|
||||
SPINLOCK_INLINE
|
||||
spinlock_data_t
|
||||
spinlock_data_testandset(volatile spinlock_data_t *sd)
|
||||
{
|
||||
spinlock_data_t x;
|
||||
spinlock_data_t y;
|
||||
spinlock_data_t spinlock_data_testandset(volatile spinlock_data_t *sd) {
|
||||
spinlock_data_t x;
|
||||
spinlock_data_t y;
|
||||
|
||||
/*
|
||||
* Test-and-set using LL/SC.
|
||||
*
|
||||
* Load the existing value into X, and use Y to store 1.
|
||||
* After the SC, Y contains 1 if the store succeeded,
|
||||
* 0 if it failed.
|
||||
*
|
||||
* On failure, return 1 to pretend that the spinlock
|
||||
* was already held.
|
||||
*/
|
||||
/*
|
||||
* Test-and-set using LL/SC.
|
||||
*
|
||||
* Load the existing value into X, and use Y to store 1.
|
||||
* After the SC, Y contains 1 if the store succeeded,
|
||||
* 0 if it failed.
|
||||
*
|
||||
* On failure, return 1 to pretend that the spinlock
|
||||
* was already held.
|
||||
*/
|
||||
|
||||
y = 1;
|
||||
__asm volatile(
|
||||
".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow MIPS32 instructions */
|
||||
".set volatile;" /* avoid unwanted optimization */
|
||||
"ll %0, 0(%2);" /* x = *sd */
|
||||
"sc %1, 0(%2);" /* *sd = y; y = success? */
|
||||
".set pop" /* restore assembler mode */
|
||||
: "=&r" (x), "+r" (y) : "r" (sd));
|
||||
if (y == 0) {
|
||||
return 1;
|
||||
}
|
||||
return x;
|
||||
y = 1;
|
||||
__asm volatile(".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow MIPS32 instructions */
|
||||
".set volatile;" /* avoid unwanted optimization */
|
||||
"ll %0, 0(%2);" /* x = *sd */
|
||||
"sc %1, 0(%2);" /* *sd = y; y = success? */
|
||||
".set pop" /* restore assembler mode */
|
||||
: "=&r"(x), "+r"(y)
|
||||
: "r"(sd));
|
||||
if (y == 0) {
|
||||
return 1;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _MIPS_SPINLOCK_H_ */
|
||||
|
@ -30,7 +30,6 @@
|
||||
#ifndef _MIPS_THREAD_H_
|
||||
#define _MIPS_THREAD_H_
|
||||
|
||||
|
||||
/*
|
||||
* Machine-dependent thread bits.
|
||||
*/
|
||||
@ -40,9 +39,8 @@
|
||||
typedef void (*badfaultfunc_t)(void);
|
||||
|
||||
struct thread_machdep {
|
||||
badfaultfunc_t tm_badfaultfunc; /* fault hook used by copyin/out */
|
||||
jmp_buf tm_copyjmp; /* longjmp area used by copyin/out */
|
||||
badfaultfunc_t tm_badfaultfunc; /* fault hook used by copyin/out */
|
||||
jmp_buf tm_copyjmp; /* longjmp area used by copyin/out */
|
||||
};
|
||||
|
||||
|
||||
#endif /* _MIPS_THREAD_H_ */
|
||||
|
@ -77,14 +77,14 @@ int tlb_probe(uint32_t entryhi, uint32_t entrylo);
|
||||
*/
|
||||
|
||||
/* Fields in the high-order word */
|
||||
#define TLBHI_VPAGE 0xfffff000
|
||||
#define TLBHI_VPAGE 0xfffff000
|
||||
/* TLBHI_PID 0x00000fc0 */
|
||||
|
||||
/* Fields in the low-order word */
|
||||
#define TLBLO_PPAGE 0xfffff000
|
||||
#define TLBLO_PPAGE 0xfffff000
|
||||
#define TLBLO_NOCACHE 0x00000800
|
||||
#define TLBLO_DIRTY 0x00000400
|
||||
#define TLBLO_VALID 0x00000200
|
||||
#define TLBLO_DIRTY 0x00000400
|
||||
#define TLBLO_VALID 0x00000200
|
||||
/* TLBLO_GLOBAL 0x00000100 */
|
||||
|
||||
/*
|
||||
@ -92,14 +92,13 @@ int tlb_probe(uint32_t entryhi, uint32_t entrylo);
|
||||
* be passed to TLBHI_INVALID; this prevents loading the same invalid
|
||||
* entry into multiple TLB slots.
|
||||
*/
|
||||
#define TLBHI_INVALID(entryno) ((0x80000+(entryno))<<12)
|
||||
#define TLBLO_INVALID() (0)
|
||||
#define TLBHI_INVALID(entryno) ((0x80000 + (entryno)) << 12)
|
||||
#define TLBLO_INVALID() (0)
|
||||
|
||||
/*
|
||||
* Number of TLB entries in the processor.
|
||||
*/
|
||||
|
||||
#define NUM_TLB 64
|
||||
|
||||
#define NUM_TLB 64
|
||||
|
||||
#endif /* _MIPS_TLB_H_ */
|
||||
|
@ -38,59 +38,59 @@
|
||||
*/
|
||||
|
||||
struct trapframe {
|
||||
uint32_t tf_vaddr; /* coprocessor 0 vaddr register */
|
||||
uint32_t tf_status; /* coprocessor 0 status register */
|
||||
uint32_t tf_cause; /* coprocessor 0 cause register */
|
||||
uint32_t tf_lo;
|
||||
uint32_t tf_hi;
|
||||
uint32_t tf_ra; /* Saved register 31 */
|
||||
uint32_t tf_at; /* Saved register 1 (AT) */
|
||||
uint32_t tf_v0; /* Saved register 2 (v0) */
|
||||
uint32_t tf_v1; /* etc. */
|
||||
uint32_t tf_a0;
|
||||
uint32_t tf_a1;
|
||||
uint32_t tf_a2;
|
||||
uint32_t tf_a3;
|
||||
uint32_t tf_t0;
|
||||
uint32_t tf_t1;
|
||||
uint32_t tf_t2;
|
||||
uint32_t tf_t3;
|
||||
uint32_t tf_t4;
|
||||
uint32_t tf_t5;
|
||||
uint32_t tf_t6;
|
||||
uint32_t tf_t7;
|
||||
uint32_t tf_s0;
|
||||
uint32_t tf_s1;
|
||||
uint32_t tf_s2;
|
||||
uint32_t tf_s3;
|
||||
uint32_t tf_s4;
|
||||
uint32_t tf_s5;
|
||||
uint32_t tf_s6;
|
||||
uint32_t tf_s7;
|
||||
uint32_t tf_t8;
|
||||
uint32_t tf_t9;
|
||||
uint32_t tf_gp;
|
||||
uint32_t tf_sp;
|
||||
uint32_t tf_s8;
|
||||
uint32_t tf_epc; /* coprocessor 0 epc register */
|
||||
uint32_t tf_vaddr; /* coprocessor 0 vaddr register */
|
||||
uint32_t tf_status; /* coprocessor 0 status register */
|
||||
uint32_t tf_cause; /* coprocessor 0 cause register */
|
||||
uint32_t tf_lo;
|
||||
uint32_t tf_hi;
|
||||
uint32_t tf_ra; /* Saved register 31 */
|
||||
uint32_t tf_at; /* Saved register 1 (AT) */
|
||||
uint32_t tf_v0; /* Saved register 2 (v0) */
|
||||
uint32_t tf_v1; /* etc. */
|
||||
uint32_t tf_a0;
|
||||
uint32_t tf_a1;
|
||||
uint32_t tf_a2;
|
||||
uint32_t tf_a3;
|
||||
uint32_t tf_t0;
|
||||
uint32_t tf_t1;
|
||||
uint32_t tf_t2;
|
||||
uint32_t tf_t3;
|
||||
uint32_t tf_t4;
|
||||
uint32_t tf_t5;
|
||||
uint32_t tf_t6;
|
||||
uint32_t tf_t7;
|
||||
uint32_t tf_s0;
|
||||
uint32_t tf_s1;
|
||||
uint32_t tf_s2;
|
||||
uint32_t tf_s3;
|
||||
uint32_t tf_s4;
|
||||
uint32_t tf_s5;
|
||||
uint32_t tf_s6;
|
||||
uint32_t tf_s7;
|
||||
uint32_t tf_t8;
|
||||
uint32_t tf_t9;
|
||||
uint32_t tf_gp;
|
||||
uint32_t tf_sp;
|
||||
uint32_t tf_s8;
|
||||
uint32_t tf_epc; /* coprocessor 0 epc register */
|
||||
};
|
||||
|
||||
/*
|
||||
* MIPS exception codes.
|
||||
*/
|
||||
#define EX_IRQ 0 /* Interrupt */
|
||||
#define EX_MOD 1 /* TLB Modify (write to read-only page) */
|
||||
#define EX_TLBL 2 /* TLB miss on load */
|
||||
#define EX_TLBS 3 /* TLB miss on store */
|
||||
#define EX_ADEL 4 /* Address error on load */
|
||||
#define EX_ADES 5 /* Address error on store */
|
||||
#define EX_IBE 6 /* Bus error on instruction fetch */
|
||||
#define EX_DBE 7 /* Bus error on data load *or* store */
|
||||
#define EX_SYS 8 /* Syscall */
|
||||
#define EX_BP 9 /* Breakpoint */
|
||||
#define EX_RI 10 /* Reserved (illegal) instruction */
|
||||
#define EX_CPU 11 /* Coprocessor unusable */
|
||||
#define EX_OVF 12 /* Arithmetic overflow */
|
||||
#define EX_IRQ 0 /* Interrupt */
|
||||
#define EX_MOD 1 /* TLB Modify (write to read-only page) */
|
||||
#define EX_TLBL 2 /* TLB miss on load */
|
||||
#define EX_TLBS 3 /* TLB miss on store */
|
||||
#define EX_ADEL 4 /* Address error on load */
|
||||
#define EX_ADES 5 /* Address error on store */
|
||||
#define EX_IBE 6 /* Bus error on instruction fetch */
|
||||
#define EX_DBE 7 /* Bus error on data load *or* store */
|
||||
#define EX_SYS 8 /* Syscall */
|
||||
#define EX_BP 9 /* Breakpoint */
|
||||
#define EX_RI 10 /* Reserved (illegal) instruction */
|
||||
#define EX_CPU 11 /* Coprocessor unusable */
|
||||
#define EX_OVF 12 /* Arithmetic overflow */
|
||||
|
||||
/*
|
||||
* Function to enter user mode. Does not return. The trapframe must
|
||||
@ -104,5 +104,4 @@ __DEAD void mips_usermode(struct trapframe *tf);
|
||||
extern vaddr_t cpustacks[];
|
||||
extern vaddr_t cputhreads[];
|
||||
|
||||
|
||||
#endif /* _MIPS_TRAPFRAME_H_ */
|
||||
|
@ -30,13 +30,12 @@
|
||||
#ifndef _MIPS_VM_H_
|
||||
#define _MIPS_VM_H_
|
||||
|
||||
|
||||
/*
|
||||
* Machine-dependent VM system definitions.
|
||||
*/
|
||||
|
||||
#define PAGE_SIZE 4096 /* size of VM page */
|
||||
#define PAGE_FRAME 0xfffff000 /* mask for getting page number from addr */
|
||||
#define PAGE_SIZE 4096 /* size of VM page */
|
||||
#define PAGE_FRAME 0xfffff000 /* mask for getting page number from addr */
|
||||
|
||||
/*
|
||||
* MIPS-I hardwired memory layout:
|
||||
@ -48,10 +47,10 @@
|
||||
* (mips32 is a little different)
|
||||
*/
|
||||
|
||||
#define MIPS_KUSEG 0x00000000
|
||||
#define MIPS_KSEG0 0x80000000
|
||||
#define MIPS_KSEG1 0xa0000000
|
||||
#define MIPS_KSEG2 0xc0000000
|
||||
#define MIPS_KUSEG 0x00000000
|
||||
#define MIPS_KSEG0 0x80000000
|
||||
#define MIPS_KSEG1 0xa0000000
|
||||
#define MIPS_KSEG2 0xc0000000
|
||||
|
||||
/*
|
||||
* The first 512 megs of physical space can be addressed in both kseg0 and
|
||||
@ -65,13 +64,13 @@
|
||||
* exception handler code) when converted to a vaddr it's *not* NULL, *is*
|
||||
* a valid address, and will make a *huge* mess if you scribble on it.
|
||||
*/
|
||||
#define PADDR_TO_KVADDR(paddr) ((paddr)+MIPS_KSEG0)
|
||||
#define PADDR_TO_KVADDR(paddr) ((paddr) + MIPS_KSEG0)
|
||||
|
||||
/*
|
||||
* The top of user space. (Actually, the address immediately above the
|
||||
* last valid user address.)
|
||||
*/
|
||||
#define USERSPACETOP MIPS_KSEG0
|
||||
#define USERSPACETOP MIPS_KSEG0
|
||||
|
||||
/*
|
||||
* The starting value for the stack pointer at user level. Because
|
||||
@ -81,7 +80,7 @@
|
||||
* We put the stack at the very top of user virtual memory because it
|
||||
* grows downwards.
|
||||
*/
|
||||
#define USERSTACK USERSPACETOP
|
||||
#define USERSTACK USERSPACETOP
|
||||
|
||||
/*
|
||||
* Interface to the low-level module that looks after the amount of
|
||||
@ -117,13 +116,12 @@ paddr_t ram_getfirstfree(void);
|
||||
*/
|
||||
|
||||
struct tlbshootdown {
|
||||
/*
|
||||
* Change this to what you need for your VM design.
|
||||
*/
|
||||
int ts_placeholder;
|
||||
/*
|
||||
* Change this to what you need for your VM design.
|
||||
*/
|
||||
int ts_placeholder;
|
||||
};
|
||||
|
||||
#define TLBSHOOTDOWN_MAX 16
|
||||
|
||||
|
||||
#endif /* _MIPS_VM_H_ */
|
||||
|
@ -40,81 +40,68 @@
|
||||
#include <mainbus.h>
|
||||
#include <syscall.h>
|
||||
|
||||
|
||||
/* in exception-*.S */
|
||||
extern __DEAD void asm_usermode(struct trapframe *tf);
|
||||
|
||||
/* called only from assembler, so not declared in a header */
|
||||
void mips_trap(struct trapframe *tf);
|
||||
|
||||
|
||||
/* Names for trap codes */
|
||||
#define NTRAPCODES 13
|
||||
static const char *const trapcodenames[NTRAPCODES] = {
|
||||
"Interrupt",
|
||||
"TLB modify trap",
|
||||
"TLB miss on load",
|
||||
"TLB miss on store",
|
||||
"Address error on load",
|
||||
"Address error on store",
|
||||
"Bus error on code",
|
||||
"Bus error on data",
|
||||
"System call",
|
||||
"Break instruction",
|
||||
"Illegal instruction",
|
||||
"Coprocessor unusable",
|
||||
"Arithmetic overflow",
|
||||
"Interrupt", "TLB modify trap", "TLB miss on load",
|
||||
"TLB miss on store", "Address error on load", "Address error on store",
|
||||
"Bus error on code", "Bus error on data", "System call",
|
||||
"Break instruction", "Illegal instruction", "Coprocessor unusable",
|
||||
"Arithmetic overflow",
|
||||
};
|
||||
|
||||
/*
|
||||
* Function called when user-level code hits a fatal fault.
|
||||
*/
|
||||
static
|
||||
void
|
||||
kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr)
|
||||
{
|
||||
int sig = 0;
|
||||
static void kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr) {
|
||||
int sig = 0;
|
||||
|
||||
KASSERT(code < NTRAPCODES);
|
||||
switch (code) {
|
||||
case EX_IRQ:
|
||||
case EX_IBE:
|
||||
case EX_DBE:
|
||||
case EX_SYS:
|
||||
/* should not be seen */
|
||||
KASSERT(0);
|
||||
sig = SIGABRT;
|
||||
break;
|
||||
case EX_MOD:
|
||||
case EX_TLBL:
|
||||
case EX_TLBS:
|
||||
sig = SIGSEGV;
|
||||
break;
|
||||
case EX_ADEL:
|
||||
case EX_ADES:
|
||||
sig = SIGBUS;
|
||||
break;
|
||||
case EX_BP:
|
||||
sig = SIGTRAP;
|
||||
break;
|
||||
case EX_RI:
|
||||
sig = SIGILL;
|
||||
break;
|
||||
case EX_CPU:
|
||||
sig = SIGSEGV;
|
||||
break;
|
||||
case EX_OVF:
|
||||
sig = SIGFPE;
|
||||
break;
|
||||
}
|
||||
KASSERT(code < NTRAPCODES);
|
||||
switch (code) {
|
||||
case EX_IRQ:
|
||||
case EX_IBE:
|
||||
case EX_DBE:
|
||||
case EX_SYS:
|
||||
/* should not be seen */
|
||||
KASSERT(0);
|
||||
sig = SIGABRT;
|
||||
break;
|
||||
case EX_MOD:
|
||||
case EX_TLBL:
|
||||
case EX_TLBS:
|
||||
sig = SIGSEGV;
|
||||
break;
|
||||
case EX_ADEL:
|
||||
case EX_ADES:
|
||||
sig = SIGBUS;
|
||||
break;
|
||||
case EX_BP:
|
||||
sig = SIGTRAP;
|
||||
break;
|
||||
case EX_RI:
|
||||
sig = SIGILL;
|
||||
break;
|
||||
case EX_CPU:
|
||||
sig = SIGSEGV;
|
||||
break;
|
||||
case EX_OVF:
|
||||
sig = SIGFPE;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* You will probably want to change this.
|
||||
*/
|
||||
/*
|
||||
* You will probably want to change this.
|
||||
*/
|
||||
|
||||
kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n",
|
||||
code, sig, trapcodenames[code], epc, vaddr);
|
||||
panic("I don't know how to handle this\n");
|
||||
kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n", code,
|
||||
sig, trapcodenames[code], epc, vaddr);
|
||||
panic("I don't know how to handle this\n");
|
||||
}
|
||||
|
||||
/*
|
||||
@ -122,229 +109,223 @@ kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr)
|
||||
* This is called by the assembly-language exception handler once
|
||||
* the trapframe has been set up.
|
||||
*/
|
||||
void
|
||||
mips_trap(struct trapframe *tf)
|
||||
{
|
||||
uint32_t code;
|
||||
/*bool isutlb; -- not used */
|
||||
bool iskern;
|
||||
int spl;
|
||||
void mips_trap(struct trapframe *tf) {
|
||||
uint32_t code;
|
||||
/*bool isutlb; -- not used */
|
||||
bool iskern;
|
||||
int spl;
|
||||
|
||||
/* The trap frame is supposed to be 35 registers long. */
|
||||
KASSERT(sizeof(struct trapframe)==(35*4));
|
||||
/* The trap frame is supposed to be 35 registers long. */
|
||||
KASSERT(sizeof(struct trapframe) == (35 * 4));
|
||||
|
||||
/*
|
||||
* Extract the exception code info from the register fields.
|
||||
*/
|
||||
code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT;
|
||||
/*isutlb = (tf->tf_cause & CCA_UTLB) != 0;*/
|
||||
iskern = (tf->tf_status & CST_KUp) == 0;
|
||||
/*
|
||||
* Extract the exception code info from the register fields.
|
||||
*/
|
||||
code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT;
|
||||
/*isutlb = (tf->tf_cause & CCA_UTLB) != 0;*/
|
||||
iskern = (tf->tf_status & CST_KUp) == 0;
|
||||
|
||||
KASSERT(code < NTRAPCODES);
|
||||
KASSERT(code < NTRAPCODES);
|
||||
|
||||
/* Make sure we haven't run off our stack */
|
||||
if (curthread != NULL && curthread->t_stack != NULL) {
|
||||
KASSERT((vaddr_t)tf > (vaddr_t)curthread->t_stack);
|
||||
KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack
|
||||
+ STACK_SIZE));
|
||||
}
|
||||
/* Make sure we haven't run off our stack */
|
||||
if (curthread != NULL && curthread->t_stack != NULL) {
|
||||
KASSERT((vaddr_t)tf > (vaddr_t)curthread->t_stack);
|
||||
KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack + STACK_SIZE));
|
||||
}
|
||||
|
||||
/* Interrupt? Call the interrupt handler and return. */
|
||||
if (code == EX_IRQ) {
|
||||
int old_in;
|
||||
bool doadjust;
|
||||
/* Interrupt? Call the interrupt handler and return. */
|
||||
if (code == EX_IRQ) {
|
||||
int old_in;
|
||||
bool doadjust;
|
||||
|
||||
old_in = curthread->t_in_interrupt;
|
||||
curthread->t_in_interrupt = 1;
|
||||
old_in = curthread->t_in_interrupt;
|
||||
curthread->t_in_interrupt = 1;
|
||||
|
||||
/*
|
||||
* The processor has turned interrupts off; if the
|
||||
* currently recorded interrupt state is interrupts on
|
||||
* (spl of 0), adjust the recorded state to match, and
|
||||
* restore after processing the interrupt.
|
||||
*
|
||||
* How can we get an interrupt if the recorded state
|
||||
* is interrupts off? Well, as things currently stand
|
||||
* when the CPU finishes idling it flips interrupts on
|
||||
* and off to allow things to happen, but leaves
|
||||
* curspl high while doing so.
|
||||
*
|
||||
* While we're here, assert that the interrupt
|
||||
* handling code hasn't leaked a spinlock or an
|
||||
* splhigh().
|
||||
*/
|
||||
/*
|
||||
* The processor has turned interrupts off; if the
|
||||
* currently recorded interrupt state is interrupts on
|
||||
* (spl of 0), adjust the recorded state to match, and
|
||||
* restore after processing the interrupt.
|
||||
*
|
||||
* How can we get an interrupt if the recorded state
|
||||
* is interrupts off? Well, as things currently stand
|
||||
* when the CPU finishes idling it flips interrupts on
|
||||
* and off to allow things to happen, but leaves
|
||||
* curspl high while doing so.
|
||||
*
|
||||
* While we're here, assert that the interrupt
|
||||
* handling code hasn't leaked a spinlock or an
|
||||
* splhigh().
|
||||
*/
|
||||
|
||||
if (curthread->t_curspl == 0) {
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
curthread->t_curspl = IPL_HIGH;
|
||||
curthread->t_iplhigh_count++;
|
||||
doadjust = true;
|
||||
}
|
||||
else {
|
||||
doadjust = false;
|
||||
}
|
||||
if (curthread->t_curspl == 0) {
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
curthread->t_curspl = IPL_HIGH;
|
||||
curthread->t_iplhigh_count++;
|
||||
doadjust = true;
|
||||
} else {
|
||||
doadjust = false;
|
||||
}
|
||||
|
||||
mainbus_interrupt(tf);
|
||||
mainbus_interrupt(tf);
|
||||
|
||||
if (doadjust) {
|
||||
KASSERT(curthread->t_curspl == IPL_HIGH);
|
||||
KASSERT(curthread->t_iplhigh_count == 1);
|
||||
curthread->t_iplhigh_count--;
|
||||
curthread->t_curspl = 0;
|
||||
}
|
||||
if (doadjust) {
|
||||
KASSERT(curthread->t_curspl == IPL_HIGH);
|
||||
KASSERT(curthread->t_iplhigh_count == 1);
|
||||
curthread->t_iplhigh_count--;
|
||||
curthread->t_curspl = 0;
|
||||
}
|
||||
|
||||
curthread->t_in_interrupt = old_in;
|
||||
goto done2;
|
||||
}
|
||||
curthread->t_in_interrupt = old_in;
|
||||
goto done2;
|
||||
}
|
||||
|
||||
/*
|
||||
* The processor turned interrupts off when it took the trap.
|
||||
*
|
||||
* While we're in the kernel, and not actually handling an
|
||||
* interrupt, restore the interrupt state to where it was in
|
||||
* the previous context, which may be low (interrupts on).
|
||||
*
|
||||
* Do this by forcing splhigh(), which may do a redundant
|
||||
* cpu_irqoff() but forces the stored MI interrupt state into
|
||||
* sync, then restoring the previous state.
|
||||
*/
|
||||
spl = splhigh();
|
||||
splx(spl);
|
||||
/*
|
||||
* The processor turned interrupts off when it took the trap.
|
||||
*
|
||||
* While we're in the kernel, and not actually handling an
|
||||
* interrupt, restore the interrupt state to where it was in
|
||||
* the previous context, which may be low (interrupts on).
|
||||
*
|
||||
* Do this by forcing splhigh(), which may do a redundant
|
||||
* cpu_irqoff() but forces the stored MI interrupt state into
|
||||
* sync, then restoring the previous state.
|
||||
*/
|
||||
spl = splhigh();
|
||||
splx(spl);
|
||||
|
||||
/* Syscall? Call the syscall handler and return. */
|
||||
if (code == EX_SYS) {
|
||||
/* Interrupts should have been on while in user mode. */
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
/* Syscall? Call the syscall handler and return. */
|
||||
if (code == EX_SYS) {
|
||||
/* Interrupts should have been on while in user mode. */
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
|
||||
DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n",
|
||||
tf->tf_v0, tf->tf_a0, tf->tf_a1, tf->tf_a2, tf->tf_a3);
|
||||
DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n", tf->tf_v0, tf->tf_a0,
|
||||
tf->tf_a1, tf->tf_a2, tf->tf_a3);
|
||||
|
||||
syscall(tf);
|
||||
goto done;
|
||||
}
|
||||
syscall(tf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, it wasn't any of the really easy cases.
|
||||
* Call vm_fault on the TLB exceptions.
|
||||
* Panic on the bus error exceptions.
|
||||
*/
|
||||
switch (code) {
|
||||
case EX_MOD:
|
||||
if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr)==0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_TLBL:
|
||||
if (vm_fault(VM_FAULT_READ, tf->tf_vaddr)==0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_TLBS:
|
||||
if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr)==0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_IBE:
|
||||
case EX_DBE:
|
||||
/*
|
||||
* This means you loaded invalid TLB entries, or
|
||||
* touched invalid parts of the direct-mapped
|
||||
* segments. These are serious kernel errors, so
|
||||
* panic.
|
||||
*
|
||||
* The MIPS won't even tell you what invalid address
|
||||
* caused the bus error.
|
||||
*/
|
||||
panic("Bus error exception, PC=0x%x\n", tf->tf_epc);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Ok, it wasn't any of the really easy cases.
|
||||
* Call vm_fault on the TLB exceptions.
|
||||
* Panic on the bus error exceptions.
|
||||
*/
|
||||
switch (code) {
|
||||
case EX_MOD:
|
||||
if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr) == 0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_TLBL:
|
||||
if (vm_fault(VM_FAULT_READ, tf->tf_vaddr) == 0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_TLBS:
|
||||
if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr) == 0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_IBE:
|
||||
case EX_DBE:
|
||||
/*
|
||||
* This means you loaded invalid TLB entries, or
|
||||
* touched invalid parts of the direct-mapped
|
||||
* segments. These are serious kernel errors, so
|
||||
* panic.
|
||||
*
|
||||
* The MIPS won't even tell you what invalid address
|
||||
* caused the bus error.
|
||||
*/
|
||||
panic("Bus error exception, PC=0x%x\n", tf->tf_epc);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get to this point, it's a fatal fault - either it's
|
||||
* one of the other exceptions, like illegal instruction, or
|
||||
* it was a page fault we couldn't handle.
|
||||
*/
|
||||
/*
|
||||
* If we get to this point, it's a fatal fault - either it's
|
||||
* one of the other exceptions, like illegal instruction, or
|
||||
* it was a page fault we couldn't handle.
|
||||
*/
|
||||
|
||||
if (!iskern) {
|
||||
/*
|
||||
* Fatal fault in user mode.
|
||||
* Kill the current user process.
|
||||
*/
|
||||
kill_curthread(tf->tf_epc, code, tf->tf_vaddr);
|
||||
goto done;
|
||||
}
|
||||
if (!iskern) {
|
||||
/*
|
||||
* Fatal fault in user mode.
|
||||
* Kill the current user process.
|
||||
*/
|
||||
kill_curthread(tf->tf_epc, code, tf->tf_vaddr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fatal fault in kernel mode.
|
||||
*
|
||||
* If pcb_badfaultfunc is set, we do not panic; badfaultfunc is
|
||||
* set by copyin/copyout and related functions to signify that
|
||||
* the addresses they're accessing are userlevel-supplied and
|
||||
* not trustable. What we actually want to do is resume
|
||||
* execution at the function pointed to by badfaultfunc. That's
|
||||
* going to be "copyfail" (see copyinout.c), which longjmps
|
||||
* back to copyin/copyout or wherever and returns EFAULT.
|
||||
*
|
||||
* Note that we do not just *call* this function, because that
|
||||
* won't necessarily do anything. We want the control flow
|
||||
* that is currently executing in copyin (or whichever), and
|
||||
* is stopped while we process the exception, to *teleport* to
|
||||
* copyfail.
|
||||
*
|
||||
* This is accomplished by changing tf->tf_epc and returning
|
||||
* from the exception handler.
|
||||
*/
|
||||
/*
|
||||
* Fatal fault in kernel mode.
|
||||
*
|
||||
* If pcb_badfaultfunc is set, we do not panic; badfaultfunc is
|
||||
* set by copyin/copyout and related functions to signify that
|
||||
* the addresses they're accessing are userlevel-supplied and
|
||||
* not trustable. What we actually want to do is resume
|
||||
* execution at the function pointed to by badfaultfunc. That's
|
||||
* going to be "copyfail" (see copyinout.c), which longjmps
|
||||
* back to copyin/copyout or wherever and returns EFAULT.
|
||||
*
|
||||
* Note that we do not just *call* this function, because that
|
||||
* won't necessarily do anything. We want the control flow
|
||||
* that is currently executing in copyin (or whichever), and
|
||||
* is stopped while we process the exception, to *teleport* to
|
||||
* copyfail.
|
||||
*
|
||||
* This is accomplished by changing tf->tf_epc and returning
|
||||
* from the exception handler.
|
||||
*/
|
||||
|
||||
if (curthread != NULL &&
|
||||
curthread->t_machdep.tm_badfaultfunc != NULL) {
|
||||
tf->tf_epc = (vaddr_t) curthread->t_machdep.tm_badfaultfunc;
|
||||
goto done;
|
||||
}
|
||||
if (curthread != NULL && curthread->t_machdep.tm_badfaultfunc != NULL) {
|
||||
tf->tf_epc = (vaddr_t)curthread->t_machdep.tm_badfaultfunc;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Really fatal kernel-mode fault.
|
||||
*/
|
||||
/*
|
||||
* Really fatal kernel-mode fault.
|
||||
*/
|
||||
|
||||
kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code,
|
||||
trapcodenames[code]);
|
||||
kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n",
|
||||
tf->tf_epc, tf->tf_vaddr);
|
||||
kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code,
|
||||
trapcodenames[code]);
|
||||
kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n", tf->tf_epc, tf->tf_vaddr);
|
||||
|
||||
panic("I can't handle this... I think I'll just die now...\n");
|
||||
panic("I can't handle this... I think I'll just die now...\n");
|
||||
|
||||
done:
|
||||
/*
|
||||
* Turn interrupts off on the processor, without affecting the
|
||||
* stored interrupt state.
|
||||
*/
|
||||
cpu_irqoff();
|
||||
done2:
|
||||
done:
|
||||
/*
|
||||
* Turn interrupts off on the processor, without affecting the
|
||||
* stored interrupt state.
|
||||
*/
|
||||
cpu_irqoff();
|
||||
done2:
|
||||
|
||||
/*
|
||||
* The boot thread can get here (e.g. on interrupt return) but
|
||||
* since it doesn't go to userlevel, it can't be returning to
|
||||
* userlevel, so there's no need to set cputhreads[] and
|
||||
* cpustacks[]. Just return.
|
||||
*/
|
||||
if (curthread->t_stack == NULL) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* The boot thread can get here (e.g. on interrupt return) but
|
||||
* since it doesn't go to userlevel, it can't be returning to
|
||||
* userlevel, so there's no need to set cputhreads[] and
|
||||
* cpustacks[]. Just return.
|
||||
*/
|
||||
if (curthread->t_stack == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
||||
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
||||
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
||||
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
||||
|
||||
/*
|
||||
* This assertion will fail if either
|
||||
* (1) curthread->t_stack is corrupted, or
|
||||
* (2) the trap frame is somehow on the wrong kernel stack.
|
||||
*
|
||||
* If cpustacks[] is corrupted, the next trap back to the
|
||||
* kernel will (most likely) hang the system, so it's better
|
||||
* to find out now.
|
||||
*/
|
||||
KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
|
||||
/*
|
||||
* This assertion will fail if either
|
||||
* (1) curthread->t_stack is corrupted, or
|
||||
* (2) the trap frame is somehow on the wrong kernel stack.
|
||||
*
|
||||
* If cpustacks[] is corrupted, the next trap back to the
|
||||
* kernel will (most likely) hang the system, so it's better
|
||||
* to find out now.
|
||||
*/
|
||||
KASSERT(SAME_STACK(cpustacks[curcpu->c_number] - 1, (vaddr_t)tf));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -364,43 +345,41 @@ mips_trap(struct trapframe *tf)
|
||||
* - enter_new_process, for use by exec and equivalent.
|
||||
* - enter_forked_process, in syscall.c, for use by fork.
|
||||
*/
|
||||
void
|
||||
mips_usermode(struct trapframe *tf)
|
||||
{
|
||||
void mips_usermode(struct trapframe *tf) {
|
||||
|
||||
/*
|
||||
* Interrupts should be off within the kernel while entering
|
||||
* user mode. However, while in user mode, interrupts should
|
||||
* be on. To interact properly with the spl-handling logic
|
||||
* above, we explicitly call spl0() and then call cpu_irqoff().
|
||||
*/
|
||||
spl0();
|
||||
cpu_irqoff();
|
||||
/*
|
||||
* Interrupts should be off within the kernel while entering
|
||||
* user mode. However, while in user mode, interrupts should
|
||||
* be on. To interact properly with the spl-handling logic
|
||||
* above, we explicitly call spl0() and then call cpu_irqoff().
|
||||
*/
|
||||
spl0();
|
||||
cpu_irqoff();
|
||||
|
||||
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
||||
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
||||
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
||||
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
||||
|
||||
/*
|
||||
* This assertion will fail if either
|
||||
* (1) cpustacks[] is corrupted, or
|
||||
* (2) the trap frame is not on our own kernel stack, or
|
||||
* (3) the boot thread tries to enter user mode.
|
||||
*
|
||||
* If cpustacks[] is corrupted, the next trap back to the
|
||||
* kernel will (most likely) hang the system, so it's better
|
||||
* to find out now.
|
||||
*
|
||||
* It's necessary for the trap frame used here to be on the
|
||||
* current thread's own stack. It cannot correctly be on
|
||||
* either another thread's stack or in the kernel heap.
|
||||
* (Exercise: why?)
|
||||
*/
|
||||
KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
|
||||
/*
|
||||
* This assertion will fail if either
|
||||
* (1) cpustacks[] is corrupted, or
|
||||
* (2) the trap frame is not on our own kernel stack, or
|
||||
* (3) the boot thread tries to enter user mode.
|
||||
*
|
||||
* If cpustacks[] is corrupted, the next trap back to the
|
||||
* kernel will (most likely) hang the system, so it's better
|
||||
* to find out now.
|
||||
*
|
||||
* It's necessary for the trap frame used here to be on the
|
||||
* current thread's own stack. It cannot correctly be on
|
||||
* either another thread's stack or in the kernel heap.
|
||||
* (Exercise: why?)
|
||||
*/
|
||||
KASSERT(SAME_STACK(cpustacks[curcpu->c_number] - 1, (vaddr_t)tf));
|
||||
|
||||
/*
|
||||
* This actually does it. See exception-*.S.
|
||||
*/
|
||||
asm_usermode(tf);
|
||||
/*
|
||||
* This actually does it. See exception-*.S.
|
||||
*/
|
||||
asm_usermode(tf);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -419,20 +398,18 @@ mips_usermode(struct trapframe *tf)
|
||||
*
|
||||
* Works by creating an ersatz trapframe.
|
||||
*/
|
||||
void
|
||||
enter_new_process(int argc, userptr_t argv, userptr_t env,
|
||||
vaddr_t stack, vaddr_t entry)
|
||||
{
|
||||
struct trapframe tf;
|
||||
void enter_new_process(int argc, userptr_t argv, userptr_t env, vaddr_t stack,
|
||||
vaddr_t entry) {
|
||||
struct trapframe tf;
|
||||
|
||||
bzero(&tf, sizeof(tf));
|
||||
bzero(&tf, sizeof(tf));
|
||||
|
||||
tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp;
|
||||
tf.tf_epc = entry;
|
||||
tf.tf_a0 = argc;
|
||||
tf.tf_a1 = (vaddr_t)argv;
|
||||
tf.tf_a2 = (vaddr_t)env;
|
||||
tf.tf_sp = stack;
|
||||
tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp;
|
||||
tf.tf_epc = entry;
|
||||
tf.tf_a0 = argc;
|
||||
tf.tf_a1 = (vaddr_t)argv;
|
||||
tf.tf_a2 = (vaddr_t)env;
|
||||
tf.tf_sp = stack;
|
||||
|
||||
mips_usermode(&tf);
|
||||
mips_usermode(&tf);
|
||||
}
|
||||
|
@ -36,7 +36,6 @@
|
||||
#include <current.h>
|
||||
#include <syscall.h>
|
||||
|
||||
|
||||
/*
|
||||
* System call dispatcher.
|
||||
*
|
||||
@ -75,75 +74,70 @@
|
||||
* stack, starting at sp+16 to skip over the slots for the
|
||||
* registerized values, with copyin().
|
||||
*/
|
||||
void
|
||||
syscall(struct trapframe *tf)
|
||||
{
|
||||
int callno;
|
||||
int32_t retval;
|
||||
int err;
|
||||
void syscall(struct trapframe *tf) {
|
||||
int callno;
|
||||
int32_t retval;
|
||||
int err;
|
||||
|
||||
KASSERT(curthread != NULL);
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
KASSERT(curthread != NULL);
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
|
||||
callno = tf->tf_v0;
|
||||
callno = tf->tf_v0;
|
||||
|
||||
/*
|
||||
* Initialize retval to 0. Many of the system calls don't
|
||||
* really return a value, just 0 for success and -1 on
|
||||
* error. Since retval is the value returned on success,
|
||||
* initialize it to 0 by default; thus it's not necessary to
|
||||
* deal with it except for calls that return other values,
|
||||
* like write.
|
||||
*/
|
||||
/*
|
||||
* Initialize retval to 0. Many of the system calls don't
|
||||
* really return a value, just 0 for success and -1 on
|
||||
* error. Since retval is the value returned on success,
|
||||
* initialize it to 0 by default; thus it's not necessary to
|
||||
* deal with it except for calls that return other values,
|
||||
* like write.
|
||||
*/
|
||||
|
||||
retval = 0;
|
||||
retval = 0;
|
||||
|
||||
switch (callno) {
|
||||
case SYS_reboot:
|
||||
err = sys_reboot(tf->tf_a0);
|
||||
break;
|
||||
switch (callno) {
|
||||
case SYS_reboot:
|
||||
err = sys_reboot(tf->tf_a0);
|
||||
break;
|
||||
|
||||
case SYS___time:
|
||||
err = sys___time((userptr_t)tf->tf_a0,
|
||||
(userptr_t)tf->tf_a1);
|
||||
break;
|
||||
case SYS___time:
|
||||
err = sys___time((userptr_t)tf->tf_a0, (userptr_t)tf->tf_a1);
|
||||
break;
|
||||
|
||||
/* Add stuff here */
|
||||
/* Add stuff here */
|
||||
|
||||
default:
|
||||
kprintf("Unknown syscall %d\n", callno);
|
||||
err = ENOSYS;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
kprintf("Unknown syscall %d\n", callno);
|
||||
err = ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
/*
|
||||
* Return the error code. This gets converted at
|
||||
* userlevel to a return value of -1 and the error
|
||||
* code in errno.
|
||||
*/
|
||||
tf->tf_v0 = err;
|
||||
tf->tf_a3 = 1; /* signal an error */
|
||||
} else {
|
||||
/* Success. */
|
||||
tf->tf_v0 = retval;
|
||||
tf->tf_a3 = 0; /* signal no error */
|
||||
}
|
||||
|
||||
if (err) {
|
||||
/*
|
||||
* Return the error code. This gets converted at
|
||||
* userlevel to a return value of -1 and the error
|
||||
* code in errno.
|
||||
*/
|
||||
tf->tf_v0 = err;
|
||||
tf->tf_a3 = 1; /* signal an error */
|
||||
}
|
||||
else {
|
||||
/* Success. */
|
||||
tf->tf_v0 = retval;
|
||||
tf->tf_a3 = 0; /* signal no error */
|
||||
}
|
||||
/*
|
||||
* Now, advance the program counter, to avoid restarting
|
||||
* the syscall over and over again.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Now, advance the program counter, to avoid restarting
|
||||
* the syscall over and over again.
|
||||
*/
|
||||
tf->tf_epc += 4;
|
||||
|
||||
tf->tf_epc += 4;
|
||||
|
||||
/* Make sure the syscall code didn't forget to lower spl */
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
/* ...or leak any spinlocks */
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
/* Make sure the syscall code didn't forget to lower spl */
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
/* ...or leak any spinlocks */
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -154,8 +148,4 @@ syscall(struct trapframe *tf)
|
||||
*
|
||||
* Thus, you can trash it and do things another way if you prefer.
|
||||
*/
|
||||
void
|
||||
enter_forked_process(struct trapframe *tf)
|
||||
{
|
||||
(void)tf;
|
||||
}
|
||||
void enter_forked_process(struct trapframe *tf) { (void)tf; }
|
||||
|
@ -72,30 +72,27 @@ vaddr_t cputhreads[MAXCPUS];
|
||||
* associated with a new cpu. Note that we're not running on the new
|
||||
* cpu when this is called.
|
||||
*/
|
||||
void
|
||||
cpu_machdep_init(struct cpu *c)
|
||||
{
|
||||
vaddr_t stackpointer;
|
||||
void cpu_machdep_init(struct cpu *c) {
|
||||
vaddr_t stackpointer;
|
||||
|
||||
KASSERT(c->c_number < MAXCPUS);
|
||||
KASSERT(c->c_number < MAXCPUS);
|
||||
|
||||
if (c->c_curthread->t_stack == NULL) {
|
||||
/* boot cpu; don't need to do anything here */
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Stick the stack in cpustacks[], and thread pointer
|
||||
* in cputhreads[].
|
||||
*/
|
||||
if (c->c_curthread->t_stack == NULL) {
|
||||
/* boot cpu; don't need to do anything here */
|
||||
} else {
|
||||
/*
|
||||
* Stick the stack in cpustacks[], and thread pointer
|
||||
* in cputhreads[].
|
||||
*/
|
||||
|
||||
/* stack base address */
|
||||
stackpointer = (vaddr_t) c->c_curthread->t_stack;
|
||||
/* since stacks grow down, get the top */
|
||||
stackpointer += STACK_SIZE;
|
||||
/* stack base address */
|
||||
stackpointer = (vaddr_t)c->c_curthread->t_stack;
|
||||
/* since stacks grow down, get the top */
|
||||
stackpointer += STACK_SIZE;
|
||||
|
||||
cpustacks[c->c_number] = stackpointer;
|
||||
cputhreads[c->c_number] = (vaddr_t)c->c_curthread;
|
||||
}
|
||||
cpustacks[c->c_number] = stackpointer;
|
||||
cputhreads[c->c_number] = (vaddr_t)c->c_curthread;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -107,73 +104,61 @@ cpu_machdep_init(struct cpu *c)
|
||||
* System/161 processor-ID values.
|
||||
*/
|
||||
|
||||
#define SYS161_PRID_ORIG 0x000003ff
|
||||
#define SYS161_PRID_2X 0x000000a1
|
||||
#define SYS161_PRID_ORIG 0x000003ff
|
||||
#define SYS161_PRID_2X 0x000000a1
|
||||
|
||||
static inline
|
||||
uint32_t
|
||||
cpu_getprid(void)
|
||||
{
|
||||
uint32_t prid;
|
||||
static inline uint32_t cpu_getprid(void) {
|
||||
uint32_t prid;
|
||||
|
||||
__asm volatile("mfc0 %0,$15" : "=r" (prid));
|
||||
return prid;
|
||||
__asm volatile("mfc0 %0,$15" : "=r"(prid));
|
||||
return prid;
|
||||
}
|
||||
|
||||
static inline
|
||||
uint32_t
|
||||
cpu_getfeatures(void)
|
||||
{
|
||||
uint32_t features;
|
||||
static inline uint32_t cpu_getfeatures(void) {
|
||||
uint32_t features;
|
||||
|
||||
__asm volatile(".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow mips32 instructions */
|
||||
"mfc0 %0,$15,1;" /* get cop0 reg 15 sel 1 */
|
||||
".set pop" /* restore assembler mode */
|
||||
: "=r" (features));
|
||||
return features;
|
||||
__asm volatile(".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow mips32 instructions */
|
||||
"mfc0 %0,$15,1;" /* get cop0 reg 15 sel 1 */
|
||||
".set pop" /* restore assembler mode */
|
||||
: "=r"(features));
|
||||
return features;
|
||||
}
|
||||
|
||||
static inline
|
||||
uint32_t
|
||||
cpu_getifeatures(void)
|
||||
{
|
||||
uint32_t features;
|
||||
static inline uint32_t cpu_getifeatures(void) {
|
||||
uint32_t features;
|
||||
|
||||
__asm volatile(".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow mips32 instructions */
|
||||
"mfc0 %0,$15,2;" /* get cop0 reg 15 sel 2 */
|
||||
".set pop" /* restore assembler mode */
|
||||
: "=r" (features));
|
||||
return features;
|
||||
__asm volatile(".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow mips32 instructions */
|
||||
"mfc0 %0,$15,2;" /* get cop0 reg 15 sel 2 */
|
||||
".set pop" /* restore assembler mode */
|
||||
: "=r"(features));
|
||||
return features;
|
||||
}
|
||||
|
||||
void
|
||||
cpu_identify(char *buf, size_t max)
|
||||
{
|
||||
uint32_t prid;
|
||||
uint32_t features;
|
||||
void cpu_identify(char *buf, size_t max) {
|
||||
uint32_t prid;
|
||||
uint32_t features;
|
||||
|
||||
prid = cpu_getprid();
|
||||
switch (prid) {
|
||||
case SYS161_PRID_ORIG:
|
||||
snprintf(buf, max, "MIPS/161 (System/161 1.x and pre-2.x)");
|
||||
break;
|
||||
case SYS161_PRID_2X:
|
||||
features = cpu_getfeatures();
|
||||
snprintf(buf, max, "MIPS/161 (System/161 2.x) features 0x%x",
|
||||
features);
|
||||
features = cpu_getifeatures();
|
||||
if (features != 0) {
|
||||
kprintf("WARNING: unknown CPU incompatible features "
|
||||
"0x%x\n", features);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, max, "32-bit MIPS (unknown type, CPU ID 0x%x)",
|
||||
prid);
|
||||
break;
|
||||
}
|
||||
prid = cpu_getprid();
|
||||
switch (prid) {
|
||||
case SYS161_PRID_ORIG:
|
||||
snprintf(buf, max, "MIPS/161 (System/161 1.x and pre-2.x)");
|
||||
break;
|
||||
case SYS161_PRID_2X:
|
||||
features = cpu_getfeatures();
|
||||
snprintf(buf, max, "MIPS/161 (System/161 2.x) features 0x%x", features);
|
||||
features = cpu_getifeatures();
|
||||
if (features != 0) {
|
||||
kprintf("WARNING: unknown CPU incompatible features "
|
||||
"0x%x\n",
|
||||
features);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, max, "32-bit MIPS (unknown type, CPU ID 0x%x)", prid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -200,50 +185,43 @@ cpu_identify(char *buf, size_t max)
|
||||
* These considerations do not (currently) apply to System/161,
|
||||
* however.
|
||||
*/
|
||||
#define GET_STATUS(x) __asm volatile("mfc0 %0,$12" : "=r" (x))
|
||||
#define SET_STATUS(x) __asm volatile("mtc0 %0,$12" :: "r" (x))
|
||||
#define GET_STATUS(x) __asm volatile("mfc0 %0,$12" : "=r"(x))
|
||||
#define SET_STATUS(x) __asm volatile("mtc0 %0,$12" ::"r"(x))
|
||||
|
||||
/*
|
||||
* Interrupts on.
|
||||
*/
|
||||
void
|
||||
cpu_irqon(void)
|
||||
{
|
||||
uint32_t x;
|
||||
void cpu_irqon(void) {
|
||||
uint32_t x;
|
||||
|
||||
GET_STATUS(x);
|
||||
x |= CST_IEc;
|
||||
SET_STATUS(x);
|
||||
GET_STATUS(x);
|
||||
x |= CST_IEc;
|
||||
SET_STATUS(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupts off.
|
||||
*/
|
||||
void
|
||||
cpu_irqoff(void)
|
||||
{
|
||||
uint32_t x;
|
||||
void cpu_irqoff(void) {
|
||||
uint32_t x;
|
||||
|
||||
GET_STATUS(x);
|
||||
x &= ~(uint32_t)CST_IEc;
|
||||
SET_STATUS(x);
|
||||
GET_STATUS(x);
|
||||
x &= ~(uint32_t)CST_IEc;
|
||||
SET_STATUS(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used below.
|
||||
*/
|
||||
static
|
||||
void
|
||||
cpu_irqonoff(void)
|
||||
{
|
||||
uint32_t x, xon, xoff;
|
||||
static void cpu_irqonoff(void) {
|
||||
uint32_t x, xon, xoff;
|
||||
|
||||
GET_STATUS(x);
|
||||
xon = x | CST_IEc;
|
||||
xoff = x & ~(uint32_t)CST_IEc;
|
||||
SET_STATUS(xon);
|
||||
__asm volatile("nop; nop; nop; nop");
|
||||
SET_STATUS(xoff);
|
||||
GET_STATUS(x);
|
||||
xon = x | CST_IEc;
|
||||
xoff = x & ~(uint32_t)CST_IEc;
|
||||
SET_STATUS(xon);
|
||||
__asm volatile("nop; nop; nop; nop");
|
||||
SET_STATUS(xoff);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -261,49 +239,40 @@ cpu_irqonoff(void)
|
||||
* appropriate the mips32 WAIT instruction.
|
||||
*/
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
wait(void)
|
||||
{
|
||||
/*
|
||||
* The WAIT instruction goes into powersave mode until an
|
||||
* interrupt is trying to occur.
|
||||
*
|
||||
* Then switch interrupts on and off again, so we actually
|
||||
* take the interrupt.
|
||||
*
|
||||
* Note that the precise behavior of this instruction in the
|
||||
* System/161 simulator is partly guesswork. This code may not
|
||||
* work on a real mips.
|
||||
*/
|
||||
__asm volatile(
|
||||
".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow MIPS32 instructions */
|
||||
".set volatile;" /* avoid unwanted optimization */
|
||||
"wait;" /* suspend until interrupted */
|
||||
".set pop" /* restore assembler mode */
|
||||
);
|
||||
static inline void wait(void) {
|
||||
/*
|
||||
* The WAIT instruction goes into powersave mode until an
|
||||
* interrupt is trying to occur.
|
||||
*
|
||||
* Then switch interrupts on and off again, so we actually
|
||||
* take the interrupt.
|
||||
*
|
||||
* Note that the precise behavior of this instruction in the
|
||||
* System/161 simulator is partly guesswork. This code may not
|
||||
* work on a real mips.
|
||||
*/
|
||||
__asm volatile(".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow MIPS32 instructions */
|
||||
".set volatile;" /* avoid unwanted optimization */
|
||||
"wait;" /* suspend until interrupted */
|
||||
".set pop" /* restore assembler mode */
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Idle the processor until something happens.
|
||||
*/
|
||||
void
|
||||
cpu_idle(void)
|
||||
{
|
||||
wait();
|
||||
cpu_irqonoff();
|
||||
void cpu_idle(void) {
|
||||
wait();
|
||||
cpu_irqonoff();
|
||||
}
|
||||
|
||||
/*
|
||||
* Halt the CPU permanently.
|
||||
*/
|
||||
void
|
||||
cpu_halt(void)
|
||||
{
|
||||
cpu_irqoff();
|
||||
while (1) {
|
||||
wait();
|
||||
}
|
||||
void cpu_halt(void) {
|
||||
cpu_irqoff();
|
||||
while (1) {
|
||||
wait();
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,6 @@
|
||||
/* in threadstart.S */
|
||||
extern void mips_threadstart(/* arguments are in unusual registers */);
|
||||
|
||||
|
||||
/*
|
||||
* Function to initialize the switchframe of a new thread, which is
|
||||
* *not* the one that is currently running.
|
||||
@ -51,48 +50,46 @@ extern void mips_threadstart(/* arguments are in unusual registers */);
|
||||
* store the arguments in the s* registers, and use a bit of asm
|
||||
* (mips_threadstart) to move them and then jump to thread_startup.
|
||||
*/
|
||||
void
|
||||
switchframe_init(struct thread *thread,
|
||||
void (*entrypoint)(void *data1, unsigned long data2),
|
||||
void *data1, unsigned long data2)
|
||||
{
|
||||
vaddr_t stacktop;
|
||||
struct switchframe *sf;
|
||||
void switchframe_init(struct thread *thread,
|
||||
void (*entrypoint)(void *data1, unsigned long data2),
|
||||
void *data1, unsigned long data2) {
|
||||
vaddr_t stacktop;
|
||||
struct switchframe *sf;
|
||||
|
||||
/*
|
||||
* MIPS stacks grow down. t_stack is just a hunk of memory, so
|
||||
* get the other end of it. Then set up a switchframe on the
|
||||
* top of the stack.
|
||||
*/
|
||||
stacktop = ((vaddr_t)thread->t_stack) + STACK_SIZE;
|
||||
sf = ((struct switchframe *) stacktop) - 1;
|
||||
/*
|
||||
* MIPS stacks grow down. t_stack is just a hunk of memory, so
|
||||
* get the other end of it. Then set up a switchframe on the
|
||||
* top of the stack.
|
||||
*/
|
||||
stacktop = ((vaddr_t)thread->t_stack) + STACK_SIZE;
|
||||
sf = ((struct switchframe *)stacktop) - 1;
|
||||
|
||||
/* Zero out the switchframe. */
|
||||
bzero(sf, sizeof(*sf));
|
||||
/* Zero out the switchframe. */
|
||||
bzero(sf, sizeof(*sf));
|
||||
|
||||
/*
|
||||
* Now set the important parts: pass through the three arguments,
|
||||
* and set the return address register to the place we want
|
||||
* execution to begin.
|
||||
*
|
||||
* Thus, when switchframe_switch does its "j ra", it will
|
||||
* actually jump to mips_threadstart, which will move the
|
||||
* arguments into the right register and jump to
|
||||
* thread_startup().
|
||||
*
|
||||
* Note that this means that when we call switchframe_switch()
|
||||
* in thread_switch(), we may not come back out the same way
|
||||
* in the next thread. (Though we will come back out the same
|
||||
* way when we later come back to the same thread again.)
|
||||
*
|
||||
* This has implications for code at the bottom of
|
||||
* thread_switch, described in thread.c.
|
||||
*/
|
||||
sf->sf_s0 = (uint32_t)entrypoint;
|
||||
sf->sf_s1 = (uint32_t)data1;
|
||||
sf->sf_s2 = (uint32_t)data2;
|
||||
sf->sf_ra = (uint32_t)mips_threadstart;
|
||||
/*
|
||||
* Now set the important parts: pass through the three arguments,
|
||||
* and set the return address register to the place we want
|
||||
* execution to begin.
|
||||
*
|
||||
* Thus, when switchframe_switch does its "j ra", it will
|
||||
* actually jump to mips_threadstart, which will move the
|
||||
* arguments into the right register and jump to
|
||||
* thread_startup().
|
||||
*
|
||||
* Note that this means that when we call switchframe_switch()
|
||||
* in thread_switch(), we may not come back out the same way
|
||||
* in the next thread. (Though we will come back out the same
|
||||
* way when we later come back to the same thread again.)
|
||||
*
|
||||
* This has implications for code at the bottom of
|
||||
* thread_switch, described in thread.c.
|
||||
*/
|
||||
sf->sf_s0 = (uint32_t)entrypoint;
|
||||
sf->sf_s1 = (uint32_t)data1;
|
||||
sf->sf_s2 = (uint32_t)data2;
|
||||
sf->sf_ra = (uint32_t)mips_threadstart;
|
||||
|
||||
/* Set ->t_context, and we're done. */
|
||||
thread->t_context = sf;
|
||||
/* Set ->t_context, and we're done. */
|
||||
thread->t_context = sf;
|
||||
}
|
||||
|
@ -37,16 +37,16 @@
|
||||
*/
|
||||
|
||||
struct switchframe {
|
||||
uint32_t sf_s0;
|
||||
uint32_t sf_s1;
|
||||
uint32_t sf_s2;
|
||||
uint32_t sf_s3;
|
||||
uint32_t sf_s4;
|
||||
uint32_t sf_s5;
|
||||
uint32_t sf_s6;
|
||||
uint32_t sf_s8;
|
||||
uint32_t sf_gp;
|
||||
uint32_t sf_ra;
|
||||
uint32_t sf_s0;
|
||||
uint32_t sf_s1;
|
||||
uint32_t sf_s2;
|
||||
uint32_t sf_s3;
|
||||
uint32_t sf_s4;
|
||||
uint32_t sf_s5;
|
||||
uint32_t sf_s6;
|
||||
uint32_t sf_s8;
|
||||
uint32_t sf_gp;
|
||||
uint32_t sf_ra;
|
||||
};
|
||||
|
||||
#endif /* _MIPS_SWITCHFRAME_H_ */
|
||||
|
@ -36,14 +36,10 @@
|
||||
#include <thread.h>
|
||||
#include <threadprivate.h>
|
||||
|
||||
void
|
||||
thread_machdep_init(struct thread_machdep *tm)
|
||||
{
|
||||
tm->tm_badfaultfunc = NULL;
|
||||
void thread_machdep_init(struct thread_machdep *tm) {
|
||||
tm->tm_badfaultfunc = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
thread_machdep_cleanup(struct thread_machdep *tm)
|
||||
{
|
||||
KASSERT(tm->tm_badfaultfunc == NULL);
|
||||
void thread_machdep_cleanup(struct thread_machdep *tm) {
|
||||
KASSERT(tm->tm_badfaultfunc == NULL);
|
||||
}
|
||||
|
@ -57,18 +57,14 @@
|
||||
|
||||
/* under dumbvm, always have 72k of user stack */
|
||||
/* (this must be > 64K so argument blocks of size ARG_MAX will fit) */
|
||||
#define DUMBVM_STACKPAGES 18
|
||||
#define DUMBVM_STACKPAGES 18
|
||||
|
||||
/*
|
||||
* Wrap ram_stealmem in a spinlock.
|
||||
*/
|
||||
static struct spinlock stealmem_lock = SPINLOCK_INITIALIZER;
|
||||
|
||||
void
|
||||
vm_bootstrap(void)
|
||||
{
|
||||
/* Do nothing. */
|
||||
}
|
||||
void vm_bootstrap(void) { /* Do nothing. */ }
|
||||
|
||||
/*
|
||||
* Check if we're in a context that can sleep. While most of the
|
||||
@ -77,351 +73,311 @@ vm_bootstrap(void)
|
||||
* avoid the situation where syscall-layer code that works ok with
|
||||
* dumbvm starts blowing up during the VM assignment.
|
||||
*/
|
||||
static
|
||||
void
|
||||
dumbvm_can_sleep(void)
|
||||
{
|
||||
if (CURCPU_EXISTS()) {
|
||||
/* must not hold spinlocks */
|
||||
KASSERT(curcpu->c_spinlocks == 0);
|
||||
static void dumbvm_can_sleep(void) {
|
||||
if (CURCPU_EXISTS()) {
|
||||
/* must not hold spinlocks */
|
||||
KASSERT(curcpu->c_spinlocks == 0);
|
||||
|
||||
/* must not be in an interrupt handler */
|
||||
KASSERT(curthread->t_in_interrupt == 0);
|
||||
}
|
||||
/* must not be in an interrupt handler */
|
||||
KASSERT(curthread->t_in_interrupt == 0);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
paddr_t
|
||||
getppages(unsigned long npages)
|
||||
{
|
||||
paddr_t addr;
|
||||
static paddr_t getppages(unsigned long npages) {
|
||||
paddr_t addr;
|
||||
|
||||
spinlock_acquire(&stealmem_lock);
|
||||
spinlock_acquire(&stealmem_lock);
|
||||
|
||||
addr = ram_stealmem(npages);
|
||||
addr = ram_stealmem(npages);
|
||||
|
||||
spinlock_release(&stealmem_lock);
|
||||
return addr;
|
||||
spinlock_release(&stealmem_lock);
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* Allocate/free some kernel-space virtual pages */
|
||||
vaddr_t
|
||||
alloc_kpages(unsigned npages)
|
||||
{
|
||||
paddr_t pa;
|
||||
vaddr_t alloc_kpages(unsigned npages) {
|
||||
paddr_t pa;
|
||||
|
||||
dumbvm_can_sleep();
|
||||
pa = getppages(npages);
|
||||
if (pa==0) {
|
||||
return 0;
|
||||
}
|
||||
return PADDR_TO_KVADDR(pa);
|
||||
dumbvm_can_sleep();
|
||||
pa = getppages(npages);
|
||||
if (pa == 0) {
|
||||
return 0;
|
||||
}
|
||||
return PADDR_TO_KVADDR(pa);
|
||||
}
|
||||
|
||||
void
|
||||
free_kpages(vaddr_t addr)
|
||||
{
|
||||
/* nothing - leak the memory. */
|
||||
void free_kpages(vaddr_t addr) {
|
||||
/* nothing - leak the memory. */
|
||||
|
||||
(void)addr;
|
||||
(void)addr;
|
||||
}
|
||||
|
||||
void
|
||||
vm_tlbshootdown(const struct tlbshootdown *ts)
|
||||
{
|
||||
(void)ts;
|
||||
panic("dumbvm tried to do tlb shootdown?!\n");
|
||||
void vm_tlbshootdown(const struct tlbshootdown *ts) {
|
||||
(void)ts;
|
||||
panic("dumbvm tried to do tlb shootdown?!\n");
|
||||
}
|
||||
|
||||
int
|
||||
vm_fault(int faulttype, vaddr_t faultaddress)
|
||||
{
|
||||
vaddr_t vbase1, vtop1, vbase2, vtop2, stackbase, stacktop;
|
||||
paddr_t paddr;
|
||||
int i;
|
||||
uint32_t ehi, elo;
|
||||
struct addrspace *as;
|
||||
int spl;
|
||||
int vm_fault(int faulttype, vaddr_t faultaddress) {
|
||||
vaddr_t vbase1, vtop1, vbase2, vtop2, stackbase, stacktop;
|
||||
paddr_t paddr;
|
||||
int i;
|
||||
uint32_t ehi, elo;
|
||||
struct addrspace *as;
|
||||
int spl;
|
||||
|
||||
faultaddress &= PAGE_FRAME;
|
||||
faultaddress &= PAGE_FRAME;
|
||||
|
||||
DEBUG(DB_VM, "dumbvm: fault: 0x%x\n", faultaddress);
|
||||
DEBUG(DB_VM, "dumbvm: fault: 0x%x\n", faultaddress);
|
||||
|
||||
switch (faulttype) {
|
||||
case VM_FAULT_READONLY:
|
||||
/* We always create pages read-write, so we can't get this */
|
||||
panic("dumbvm: got VM_FAULT_READONLY\n");
|
||||
case VM_FAULT_READ:
|
||||
case VM_FAULT_WRITE:
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
switch (faulttype) {
|
||||
case VM_FAULT_READONLY:
|
||||
/* We always create pages read-write, so we can't get this */
|
||||
panic("dumbvm: got VM_FAULT_READONLY\n");
|
||||
case VM_FAULT_READ:
|
||||
case VM_FAULT_WRITE:
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (curproc == NULL) {
|
||||
/*
|
||||
* No process. This is probably a kernel fault early
|
||||
* in boot. Return EFAULT so as to panic instead of
|
||||
* getting into an infinite faulting loop.
|
||||
*/
|
||||
return EFAULT;
|
||||
}
|
||||
if (curproc == NULL) {
|
||||
/*
|
||||
* No process. This is probably a kernel fault early
|
||||
* in boot. Return EFAULT so as to panic instead of
|
||||
* getting into an infinite faulting loop.
|
||||
*/
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
as = proc_getas();
|
||||
if (as == NULL) {
|
||||
/*
|
||||
* No address space set up. This is probably also a
|
||||
* kernel fault early in boot.
|
||||
*/
|
||||
return EFAULT;
|
||||
}
|
||||
as = proc_getas();
|
||||
if (as == NULL) {
|
||||
/*
|
||||
* No address space set up. This is probably also a
|
||||
* kernel fault early in boot.
|
||||
*/
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
/* Assert that the address space has been set up properly. */
|
||||
KASSERT(as->as_vbase1 != 0);
|
||||
KASSERT(as->as_pbase1 != 0);
|
||||
KASSERT(as->as_npages1 != 0);
|
||||
KASSERT(as->as_vbase2 != 0);
|
||||
KASSERT(as->as_pbase2 != 0);
|
||||
KASSERT(as->as_npages2 != 0);
|
||||
KASSERT(as->as_stackpbase != 0);
|
||||
KASSERT((as->as_vbase1 & PAGE_FRAME) == as->as_vbase1);
|
||||
KASSERT((as->as_pbase1 & PAGE_FRAME) == as->as_pbase1);
|
||||
KASSERT((as->as_vbase2 & PAGE_FRAME) == as->as_vbase2);
|
||||
KASSERT((as->as_pbase2 & PAGE_FRAME) == as->as_pbase2);
|
||||
KASSERT((as->as_stackpbase & PAGE_FRAME) == as->as_stackpbase);
|
||||
/* Assert that the address space has been set up properly. */
|
||||
KASSERT(as->as_vbase1 != 0);
|
||||
KASSERT(as->as_pbase1 != 0);
|
||||
KASSERT(as->as_npages1 != 0);
|
||||
KASSERT(as->as_vbase2 != 0);
|
||||
KASSERT(as->as_pbase2 != 0);
|
||||
KASSERT(as->as_npages2 != 0);
|
||||
KASSERT(as->as_stackpbase != 0);
|
||||
KASSERT((as->as_vbase1 & PAGE_FRAME) == as->as_vbase1);
|
||||
KASSERT((as->as_pbase1 & PAGE_FRAME) == as->as_pbase1);
|
||||
KASSERT((as->as_vbase2 & PAGE_FRAME) == as->as_vbase2);
|
||||
KASSERT((as->as_pbase2 & PAGE_FRAME) == as->as_pbase2);
|
||||
KASSERT((as->as_stackpbase & PAGE_FRAME) == as->as_stackpbase);
|
||||
|
||||
vbase1 = as->as_vbase1;
|
||||
vtop1 = vbase1 + as->as_npages1 * PAGE_SIZE;
|
||||
vbase2 = as->as_vbase2;
|
||||
vtop2 = vbase2 + as->as_npages2 * PAGE_SIZE;
|
||||
stackbase = USERSTACK - DUMBVM_STACKPAGES * PAGE_SIZE;
|
||||
stacktop = USERSTACK;
|
||||
vbase1 = as->as_vbase1;
|
||||
vtop1 = vbase1 + as->as_npages1 * PAGE_SIZE;
|
||||
vbase2 = as->as_vbase2;
|
||||
vtop2 = vbase2 + as->as_npages2 * PAGE_SIZE;
|
||||
stackbase = USERSTACK - DUMBVM_STACKPAGES * PAGE_SIZE;
|
||||
stacktop = USERSTACK;
|
||||
|
||||
if (faultaddress >= vbase1 && faultaddress < vtop1) {
|
||||
paddr = (faultaddress - vbase1) + as->as_pbase1;
|
||||
}
|
||||
else if (faultaddress >= vbase2 && faultaddress < vtop2) {
|
||||
paddr = (faultaddress - vbase2) + as->as_pbase2;
|
||||
}
|
||||
else if (faultaddress >= stackbase && faultaddress < stacktop) {
|
||||
paddr = (faultaddress - stackbase) + as->as_stackpbase;
|
||||
}
|
||||
else {
|
||||
return EFAULT;
|
||||
}
|
||||
if (faultaddress >= vbase1 && faultaddress < vtop1) {
|
||||
paddr = (faultaddress - vbase1) + as->as_pbase1;
|
||||
} else if (faultaddress >= vbase2 && faultaddress < vtop2) {
|
||||
paddr = (faultaddress - vbase2) + as->as_pbase2;
|
||||
} else if (faultaddress >= stackbase && faultaddress < stacktop) {
|
||||
paddr = (faultaddress - stackbase) + as->as_stackpbase;
|
||||
} else {
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
/* make sure it's page-aligned */
|
||||
KASSERT((paddr & PAGE_FRAME) == paddr);
|
||||
/* make sure it's page-aligned */
|
||||
KASSERT((paddr & PAGE_FRAME) == paddr);
|
||||
|
||||
/* Disable interrupts on this CPU while frobbing the TLB. */
|
||||
spl = splhigh();
|
||||
/* Disable interrupts on this CPU while frobbing the TLB. */
|
||||
spl = splhigh();
|
||||
|
||||
for (i=0; i<NUM_TLB; i++) {
|
||||
tlb_read(&ehi, &elo, i);
|
||||
if (elo & TLBLO_VALID) {
|
||||
continue;
|
||||
}
|
||||
ehi = faultaddress;
|
||||
elo = paddr | TLBLO_DIRTY | TLBLO_VALID;
|
||||
DEBUG(DB_VM, "dumbvm: 0x%x -> 0x%x\n", faultaddress, paddr);
|
||||
tlb_write(ehi, elo, i);
|
||||
splx(spl);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < NUM_TLB; i++) {
|
||||
tlb_read(&ehi, &elo, i);
|
||||
if (elo & TLBLO_VALID) {
|
||||
continue;
|
||||
}
|
||||
ehi = faultaddress;
|
||||
elo = paddr | TLBLO_DIRTY | TLBLO_VALID;
|
||||
DEBUG(DB_VM, "dumbvm: 0x%x -> 0x%x\n", faultaddress, paddr);
|
||||
tlb_write(ehi, elo, i);
|
||||
splx(spl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
kprintf("dumbvm: Ran out of TLB entries - cannot handle page fault\n");
|
||||
splx(spl);
|
||||
return EFAULT;
|
||||
kprintf("dumbvm: Ran out of TLB entries - cannot handle page fault\n");
|
||||
splx(spl);
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
struct addrspace *
|
||||
as_create(void)
|
||||
{
|
||||
struct addrspace *as = kmalloc(sizeof(struct addrspace));
|
||||
if (as==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
struct addrspace *as_create(void) {
|
||||
struct addrspace *as = kmalloc(sizeof(struct addrspace));
|
||||
if (as == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
as->as_vbase1 = 0;
|
||||
as->as_pbase1 = 0;
|
||||
as->as_npages1 = 0;
|
||||
as->as_vbase2 = 0;
|
||||
as->as_pbase2 = 0;
|
||||
as->as_npages2 = 0;
|
||||
as->as_stackpbase = 0;
|
||||
as->as_vbase1 = 0;
|
||||
as->as_pbase1 = 0;
|
||||
as->as_npages1 = 0;
|
||||
as->as_vbase2 = 0;
|
||||
as->as_pbase2 = 0;
|
||||
as->as_npages2 = 0;
|
||||
as->as_stackpbase = 0;
|
||||
|
||||
return as;
|
||||
return as;
|
||||
}
|
||||
|
||||
void
|
||||
as_destroy(struct addrspace *as)
|
||||
{
|
||||
dumbvm_can_sleep();
|
||||
kfree(as);
|
||||
void as_destroy(struct addrspace *as) {
|
||||
dumbvm_can_sleep();
|
||||
kfree(as);
|
||||
}
|
||||
|
||||
void
|
||||
as_activate(void)
|
||||
{
|
||||
int i, spl;
|
||||
struct addrspace *as;
|
||||
void as_activate(void) {
|
||||
int i, spl;
|
||||
struct addrspace *as;
|
||||
|
||||
as = proc_getas();
|
||||
if (as == NULL) {
|
||||
return;
|
||||
}
|
||||
as = proc_getas();
|
||||
if (as == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disable interrupts on this CPU while frobbing the TLB. */
|
||||
spl = splhigh();
|
||||
/* Disable interrupts on this CPU while frobbing the TLB. */
|
||||
spl = splhigh();
|
||||
|
||||
for (i=0; i<NUM_TLB; i++) {
|
||||
tlb_write(TLBHI_INVALID(i), TLBLO_INVALID(), i);
|
||||
}
|
||||
for (i = 0; i < NUM_TLB; i++) {
|
||||
tlb_write(TLBHI_INVALID(i), TLBLO_INVALID(), i);
|
||||
}
|
||||
|
||||
splx(spl);
|
||||
splx(spl);
|
||||
}
|
||||
|
||||
void
|
||||
as_deactivate(void)
|
||||
{
|
||||
/* nothing */
|
||||
void as_deactivate(void) { /* nothing */ }
|
||||
|
||||
int as_define_region(struct addrspace *as, vaddr_t vaddr, size_t sz,
|
||||
int readable, int writeable, int executable) {
|
||||
size_t npages;
|
||||
|
||||
dumbvm_can_sleep();
|
||||
|
||||
/* Align the region. First, the base... */
|
||||
sz += vaddr & ~(vaddr_t)PAGE_FRAME;
|
||||
vaddr &= PAGE_FRAME;
|
||||
|
||||
/* ...and now the length. */
|
||||
sz = (sz + PAGE_SIZE - 1) & PAGE_FRAME;
|
||||
|
||||
npages = sz / PAGE_SIZE;
|
||||
|
||||
/* We don't use these - all pages are read-write */
|
||||
(void)readable;
|
||||
(void)writeable;
|
||||
(void)executable;
|
||||
|
||||
if (as->as_vbase1 == 0) {
|
||||
as->as_vbase1 = vaddr;
|
||||
as->as_npages1 = npages;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (as->as_vbase2 == 0) {
|
||||
as->as_vbase2 = vaddr;
|
||||
as->as_npages2 = npages;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for more than two regions is not available.
|
||||
*/
|
||||
kprintf("dumbvm: Warning: too many regions\n");
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
int
|
||||
as_define_region(struct addrspace *as, vaddr_t vaddr, size_t sz,
|
||||
int readable, int writeable, int executable)
|
||||
{
|
||||
size_t npages;
|
||||
|
||||
dumbvm_can_sleep();
|
||||
|
||||
/* Align the region. First, the base... */
|
||||
sz += vaddr & ~(vaddr_t)PAGE_FRAME;
|
||||
vaddr &= PAGE_FRAME;
|
||||
|
||||
/* ...and now the length. */
|
||||
sz = (sz + PAGE_SIZE - 1) & PAGE_FRAME;
|
||||
|
||||
npages = sz / PAGE_SIZE;
|
||||
|
||||
/* We don't use these - all pages are read-write */
|
||||
(void)readable;
|
||||
(void)writeable;
|
||||
(void)executable;
|
||||
|
||||
if (as->as_vbase1 == 0) {
|
||||
as->as_vbase1 = vaddr;
|
||||
as->as_npages1 = npages;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (as->as_vbase2 == 0) {
|
||||
as->as_vbase2 = vaddr;
|
||||
as->as_npages2 = npages;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for more than two regions is not available.
|
||||
*/
|
||||
kprintf("dumbvm: Warning: too many regions\n");
|
||||
return ENOSYS;
|
||||
static void as_zero_region(paddr_t paddr, unsigned npages) {
|
||||
bzero((void *)PADDR_TO_KVADDR(paddr), npages * PAGE_SIZE);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
as_zero_region(paddr_t paddr, unsigned npages)
|
||||
{
|
||||
bzero((void *)PADDR_TO_KVADDR(paddr), npages * PAGE_SIZE);
|
||||
int as_prepare_load(struct addrspace *as) {
|
||||
KASSERT(as->as_pbase1 == 0);
|
||||
KASSERT(as->as_pbase2 == 0);
|
||||
KASSERT(as->as_stackpbase == 0);
|
||||
|
||||
dumbvm_can_sleep();
|
||||
|
||||
as->as_pbase1 = getppages(as->as_npages1);
|
||||
if (as->as_pbase1 == 0) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
as->as_pbase2 = getppages(as->as_npages2);
|
||||
if (as->as_pbase2 == 0) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
as->as_stackpbase = getppages(DUMBVM_STACKPAGES);
|
||||
if (as->as_stackpbase == 0) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
as_zero_region(as->as_pbase1, as->as_npages1);
|
||||
as_zero_region(as->as_pbase2, as->as_npages2);
|
||||
as_zero_region(as->as_stackpbase, DUMBVM_STACKPAGES);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
as_prepare_load(struct addrspace *as)
|
||||
{
|
||||
KASSERT(as->as_pbase1 == 0);
|
||||
KASSERT(as->as_pbase2 == 0);
|
||||
KASSERT(as->as_stackpbase == 0);
|
||||
|
||||
dumbvm_can_sleep();
|
||||
|
||||
as->as_pbase1 = getppages(as->as_npages1);
|
||||
if (as->as_pbase1 == 0) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
as->as_pbase2 = getppages(as->as_npages2);
|
||||
if (as->as_pbase2 == 0) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
as->as_stackpbase = getppages(DUMBVM_STACKPAGES);
|
||||
if (as->as_stackpbase == 0) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
as_zero_region(as->as_pbase1, as->as_npages1);
|
||||
as_zero_region(as->as_pbase2, as->as_npages2);
|
||||
as_zero_region(as->as_stackpbase, DUMBVM_STACKPAGES);
|
||||
|
||||
return 0;
|
||||
int as_complete_load(struct addrspace *as) {
|
||||
dumbvm_can_sleep();
|
||||
(void)as;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
as_complete_load(struct addrspace *as)
|
||||
{
|
||||
dumbvm_can_sleep();
|
||||
(void)as;
|
||||
return 0;
|
||||
int as_define_stack(struct addrspace *as, vaddr_t *stackptr) {
|
||||
KASSERT(as->as_stackpbase != 0);
|
||||
|
||||
*stackptr = USERSTACK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
as_define_stack(struct addrspace *as, vaddr_t *stackptr)
|
||||
{
|
||||
KASSERT(as->as_stackpbase != 0);
|
||||
int as_copy(struct addrspace *old, struct addrspace **ret) {
|
||||
struct addrspace *new;
|
||||
|
||||
*stackptr = USERSTACK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
as_copy(struct addrspace *old, struct addrspace **ret)
|
||||
{
|
||||
struct addrspace *new;
|
||||
|
||||
dumbvm_can_sleep();
|
||||
|
||||
new = as_create();
|
||||
if (new==NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
new->as_vbase1 = old->as_vbase1;
|
||||
new->as_npages1 = old->as_npages1;
|
||||
new->as_vbase2 = old->as_vbase2;
|
||||
new->as_npages2 = old->as_npages2;
|
||||
|
||||
/* (Mis)use as_prepare_load to allocate some physical memory. */
|
||||
if (as_prepare_load(new)) {
|
||||
as_destroy(new);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
KASSERT(new->as_pbase1 != 0);
|
||||
KASSERT(new->as_pbase2 != 0);
|
||||
KASSERT(new->as_stackpbase != 0);
|
||||
|
||||
memmove((void *)PADDR_TO_KVADDR(new->as_pbase1),
|
||||
(const void *)PADDR_TO_KVADDR(old->as_pbase1),
|
||||
old->as_npages1*PAGE_SIZE);
|
||||
|
||||
memmove((void *)PADDR_TO_KVADDR(new->as_pbase2),
|
||||
(const void *)PADDR_TO_KVADDR(old->as_pbase2),
|
||||
old->as_npages2*PAGE_SIZE);
|
||||
|
||||
memmove((void *)PADDR_TO_KVADDR(new->as_stackpbase),
|
||||
(const void *)PADDR_TO_KVADDR(old->as_stackpbase),
|
||||
DUMBVM_STACKPAGES*PAGE_SIZE);
|
||||
|
||||
*ret = new;
|
||||
return 0;
|
||||
dumbvm_can_sleep();
|
||||
|
||||
new = as_create();
|
||||
if (new == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
new->as_vbase1 = old->as_vbase1;
|
||||
new->as_npages1 = old->as_npages1;
|
||||
new->as_vbase2 = old->as_vbase2;
|
||||
new->as_npages2 = old->as_npages2;
|
||||
|
||||
/* (Mis)use as_prepare_load to allocate some physical memory. */
|
||||
if (as_prepare_load(new)) {
|
||||
as_destroy(new);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
KASSERT(new->as_pbase1 != 0);
|
||||
KASSERT(new->as_pbase2 != 0);
|
||||
KASSERT(new->as_stackpbase != 0);
|
||||
|
||||
memmove((void *)PADDR_TO_KVADDR(new->as_pbase1),
|
||||
(const void *)PADDR_TO_KVADDR(old->as_pbase1),
|
||||
old->as_npages1 * PAGE_SIZE);
|
||||
|
||||
memmove((void *)PADDR_TO_KVADDR(new->as_pbase2),
|
||||
(const void *)PADDR_TO_KVADDR(old->as_pbase2),
|
||||
old->as_npages2 * PAGE_SIZE);
|
||||
|
||||
memmove((void *)PADDR_TO_KVADDR(new->as_stackpbase),
|
||||
(const void *)PADDR_TO_KVADDR(old->as_stackpbase),
|
||||
DUMBVM_STACKPAGES * PAGE_SIZE);
|
||||
|
||||
*ret = new;
|
||||
return 0;
|
||||
}
|
||||
|
@ -32,45 +32,41 @@
|
||||
#include <vm.h>
|
||||
#include <mainbus.h>
|
||||
|
||||
vaddr_t firstfree; /* first free virtual address; set by start.S */
|
||||
|
||||
vaddr_t firstfree; /* first free virtual address; set by start.S */
|
||||
|
||||
static paddr_t firstpaddr; /* address of first free physical page */
|
||||
static paddr_t lastpaddr; /* one past end of last free physical page */
|
||||
static paddr_t firstpaddr; /* address of first free physical page */
|
||||
static paddr_t lastpaddr; /* one past end of last free physical page */
|
||||
|
||||
/*
|
||||
* Called very early in system boot to figure out how much physical
|
||||
* RAM is available.
|
||||
*/
|
||||
void
|
||||
ram_bootstrap(void)
|
||||
{
|
||||
size_t ramsize;
|
||||
void ram_bootstrap(void) {
|
||||
size_t ramsize;
|
||||
|
||||
/* Get size of RAM. */
|
||||
ramsize = mainbus_ramsize();
|
||||
/* Get size of RAM. */
|
||||
ramsize = mainbus_ramsize();
|
||||
|
||||
/*
|
||||
* This is the same as the last physical address, as long as
|
||||
* we have less than 512 megabytes of memory. If we had more,
|
||||
* we wouldn't be able to access it all through kseg0 and
|
||||
* everything would get a lot more complicated. This is not a
|
||||
* case we are going to worry about.
|
||||
*/
|
||||
if (ramsize > 512*1024*1024) {
|
||||
ramsize = 512*1024*1024;
|
||||
}
|
||||
/*
|
||||
* This is the same as the last physical address, as long as
|
||||
* we have less than 512 megabytes of memory. If we had more,
|
||||
* we wouldn't be able to access it all through kseg0 and
|
||||
* everything would get a lot more complicated. This is not a
|
||||
* case we are going to worry about.
|
||||
*/
|
||||
if (ramsize > 512 * 1024 * 1024) {
|
||||
ramsize = 512 * 1024 * 1024;
|
||||
}
|
||||
|
||||
lastpaddr = ramsize;
|
||||
lastpaddr = ramsize;
|
||||
|
||||
/*
|
||||
* Get first free virtual address from where start.S saved it.
|
||||
* Convert to physical address.
|
||||
*/
|
||||
firstpaddr = firstfree - MIPS_KSEG0;
|
||||
/*
|
||||
* Get first free virtual address from where start.S saved it.
|
||||
* Convert to physical address.
|
||||
*/
|
||||
firstpaddr = firstfree - MIPS_KSEG0;
|
||||
|
||||
kprintf("%uk physical memory available\n",
|
||||
(lastpaddr-firstpaddr)/1024);
|
||||
kprintf("%uk physical memory available\n", (lastpaddr - firstpaddr) / 1024);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -91,22 +87,20 @@ ram_bootstrap(void)
|
||||
* This function should not be called once the VM system is initialized,
|
||||
* so it is not synchronized.
|
||||
*/
|
||||
paddr_t
|
||||
ram_stealmem(unsigned long npages)
|
||||
{
|
||||
size_t size;
|
||||
paddr_t paddr;
|
||||
paddr_t ram_stealmem(unsigned long npages) {
|
||||
size_t size;
|
||||
paddr_t paddr;
|
||||
|
||||
size = npages * PAGE_SIZE;
|
||||
size = npages * PAGE_SIZE;
|
||||
|
||||
if (firstpaddr + size > lastpaddr) {
|
||||
return 0;
|
||||
}
|
||||
if (firstpaddr + size > lastpaddr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
paddr = firstpaddr;
|
||||
firstpaddr += size;
|
||||
paddr = firstpaddr;
|
||||
firstpaddr += size;
|
||||
|
||||
return paddr;
|
||||
return paddr;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -124,11 +118,7 @@ ram_stealmem(unsigned long npages)
|
||||
* initialize the VM system, after which the VM system should take
|
||||
* charge of knowing what memory exists.
|
||||
*/
|
||||
paddr_t
|
||||
ram_getsize(void)
|
||||
{
|
||||
return lastpaddr;
|
||||
}
|
||||
paddr_t ram_getsize(void) { return lastpaddr; }
|
||||
|
||||
/*
|
||||
* This function is intended to be called by the VM system when it
|
||||
@ -142,12 +132,10 @@ ram_getsize(void)
|
||||
* This function should not be called once the VM system is initialized,
|
||||
* so it is not synchronized.
|
||||
*/
|
||||
paddr_t
|
||||
ram_getfirstfree(void)
|
||||
{
|
||||
paddr_t ret;
|
||||
paddr_t ram_getfirstfree(void) {
|
||||
paddr_t ret;
|
||||
|
||||
ret = firstpaddr;
|
||||
firstpaddr = lastpaddr = 0;
|
||||
return ret;
|
||||
ret = firstpaddr;
|
||||
firstpaddr = lastpaddr = 0;
|
||||
return ret;
|
||||
}
|
||||
|
@ -60,20 +60,16 @@
|
||||
* matches the c0_compare register, the timer interrupt line is
|
||||
* asserted. Writing to c0_compare again clears the interrupt.
|
||||
*/
|
||||
static
|
||||
void
|
||||
mips_timer_set(uint32_t count)
|
||||
{
|
||||
/*
|
||||
* $11 == c0_compare; we can't use the symbolic name inside
|
||||
* the asm string.
|
||||
*/
|
||||
__asm volatile(
|
||||
".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow MIPS32 registers */
|
||||
"mtc0 %0, $11;" /* do it */
|
||||
".set pop" /* restore assembler mode */
|
||||
:: "r" (count));
|
||||
static void mips_timer_set(uint32_t count) {
|
||||
/*
|
||||
* $11 == c0_compare; we can't use the symbolic name inside
|
||||
* the asm string.
|
||||
*/
|
||||
__asm volatile(".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow MIPS32 registers */
|
||||
"mtc0 %0, $11;" /* do it */
|
||||
".set pop" /* restore assembler mode */
|
||||
::"r"(count));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -83,138 +79,122 @@ mips_timer_set(uint32_t count)
|
||||
*/
|
||||
static struct lamebus_softc *lamebus;
|
||||
|
||||
void
|
||||
mainbus_bootstrap(void)
|
||||
{
|
||||
/* Interrupts should be off (and have been off since startup) */
|
||||
KASSERT(curthread->t_curspl > 0);
|
||||
void mainbus_bootstrap(void) {
|
||||
/* Interrupts should be off (and have been off since startup) */
|
||||
KASSERT(curthread->t_curspl > 0);
|
||||
|
||||
/* Initialize the system LAMEbus data */
|
||||
lamebus = lamebus_init();
|
||||
/* Initialize the system LAMEbus data */
|
||||
lamebus = lamebus_init();
|
||||
|
||||
/* Probe CPUs (should these be done as device attachments instead?) */
|
||||
lamebus_find_cpus(lamebus);
|
||||
/* Probe CPUs (should these be done as device attachments instead?) */
|
||||
lamebus_find_cpus(lamebus);
|
||||
|
||||
/*
|
||||
* Print the device name for the main bus.
|
||||
*/
|
||||
kprintf("lamebus0 (system main bus)\n");
|
||||
/*
|
||||
* Print the device name for the main bus.
|
||||
*/
|
||||
kprintf("lamebus0 (system main bus)\n");
|
||||
|
||||
/*
|
||||
* Now we can take interrupts without croaking, so turn them on.
|
||||
* Some device probes might require being able to get interrupts.
|
||||
*/
|
||||
/*
|
||||
* Now we can take interrupts without croaking, so turn them on.
|
||||
* Some device probes might require being able to get interrupts.
|
||||
*/
|
||||
|
||||
spl0();
|
||||
spl0();
|
||||
|
||||
/*
|
||||
* Now probe all the devices attached to the bus.
|
||||
* (This amounts to all devices.)
|
||||
*/
|
||||
autoconf_lamebus(lamebus, 0);
|
||||
/*
|
||||
* Now probe all the devices attached to the bus.
|
||||
* (This amounts to all devices.)
|
||||
*/
|
||||
autoconf_lamebus(lamebus, 0);
|
||||
|
||||
/*
|
||||
* Configure the MIPS on-chip timer to interrupt HZ times a second.
|
||||
*/
|
||||
mips_timer_set(CPU_FREQUENCY / HZ);
|
||||
/*
|
||||
* Configure the MIPS on-chip timer to interrupt HZ times a second.
|
||||
*/
|
||||
mips_timer_set(CPU_FREQUENCY / HZ);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start all secondary CPUs.
|
||||
*/
|
||||
void
|
||||
mainbus_start_cpus(void)
|
||||
{
|
||||
lamebus_start_cpus(lamebus);
|
||||
}
|
||||
void mainbus_start_cpus(void) { lamebus_start_cpus(lamebus); }
|
||||
|
||||
/*
|
||||
* Function to generate the memory address (in the uncached segment)
|
||||
* for the specified offset into the specified slot's region of the
|
||||
* LAMEbus.
|
||||
*/
|
||||
void *
|
||||
lamebus_map_area(struct lamebus_softc *bus, int slot, uint32_t offset)
|
||||
{
|
||||
uint32_t address;
|
||||
void *lamebus_map_area(struct lamebus_softc *bus, int slot, uint32_t offset) {
|
||||
uint32_t address;
|
||||
|
||||
(void)bus; // not needed
|
||||
(void)bus; // not needed
|
||||
|
||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||
|
||||
address = LB_BASEADDR + slot*LB_SLOT_SIZE + offset;
|
||||
return (void *)address;
|
||||
address = LB_BASEADDR + slot * LB_SLOT_SIZE + offset;
|
||||
return (void *)address;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a 32-bit register from a LAMEbus device.
|
||||
*/
|
||||
uint32_t
|
||||
lamebus_read_register(struct lamebus_softc *bus, int slot, uint32_t offset)
|
||||
{
|
||||
uint32_t *ptr;
|
||||
uint32_t lamebus_read_register(struct lamebus_softc *bus, int slot,
|
||||
uint32_t offset) {
|
||||
uint32_t *ptr;
|
||||
|
||||
ptr = lamebus_map_area(bus, slot, offset);
|
||||
ptr = lamebus_map_area(bus, slot, offset);
|
||||
|
||||
/*
|
||||
* Make sure the load happens after anything the device has
|
||||
* been doing.
|
||||
*/
|
||||
membar_load_load();
|
||||
/*
|
||||
* Make sure the load happens after anything the device has
|
||||
* been doing.
|
||||
*/
|
||||
membar_load_load();
|
||||
|
||||
return *ptr;
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a 32-bit register of a LAMEbus device.
|
||||
*/
|
||||
void
|
||||
lamebus_write_register(struct lamebus_softc *bus, int slot,
|
||||
uint32_t offset, uint32_t val)
|
||||
{
|
||||
uint32_t *ptr;
|
||||
void lamebus_write_register(struct lamebus_softc *bus, int slot,
|
||||
uint32_t offset, uint32_t val) {
|
||||
uint32_t *ptr;
|
||||
|
||||
ptr = lamebus_map_area(bus, slot, offset);
|
||||
*ptr = val;
|
||||
ptr = lamebus_map_area(bus, slot, offset);
|
||||
*ptr = val;
|
||||
|
||||
/*
|
||||
* Make sure the store happens before we do anything else to
|
||||
* the device.
|
||||
*/
|
||||
membar_store_store();
|
||||
/*
|
||||
* Make sure the store happens before we do anything else to
|
||||
* the device.
|
||||
*/
|
||||
membar_store_store();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Power off the system.
|
||||
*/
|
||||
void
|
||||
mainbus_poweroff(void)
|
||||
{
|
||||
/*
|
||||
*
|
||||
* Note that lamebus_write_register() doesn't actually access
|
||||
* the bus argument, so this will still work if we get here
|
||||
* before the bus is initialized.
|
||||
*/
|
||||
lamebus_poweroff(lamebus);
|
||||
void mainbus_poweroff(void) {
|
||||
/*
|
||||
*
|
||||
* Note that lamebus_write_register() doesn't actually access
|
||||
* the bus argument, so this will still work if we get here
|
||||
* before the bus is initialized.
|
||||
*/
|
||||
lamebus_poweroff(lamebus);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reboot the system.
|
||||
*/
|
||||
void
|
||||
mainbus_reboot(void)
|
||||
{
|
||||
/*
|
||||
* The MIPS doesn't appear to have any on-chip reset.
|
||||
* LAMEbus doesn't have a reset control, so we just
|
||||
* power off instead of rebooting. This would not be
|
||||
* so great in a real system, but it's fine for what
|
||||
* we're doing.
|
||||
*/
|
||||
kprintf("Cannot reboot - powering off instead, sorry.\n");
|
||||
mainbus_poweroff();
|
||||
void mainbus_reboot(void) {
|
||||
/*
|
||||
* The MIPS doesn't appear to have any on-chip reset.
|
||||
* LAMEbus doesn't have a reset control, so we just
|
||||
* power off instead of rebooting. This would not be
|
||||
* so great in a real system, but it's fine for what
|
||||
* we're doing.
|
||||
*/
|
||||
kprintf("Cannot reboot - powering off instead, sorry.\n");
|
||||
mainbus_poweroff();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -222,11 +202,7 @@ mainbus_reboot(void)
|
||||
* On some systems, this would return to the boot monitor. But we don't
|
||||
* have one.
|
||||
*/
|
||||
void
|
||||
mainbus_halt(void)
|
||||
{
|
||||
cpu_halt();
|
||||
}
|
||||
void mainbus_halt(void) { cpu_halt(); }
|
||||
|
||||
/*
|
||||
* Called to reset the system from panic().
|
||||
@ -235,110 +211,94 @@ mainbus_halt(void)
|
||||
* as to panic recursively if we do much of anything. So just power off.
|
||||
* (We'd reboot, but System/161 doesn't do that.)
|
||||
*/
|
||||
void
|
||||
mainbus_panic(void)
|
||||
{
|
||||
mainbus_poweroff();
|
||||
}
|
||||
void mainbus_panic(void) { mainbus_poweroff(); }
|
||||
|
||||
/*
|
||||
* Function to get the size of installed physical RAM from the LAMEbus
|
||||
* controller.
|
||||
*/
|
||||
uint32_t
|
||||
mainbus_ramsize(void)
|
||||
{
|
||||
uint32_t ramsize;
|
||||
uint32_t mainbus_ramsize(void) {
|
||||
uint32_t ramsize;
|
||||
|
||||
ramsize = lamebus_ramsize();
|
||||
ramsize = lamebus_ramsize();
|
||||
|
||||
/*
|
||||
* This is the same as the last physical address, as long as
|
||||
* we have less than 508 megabytes of memory. The LAMEbus I/O
|
||||
* area occupies the space between 508 megabytes and 512
|
||||
* megabytes, so if we had more RAM than this it would have to
|
||||
* be discontiguous. This is not a case we are going to worry
|
||||
* about.
|
||||
*/
|
||||
if (ramsize > 508*1024*1024) {
|
||||
ramsize = 508*1024*1024;
|
||||
}
|
||||
/*
|
||||
* This is the same as the last physical address, as long as
|
||||
* we have less than 508 megabytes of memory. The LAMEbus I/O
|
||||
* area occupies the space between 508 megabytes and 512
|
||||
* megabytes, so if we had more RAM than this it would have to
|
||||
* be discontiguous. This is not a case we are going to worry
|
||||
* about.
|
||||
*/
|
||||
if (ramsize > 508 * 1024 * 1024) {
|
||||
ramsize = 508 * 1024 * 1024;
|
||||
}
|
||||
|
||||
return ramsize;
|
||||
return ramsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send IPI.
|
||||
*/
|
||||
void
|
||||
mainbus_send_ipi(struct cpu *target)
|
||||
{
|
||||
lamebus_assert_ipi(lamebus, target);
|
||||
void mainbus_send_ipi(struct cpu *target) {
|
||||
lamebus_assert_ipi(lamebus, target);
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger the debugger.
|
||||
*/
|
||||
void
|
||||
mainbus_debugger(void)
|
||||
{
|
||||
ltrace_stop(0);
|
||||
}
|
||||
void mainbus_debugger(void) { ltrace_stop(0); }
|
||||
|
||||
/*
|
||||
* Interrupt dispatcher.
|
||||
*/
|
||||
|
||||
/* Wiring of LAMEbus interrupts to bits in the cause register */
|
||||
#define LAMEBUS_IRQ_BIT 0x00000400 /* all system bus slots */
|
||||
#define LAMEBUS_IPI_BIT 0x00000800 /* inter-processor interrupt */
|
||||
#define MIPS_TIMER_BIT 0x00008000 /* on-chip timer */
|
||||
#define LAMEBUS_IRQ_BIT 0x00000400 /* all system bus slots */
|
||||
#define LAMEBUS_IPI_BIT 0x00000800 /* inter-processor interrupt */
|
||||
#define MIPS_TIMER_BIT 0x00008000 /* on-chip timer */
|
||||
|
||||
void
|
||||
mainbus_interrupt(struct trapframe *tf)
|
||||
{
|
||||
uint32_t cause;
|
||||
bool seen = false;
|
||||
void mainbus_interrupt(struct trapframe *tf) {
|
||||
uint32_t cause;
|
||||
bool seen = false;
|
||||
|
||||
/* interrupts should be off */
|
||||
KASSERT(curthread->t_curspl > 0);
|
||||
/* interrupts should be off */
|
||||
KASSERT(curthread->t_curspl > 0);
|
||||
|
||||
cause = tf->tf_cause;
|
||||
if (cause & LAMEBUS_IRQ_BIT) {
|
||||
lamebus_interrupt(lamebus);
|
||||
seen = true;
|
||||
}
|
||||
if (cause & LAMEBUS_IPI_BIT) {
|
||||
interprocessor_interrupt();
|
||||
lamebus_clear_ipi(lamebus, curcpu);
|
||||
seen = true;
|
||||
}
|
||||
if (cause & MIPS_TIMER_BIT) {
|
||||
/* Reset the timer (this clears the interrupt) */
|
||||
mips_timer_set(CPU_FREQUENCY / HZ);
|
||||
/* and call hardclock */
|
||||
hardclock();
|
||||
seen = true;
|
||||
}
|
||||
cause = tf->tf_cause;
|
||||
if (cause & LAMEBUS_IRQ_BIT) {
|
||||
lamebus_interrupt(lamebus);
|
||||
seen = true;
|
||||
}
|
||||
if (cause & LAMEBUS_IPI_BIT) {
|
||||
interprocessor_interrupt();
|
||||
lamebus_clear_ipi(lamebus, curcpu);
|
||||
seen = true;
|
||||
}
|
||||
if (cause & MIPS_TIMER_BIT) {
|
||||
/* Reset the timer (this clears the interrupt) */
|
||||
mips_timer_set(CPU_FREQUENCY / HZ);
|
||||
/* and call hardclock */
|
||||
hardclock();
|
||||
seen = true;
|
||||
}
|
||||
|
||||
if (!seen) {
|
||||
if ((cause & CCA_IRQS) == 0) {
|
||||
/*
|
||||
* Don't panic here; this can happen if an
|
||||
* interrupt line asserts (very) briefly and
|
||||
* turns off again before we get as far as
|
||||
* reading the cause register. This was
|
||||
* actually seen... once.
|
||||
*/
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* But if we get an interrupt on an interrupt
|
||||
* line that's not supposed to be wired up,
|
||||
* complain.
|
||||
*/
|
||||
panic("Unknown interrupt; cause register is %08x\n",
|
||||
cause);
|
||||
}
|
||||
}
|
||||
if (!seen) {
|
||||
if ((cause & CCA_IRQS) == 0) {
|
||||
/*
|
||||
* Don't panic here; this can happen if an
|
||||
* interrupt line asserts (very) briefly and
|
||||
* turns off again before we get as far as
|
||||
* reading the cause register. This was
|
||||
* actually seen... once.
|
||||
*/
|
||||
} else {
|
||||
/*
|
||||
* But if we get an interrupt on an interrupt
|
||||
* line that's not supposed to be wired up,
|
||||
* complain.
|
||||
*/
|
||||
panic("Unknown interrupt; cause register is %08x\n", cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,24 +37,22 @@
|
||||
* This would need to be a bit more complicated if that weren't the case.
|
||||
*/
|
||||
|
||||
#include <machine/vm.h> /* for MIPS_KSEG1 */
|
||||
#include <lamebus/lamebus.h> /* for LAMEbus definitions */
|
||||
#include <machine/vm.h> /* for MIPS_KSEG1 */
|
||||
#include <lamebus/lamebus.h> /* for LAMEbus definitions */
|
||||
|
||||
#define bus_write_register(bus, slot, offset, val) \
|
||||
lamebus_write_register(bus, slot, offset, val)
|
||||
#define bus_write_register(bus, slot, offset, val) \
|
||||
lamebus_write_register(bus, slot, offset, val)
|
||||
|
||||
#define bus_read_register(bus, slot, offset) \
|
||||
lamebus_read_register(bus, slot, offset)
|
||||
#define bus_read_register(bus, slot, offset) \
|
||||
lamebus_read_register(bus, slot, offset)
|
||||
|
||||
#define bus_map_area(bus, slot, offset) \
|
||||
lamebus_map_area(bus, slot, offset)
|
||||
#define bus_map_area(bus, slot, offset) lamebus_map_area(bus, slot, offset)
|
||||
|
||||
/*
|
||||
* Machine-dependent LAMEbus definitions
|
||||
*/
|
||||
|
||||
/* Base address of the LAMEbus mapping area */
|
||||
#define LB_BASEADDR (MIPS_KSEG1 + 0x1fe00000)
|
||||
|
||||
#define LB_BASEADDR (MIPS_KSEG1 + 0x1fe00000)
|
||||
|
||||
#endif /* _SYS161_BUS_H_ */
|
||||
|
@ -46,26 +46,21 @@
|
||||
|
||||
static struct beep_softc *the_beep = NULL;
|
||||
|
||||
int
|
||||
config_beep(struct beep_softc *bs, int unit)
|
||||
{
|
||||
/* We use only the first beep device. */
|
||||
if (unit!=0) {
|
||||
return ENODEV;
|
||||
}
|
||||
int config_beep(struct beep_softc *bs, int unit) {
|
||||
/* We use only the first beep device. */
|
||||
if (unit != 0) {
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
KASSERT(the_beep==NULL);
|
||||
the_beep = bs;
|
||||
return 0;
|
||||
KASSERT(the_beep == NULL);
|
||||
the_beep = bs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
beep(void)
|
||||
{
|
||||
if (the_beep!=NULL) {
|
||||
the_beep->bs_beep(the_beep->bs_devdata);
|
||||
}
|
||||
else {
|
||||
kprintf("beep: Warning: no beep device\n");
|
||||
}
|
||||
void beep(void) {
|
||||
if (the_beep != NULL) {
|
||||
the_beep->bs_beep(the_beep->bs_devdata);
|
||||
} else {
|
||||
kprintf("beep: Warning: no beep device\n");
|
||||
}
|
||||
}
|
||||
|
@ -36,8 +36,8 @@
|
||||
*/
|
||||
|
||||
struct beep_softc {
|
||||
void *bs_devdata;
|
||||
void (*bs_beep)(void *devdata);
|
||||
void *bs_devdata;
|
||||
void (*bs_beep)(void *devdata);
|
||||
};
|
||||
|
||||
#endif /* _GENERIC_BEEP_H_ */
|
||||
|
@ -79,32 +79,26 @@ static struct lock *con_userlock_write = NULL;
|
||||
* console is set up. Upon console setup they are dumped
|
||||
* to the actual console; thenceforth this space is unused.
|
||||
*/
|
||||
#define DELAYBUFSIZE 1024
|
||||
#define DELAYBUFSIZE 1024
|
||||
static char delayed_outbuf[DELAYBUFSIZE];
|
||||
static size_t delayed_outbuf_pos=0;
|
||||
static size_t delayed_outbuf_pos = 0;
|
||||
|
||||
static
|
||||
void
|
||||
putch_delayed(int ch)
|
||||
{
|
||||
/*
|
||||
* No synchronization needed: called only during system startup
|
||||
* by main thread.
|
||||
*/
|
||||
static void putch_delayed(int ch) {
|
||||
/*
|
||||
* No synchronization needed: called only during system startup
|
||||
* by main thread.
|
||||
*/
|
||||
|
||||
KASSERT(delayed_outbuf_pos < sizeof(delayed_outbuf));
|
||||
delayed_outbuf[delayed_outbuf_pos++] = ch;
|
||||
KASSERT(delayed_outbuf_pos < sizeof(delayed_outbuf));
|
||||
delayed_outbuf[delayed_outbuf_pos++] = ch;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
flush_delay_buf(void)
|
||||
{
|
||||
size_t i;
|
||||
for (i=0; i<delayed_outbuf_pos; i++) {
|
||||
putch(delayed_outbuf[i]);
|
||||
}
|
||||
delayed_outbuf_pos = 0;
|
||||
static void flush_delay_buf(void) {
|
||||
size_t i;
|
||||
for (i = 0; i < delayed_outbuf_pos; i++) {
|
||||
putch(delayed_outbuf[i]);
|
||||
}
|
||||
delayed_outbuf_pos = 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
@ -113,11 +107,8 @@ flush_delay_buf(void)
|
||||
* Print a character, using polling instead of interrupts to wait for
|
||||
* I/O completion.
|
||||
*/
|
||||
static
|
||||
void
|
||||
putch_polled(struct con_softc *cs, int ch)
|
||||
{
|
||||
cs->cs_sendpolled(cs->cs_devdata, ch);
|
||||
static void putch_polled(struct con_softc *cs, int ch) {
|
||||
cs->cs_sendpolled(cs->cs_devdata, ch);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
@ -125,28 +116,21 @@ putch_polled(struct con_softc *cs, int ch)
|
||||
/*
|
||||
* Print a character, using interrupts to wait for I/O completion.
|
||||
*/
|
||||
static
|
||||
void
|
||||
putch_intr(struct con_softc *cs, int ch)
|
||||
{
|
||||
P(cs->cs_wsem);
|
||||
cs->cs_send(cs->cs_devdata, ch);
|
||||
static void putch_intr(struct con_softc *cs, int ch) {
|
||||
P(cs->cs_wsem);
|
||||
cs->cs_send(cs->cs_devdata, ch);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a character, using interrupts to wait for I/O completion.
|
||||
*/
|
||||
static
|
||||
int
|
||||
getch_intr(struct con_softc *cs)
|
||||
{
|
||||
unsigned char ret;
|
||||
static int getch_intr(struct con_softc *cs) {
|
||||
unsigned char ret;
|
||||
|
||||
P(cs->cs_rsem);
|
||||
ret = cs->cs_gotchars[cs->cs_gotchars_tail];
|
||||
cs->cs_gotchars_tail =
|
||||
(cs->cs_gotchars_tail + 1) % CONSOLE_INPUT_BUFFER_SIZE;
|
||||
return ret;
|
||||
P(cs->cs_rsem);
|
||||
ret = cs->cs_gotchars[cs->cs_gotchars_tail];
|
||||
cs->cs_gotchars_tail = (cs->cs_gotchars_tail + 1) % CONSOLE_INPUT_BUFFER_SIZE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -158,33 +142,29 @@ getch_intr(struct con_softc *cs)
|
||||
* too) would be with a second semaphore used with a nonblocking P,
|
||||
* but we don't have that in OS/161.
|
||||
*/
|
||||
void
|
||||
con_input(void *vcs, int ch)
|
||||
{
|
||||
struct con_softc *cs = vcs;
|
||||
unsigned nexthead;
|
||||
void con_input(void *vcs, int ch) {
|
||||
struct con_softc *cs = vcs;
|
||||
unsigned nexthead;
|
||||
|
||||
nexthead = (cs->cs_gotchars_head + 1) % CONSOLE_INPUT_BUFFER_SIZE;
|
||||
if (nexthead == cs->cs_gotchars_tail) {
|
||||
/* overflow; drop character */
|
||||
return;
|
||||
}
|
||||
nexthead = (cs->cs_gotchars_head + 1) % CONSOLE_INPUT_BUFFER_SIZE;
|
||||
if (nexthead == cs->cs_gotchars_tail) {
|
||||
/* overflow; drop character */
|
||||
return;
|
||||
}
|
||||
|
||||
cs->cs_gotchars[cs->cs_gotchars_head] = ch;
|
||||
cs->cs_gotchars_head = nexthead;
|
||||
cs->cs_gotchars[cs->cs_gotchars_head] = ch;
|
||||
cs->cs_gotchars_head = nexthead;
|
||||
|
||||
V(cs->cs_rsem);
|
||||
V(cs->cs_rsem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called from underlying device when a write-done interrupt occurs.
|
||||
*/
|
||||
void
|
||||
con_start(void *vcs)
|
||||
{
|
||||
struct con_softc *cs = vcs;
|
||||
void con_start(void *vcs) {
|
||||
struct con_softc *cs = vcs;
|
||||
|
||||
V(cs->cs_wsem);
|
||||
V(cs->cs_wsem);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
@ -197,32 +177,25 @@ con_start(void *vcs)
|
||||
* not, and does not.
|
||||
*/
|
||||
|
||||
void
|
||||
putch(int ch)
|
||||
{
|
||||
struct con_softc *cs = the_console;
|
||||
void putch(int ch) {
|
||||
struct con_softc *cs = the_console;
|
||||
|
||||
if (cs==NULL) {
|
||||
putch_delayed(ch);
|
||||
}
|
||||
else if (curthread->t_in_interrupt ||
|
||||
curthread->t_curspl > 0 ||
|
||||
curcpu->c_spinlocks > 0) {
|
||||
putch_polled(cs, ch);
|
||||
}
|
||||
else {
|
||||
putch_intr(cs, ch);
|
||||
}
|
||||
if (cs == NULL) {
|
||||
putch_delayed(ch);
|
||||
} else if (curthread->t_in_interrupt || curthread->t_curspl > 0 ||
|
||||
curcpu->c_spinlocks > 0) {
|
||||
putch_polled(cs, ch);
|
||||
} else {
|
||||
putch_intr(cs, ch);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getch(void)
|
||||
{
|
||||
struct con_softc *cs = the_console;
|
||||
KASSERT(cs != NULL);
|
||||
KASSERT(!curthread->t_in_interrupt && curthread->t_iplhigh_count == 0);
|
||||
int getch(void) {
|
||||
struct con_softc *cs = the_console;
|
||||
KASSERT(cs != NULL);
|
||||
KASSERT(!curthread->t_in_interrupt && curthread->t_iplhigh_count == 0);
|
||||
|
||||
return getch_intr(cs);
|
||||
return getch_intr(cs);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -231,107 +204,93 @@ getch(void)
|
||||
* VFS interface functions
|
||||
*/
|
||||
|
||||
static
|
||||
int
|
||||
con_eachopen(struct device *dev, int openflags)
|
||||
{
|
||||
(void)dev;
|
||||
(void)openflags;
|
||||
return 0;
|
||||
static int con_eachopen(struct device *dev, int openflags) {
|
||||
(void)dev;
|
||||
(void)openflags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
con_io(struct device *dev, struct uio *uio)
|
||||
{
|
||||
int result;
|
||||
char ch;
|
||||
struct lock *lk;
|
||||
static int con_io(struct device *dev, struct uio *uio) {
|
||||
int result;
|
||||
char ch;
|
||||
struct lock *lk;
|
||||
|
||||
(void)dev; // unused
|
||||
(void)dev; // unused
|
||||
|
||||
if (uio->uio_rw==UIO_READ) {
|
||||
lk = con_userlock_read;
|
||||
}
|
||||
else {
|
||||
lk = con_userlock_write;
|
||||
}
|
||||
if (uio->uio_rw == UIO_READ) {
|
||||
lk = con_userlock_read;
|
||||
} else {
|
||||
lk = con_userlock_write;
|
||||
}
|
||||
|
||||
KASSERT(lk != NULL);
|
||||
lock_acquire(lk);
|
||||
KASSERT(lk != NULL);
|
||||
lock_acquire(lk);
|
||||
|
||||
while (uio->uio_resid > 0) {
|
||||
if (uio->uio_rw==UIO_READ) {
|
||||
ch = getch();
|
||||
if (ch=='\r') {
|
||||
ch = '\n';
|
||||
}
|
||||
result = uiomove(&ch, 1, uio);
|
||||
if (result) {
|
||||
lock_release(lk);
|
||||
return result;
|
||||
}
|
||||
if (ch=='\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = uiomove(&ch, 1, uio);
|
||||
if (result) {
|
||||
lock_release(lk);
|
||||
return result;
|
||||
}
|
||||
if (ch=='\n') {
|
||||
putch('\r');
|
||||
}
|
||||
putch(ch);
|
||||
}
|
||||
}
|
||||
lock_release(lk);
|
||||
return 0;
|
||||
while (uio->uio_resid > 0) {
|
||||
if (uio->uio_rw == UIO_READ) {
|
||||
ch = getch();
|
||||
if (ch == '\r') {
|
||||
ch = '\n';
|
||||
}
|
||||
result = uiomove(&ch, 1, uio);
|
||||
if (result) {
|
||||
lock_release(lk);
|
||||
return result;
|
||||
}
|
||||
if (ch == '\n') {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
result = uiomove(&ch, 1, uio);
|
||||
if (result) {
|
||||
lock_release(lk);
|
||||
return result;
|
||||
}
|
||||
if (ch == '\n') {
|
||||
putch('\r');
|
||||
}
|
||||
putch(ch);
|
||||
}
|
||||
}
|
||||
lock_release(lk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
con_ioctl(struct device *dev, int op, userptr_t data)
|
||||
{
|
||||
/* No ioctls. */
|
||||
(void)dev;
|
||||
(void)op;
|
||||
(void)data;
|
||||
return EINVAL;
|
||||
static int con_ioctl(struct device *dev, int op, userptr_t data) {
|
||||
/* No ioctls. */
|
||||
(void)dev;
|
||||
(void)op;
|
||||
(void)data;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
static const struct device_ops console_devops = {
|
||||
.devop_eachopen = con_eachopen,
|
||||
.devop_io = con_io,
|
||||
.devop_ioctl = con_ioctl,
|
||||
.devop_eachopen = con_eachopen,
|
||||
.devop_io = con_io,
|
||||
.devop_ioctl = con_ioctl,
|
||||
};
|
||||
|
||||
static
|
||||
int
|
||||
attach_console_to_vfs(struct con_softc *cs)
|
||||
{
|
||||
struct device *dev;
|
||||
int result;
|
||||
static int attach_console_to_vfs(struct con_softc *cs) {
|
||||
struct device *dev;
|
||||
int result;
|
||||
|
||||
dev = kmalloc(sizeof(*dev));
|
||||
if (dev==NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
dev = kmalloc(sizeof(*dev));
|
||||
if (dev == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
dev->d_ops = &console_devops;
|
||||
dev->d_blocks = 0;
|
||||
dev->d_blocksize = 1;
|
||||
dev->d_data = cs;
|
||||
dev->d_ops = &console_devops;
|
||||
dev->d_blocks = 0;
|
||||
dev->d_blocksize = 1;
|
||||
dev->d_data = cs;
|
||||
|
||||
result = vfs_adddev("con", dev, 0);
|
||||
if (result) {
|
||||
kfree(dev);
|
||||
return result;
|
||||
}
|
||||
result = vfs_adddev("con", dev, 0);
|
||||
if (result) {
|
||||
kfree(dev);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -340,58 +299,56 @@ attach_console_to_vfs(struct con_softc *cs)
|
||||
* Config routine called by autoconf.c after we are attached to something.
|
||||
*/
|
||||
|
||||
int
|
||||
config_con(struct con_softc *cs, int unit)
|
||||
{
|
||||
struct semaphore *rsem, *wsem;
|
||||
struct lock *rlk, *wlk;
|
||||
int config_con(struct con_softc *cs, int unit) {
|
||||
struct semaphore *rsem, *wsem;
|
||||
struct lock *rlk, *wlk;
|
||||
|
||||
/*
|
||||
* Only allow one system console.
|
||||
* Further devices that could be the system console are ignored.
|
||||
*
|
||||
* Do not hardwire the console to be "con1" instead of "con0",
|
||||
* or these asserts will go off.
|
||||
*/
|
||||
if (unit>0) {
|
||||
KASSERT(the_console!=NULL);
|
||||
return ENODEV;
|
||||
}
|
||||
KASSERT(the_console==NULL);
|
||||
/*
|
||||
* Only allow one system console.
|
||||
* Further devices that could be the system console are ignored.
|
||||
*
|
||||
* Do not hardwire the console to be "con1" instead of "con0",
|
||||
* or these asserts will go off.
|
||||
*/
|
||||
if (unit > 0) {
|
||||
KASSERT(the_console != NULL);
|
||||
return ENODEV;
|
||||
}
|
||||
KASSERT(the_console == NULL);
|
||||
|
||||
rsem = sem_create("console read", 0);
|
||||
if (rsem == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
wsem = sem_create("console write", 1);
|
||||
if (wsem == NULL) {
|
||||
sem_destroy(rsem);
|
||||
return ENOMEM;
|
||||
}
|
||||
rlk = lock_create("console-lock-read");
|
||||
if (rlk == NULL) {
|
||||
sem_destroy(rsem);
|
||||
sem_destroy(wsem);
|
||||
return ENOMEM;
|
||||
}
|
||||
wlk = lock_create("console-lock-write");
|
||||
if (wlk == NULL) {
|
||||
lock_destroy(rlk);
|
||||
sem_destroy(rsem);
|
||||
sem_destroy(wsem);
|
||||
return ENOMEM;
|
||||
}
|
||||
rsem = sem_create("console read", 0);
|
||||
if (rsem == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
wsem = sem_create("console write", 1);
|
||||
if (wsem == NULL) {
|
||||
sem_destroy(rsem);
|
||||
return ENOMEM;
|
||||
}
|
||||
rlk = lock_create("console-lock-read");
|
||||
if (rlk == NULL) {
|
||||
sem_destroy(rsem);
|
||||
sem_destroy(wsem);
|
||||
return ENOMEM;
|
||||
}
|
||||
wlk = lock_create("console-lock-write");
|
||||
if (wlk == NULL) {
|
||||
lock_destroy(rlk);
|
||||
sem_destroy(rsem);
|
||||
sem_destroy(wsem);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
cs->cs_rsem = rsem;
|
||||
cs->cs_wsem = wsem;
|
||||
cs->cs_gotchars_head = 0;
|
||||
cs->cs_gotchars_tail = 0;
|
||||
cs->cs_rsem = rsem;
|
||||
cs->cs_wsem = wsem;
|
||||
cs->cs_gotchars_head = 0;
|
||||
cs->cs_gotchars_tail = 0;
|
||||
|
||||
the_console = cs;
|
||||
con_userlock_read = rlk;
|
||||
con_userlock_write = wlk;
|
||||
the_console = cs;
|
||||
con_userlock_read = rlk;
|
||||
con_userlock_write = wlk;
|
||||
|
||||
flush_delay_buf();
|
||||
flush_delay_buf();
|
||||
|
||||
return attach_console_to_vfs(cs);
|
||||
return attach_console_to_vfs(cs);
|
||||
}
|
||||
|
@ -40,17 +40,17 @@
|
||||
#define CONSOLE_INPUT_BUFFER_SIZE 32
|
||||
|
||||
struct con_softc {
|
||||
/* initialized by attach routine */
|
||||
void *cs_devdata;
|
||||
void (*cs_send)(void *devdata, int ch);
|
||||
void (*cs_sendpolled)(void *devdata, int ch);
|
||||
/* initialized by attach routine */
|
||||
void *cs_devdata;
|
||||
void (*cs_send)(void *devdata, int ch);
|
||||
void (*cs_sendpolled)(void *devdata, int ch);
|
||||
|
||||
/* initialized by config routine */
|
||||
struct semaphore *cs_rsem;
|
||||
struct semaphore *cs_wsem;
|
||||
unsigned char cs_gotchars[CONSOLE_INPUT_BUFFER_SIZE];
|
||||
unsigned cs_gotchars_head; /* next slot to put a char in */
|
||||
unsigned cs_gotchars_tail; /* next slot to take a char out */
|
||||
/* initialized by config routine */
|
||||
struct semaphore *cs_rsem;
|
||||
struct semaphore *cs_wsem;
|
||||
unsigned char cs_gotchars[CONSOLE_INPUT_BUFFER_SIZE];
|
||||
unsigned cs_gotchars_head; /* next slot to put a char in */
|
||||
unsigned cs_gotchars_tail; /* next slot to take a char out */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -53,106 +53,90 @@ static struct random_softc *the_random = NULL;
|
||||
* VFS device functions.
|
||||
* open: allow reading only.
|
||||
*/
|
||||
static
|
||||
int
|
||||
randeachopen(struct device *dev, int openflags)
|
||||
{
|
||||
(void)dev;
|
||||
static int randeachopen(struct device *dev, int openflags) {
|
||||
(void)dev;
|
||||
|
||||
if (openflags != O_RDONLY) {
|
||||
return EIO;
|
||||
}
|
||||
if (openflags != O_RDONLY) {
|
||||
return EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* VFS I/O function. Hand off to implementation.
|
||||
*/
|
||||
static
|
||||
int
|
||||
randio(struct device *dev, struct uio *uio)
|
||||
{
|
||||
struct random_softc *rs = dev->d_data;
|
||||
static int randio(struct device *dev, struct uio *uio) {
|
||||
struct random_softc *rs = dev->d_data;
|
||||
|
||||
if (uio->uio_rw != UIO_READ) {
|
||||
return EIO;
|
||||
}
|
||||
if (uio->uio_rw != UIO_READ) {
|
||||
return EIO;
|
||||
}
|
||||
|
||||
return rs->rs_read(rs->rs_devdata, uio);
|
||||
return rs->rs_read(rs->rs_devdata, uio);
|
||||
}
|
||||
|
||||
/*
|
||||
* VFS ioctl function.
|
||||
*/
|
||||
static
|
||||
int
|
||||
randioctl(struct device *dev, int op, userptr_t data)
|
||||
{
|
||||
/*
|
||||
* We don't support any ioctls.
|
||||
*/
|
||||
(void)dev;
|
||||
(void)op;
|
||||
(void)data;
|
||||
return EIOCTL;
|
||||
static int randioctl(struct device *dev, int op, userptr_t data) {
|
||||
/*
|
||||
* We don't support any ioctls.
|
||||
*/
|
||||
(void)dev;
|
||||
(void)op;
|
||||
(void)data;
|
||||
return EIOCTL;
|
||||
}
|
||||
|
||||
static const struct device_ops random_devops = {
|
||||
.devop_eachopen = randeachopen,
|
||||
.devop_io = randio,
|
||||
.devop_ioctl = randioctl,
|
||||
.devop_eachopen = randeachopen,
|
||||
.devop_io = randio,
|
||||
.devop_ioctl = randioctl,
|
||||
};
|
||||
|
||||
/*
|
||||
* Config function.
|
||||
*/
|
||||
int
|
||||
config_random(struct random_softc *rs, int unit)
|
||||
{
|
||||
int result;
|
||||
int config_random(struct random_softc *rs, int unit) {
|
||||
int result;
|
||||
|
||||
/* We use only the first random device. */
|
||||
if (unit!=0) {
|
||||
return ENODEV;
|
||||
}
|
||||
/* We use only the first random device. */
|
||||
if (unit != 0) {
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
KASSERT(the_random==NULL);
|
||||
the_random = rs;
|
||||
KASSERT(the_random == NULL);
|
||||
the_random = rs;
|
||||
|
||||
rs->rs_dev.d_ops = &random_devops;
|
||||
rs->rs_dev.d_blocks = 0;
|
||||
rs->rs_dev.d_blocksize = 1;
|
||||
rs->rs_dev.d_data = rs;
|
||||
rs->rs_dev.d_ops = &random_devops;
|
||||
rs->rs_dev.d_blocks = 0;
|
||||
rs->rs_dev.d_blocksize = 1;
|
||||
rs->rs_dev.d_data = rs;
|
||||
|
||||
/* Add the VFS device structure to the VFS device list. */
|
||||
result = vfs_adddev("random", &rs->rs_dev, 0);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
/* Add the VFS device structure to the VFS device list. */
|
||||
result = vfs_adddev("random", &rs->rs_dev, 0);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Random number functions exported to the rest of the kernel.
|
||||
*/
|
||||
|
||||
uint32_t
|
||||
random(void)
|
||||
{
|
||||
if (the_random==NULL) {
|
||||
panic("No random device\n");
|
||||
}
|
||||
return the_random->rs_random(the_random->rs_devdata);
|
||||
uint32_t random(void) {
|
||||
if (the_random == NULL) {
|
||||
panic("No random device\n");
|
||||
}
|
||||
return the_random->rs_random(the_random->rs_devdata);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
randmax(void)
|
||||
{
|
||||
if (the_random==NULL) {
|
||||
panic("No random device\n");
|
||||
}
|
||||
return the_random->rs_randmax(the_random->rs_devdata);
|
||||
uint32_t randmax(void) {
|
||||
if (the_random == NULL) {
|
||||
panic("No random device\n");
|
||||
}
|
||||
return the_random->rs_randmax(the_random->rs_devdata);
|
||||
}
|
||||
|
@ -34,13 +34,13 @@
|
||||
struct uio;
|
||||
|
||||
struct random_softc {
|
||||
/* Initialized by lower-level attach routine */
|
||||
void *rs_devdata;
|
||||
uint32_t (*rs_random)(void *devdata);
|
||||
uint32_t (*rs_randmax)(void *devdata);
|
||||
int (*rs_read)(void *devdata, struct uio *uio);
|
||||
/* Initialized by lower-level attach routine */
|
||||
void *rs_devdata;
|
||||
uint32_t (*rs_random)(void *devdata);
|
||||
uint32_t (*rs_randmax)(void *devdata);
|
||||
int (*rs_read)(void *devdata, struct uio *uio);
|
||||
|
||||
struct device rs_dev;
|
||||
struct device rs_dev;
|
||||
};
|
||||
|
||||
#endif /* _GENERIC_RANDOM_H_ */
|
||||
|
@ -49,22 +49,18 @@
|
||||
|
||||
static struct rtclock_softc *the_clock = NULL;
|
||||
|
||||
int
|
||||
config_rtclock(struct rtclock_softc *rtc, int unit)
|
||||
{
|
||||
/* We use only the first clock device. */
|
||||
if (unit!=0) {
|
||||
return ENODEV;
|
||||
}
|
||||
int config_rtclock(struct rtclock_softc *rtc, int unit) {
|
||||
/* We use only the first clock device. */
|
||||
if (unit != 0) {
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
KASSERT(the_clock==NULL);
|
||||
the_clock = rtc;
|
||||
return 0;
|
||||
KASSERT(the_clock == NULL);
|
||||
the_clock = rtc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gettime(struct timespec *ts)
|
||||
{
|
||||
KASSERT(the_clock!=NULL);
|
||||
the_clock->rtc_gettime(the_clock->rtc_devdata, ts);
|
||||
void gettime(struct timespec *ts) {
|
||||
KASSERT(the_clock != NULL);
|
||||
the_clock->rtc_gettime(the_clock->rtc_devdata, ts);
|
||||
}
|
||||
|
@ -38,8 +38,8 @@
|
||||
struct timespec;
|
||||
|
||||
struct rtclock_softc {
|
||||
void *rtc_devdata;
|
||||
void (*rtc_gettime)(void *devdata, struct timespec *);
|
||||
void *rtc_devdata;
|
||||
void (*rtc_gettime)(void *devdata, struct timespec *);
|
||||
};
|
||||
|
||||
#endif /* _GENERIC_RTCLOCK_H_ */
|
||||
|
@ -38,18 +38,16 @@
|
||||
#include <lamebus/ltimer.h>
|
||||
#include "autoconf.h"
|
||||
|
||||
struct beep_softc *
|
||||
attach_beep_to_ltimer(int beepno, struct ltimer_softc *ls)
|
||||
{
|
||||
struct beep_softc *bs = kmalloc(sizeof(struct beep_softc));
|
||||
if (bs==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
struct beep_softc *attach_beep_to_ltimer(int beepno, struct ltimer_softc *ls) {
|
||||
struct beep_softc *bs = kmalloc(sizeof(struct beep_softc));
|
||||
if (bs == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)beepno; // unused
|
||||
(void)beepno; // unused
|
||||
|
||||
bs->bs_devdata = ls;
|
||||
bs->bs_beep = ltimer_beep;
|
||||
bs->bs_devdata = ls;
|
||||
bs->bs_beep = ltimer_beep;
|
||||
|
||||
return bs;
|
||||
return bs;
|
||||
}
|
||||
|
@ -38,22 +38,19 @@
|
||||
#include <lamebus/lscreen.h>
|
||||
#include "autoconf.h"
|
||||
|
||||
struct con_softc *
|
||||
attach_con_to_lscreen(int consno, struct lscreen_softc *ls)
|
||||
{
|
||||
struct con_softc *cs = kmalloc(sizeof(struct con_softc));
|
||||
if (cs==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
struct con_softc *attach_con_to_lscreen(int consno, struct lscreen_softc *ls) {
|
||||
struct con_softc *cs = kmalloc(sizeof(struct con_softc));
|
||||
if (cs == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cs->cs_devdata = ls;
|
||||
cs->cs_send = lscreen_write;
|
||||
cs->cs_sendpolled = lscreen_write;
|
||||
cs->cs_devdata = ls;
|
||||
cs->cs_send = lscreen_write;
|
||||
cs->cs_sendpolled = lscreen_write;
|
||||
|
||||
ls->ls_devdata = cs;
|
||||
ls->ls_start = con_start;
|
||||
ls->ls_input = con_input;
|
||||
ls->ls_devdata = cs;
|
||||
ls->ls_start = con_start;
|
||||
ls->ls_input = con_input;
|
||||
|
||||
return cs;
|
||||
return cs;
|
||||
}
|
||||
|
||||
|
@ -38,24 +38,21 @@
|
||||
#include <lamebus/lser.h>
|
||||
#include "autoconf.h"
|
||||
|
||||
struct con_softc *
|
||||
attach_con_to_lser(int consno, struct lser_softc *ls)
|
||||
{
|
||||
struct con_softc *cs = kmalloc(sizeof(struct con_softc));
|
||||
if (cs==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
struct con_softc *attach_con_to_lser(int consno, struct lser_softc *ls) {
|
||||
struct con_softc *cs = kmalloc(sizeof(struct con_softc));
|
||||
if (cs == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)consno; // unused
|
||||
(void)consno; // unused
|
||||
|
||||
cs->cs_devdata = ls;
|
||||
cs->cs_send = lser_write;
|
||||
cs->cs_sendpolled = lser_writepolled;
|
||||
cs->cs_devdata = ls;
|
||||
cs->cs_send = lser_write;
|
||||
cs->cs_sendpolled = lser_writepolled;
|
||||
|
||||
ls->ls_devdata = cs;
|
||||
ls->ls_start = con_start;
|
||||
ls->ls_input = con_input;
|
||||
ls->ls_devdata = cs;
|
||||
ls->ls_start = con_start;
|
||||
ls->ls_input = con_input;
|
||||
|
||||
return cs;
|
||||
return cs;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,9 +30,8 @@
|
||||
#ifndef _LAMEBUS_EMU_H_
|
||||
#define _LAMEBUS_EMU_H_
|
||||
|
||||
|
||||
#define EMU_MAXIO 16384
|
||||
#define EMU_ROOTHANDLE 0
|
||||
#define EMU_MAXIO 16384
|
||||
#define EMU_ROOTHANDLE 0
|
||||
|
||||
/*
|
||||
* The per-device data used by the emufs device driver.
|
||||
@ -41,22 +40,21 @@
|
||||
*/
|
||||
|
||||
struct emu_softc {
|
||||
/* Initialized by lower-level attach code */
|
||||
void *e_busdata;
|
||||
uint32_t e_buspos;
|
||||
int e_unit;
|
||||
/* Initialized by lower-level attach code */
|
||||
void *e_busdata;
|
||||
uint32_t e_buspos;
|
||||
int e_unit;
|
||||
|
||||
/* Initialized by config_emu() */
|
||||
struct lock *e_lock;
|
||||
struct semaphore *e_sem;
|
||||
void *e_iobuf;
|
||||
/* Initialized by config_emu() */
|
||||
struct lock *e_lock;
|
||||
struct semaphore *e_sem;
|
||||
void *e_iobuf;
|
||||
|
||||
/* Written by the interrupt handler */
|
||||
uint32_t e_result;
|
||||
/* Written by the interrupt handler */
|
||||
uint32_t e_result;
|
||||
};
|
||||
|
||||
/* Functions called by lower-level drivers */
|
||||
void emu_irq(/*struct emu_softc*/ void *);
|
||||
|
||||
|
||||
#endif /* _LAMEBUS_EMU_H_ */
|
||||
|
@ -38,29 +38,27 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Lowest revision we support */
|
||||
#define LOW_VERSION 1
|
||||
#define LOW_VERSION 1
|
||||
|
||||
struct emu_softc *
|
||||
attach_emu_to_lamebus(int emuno, struct lamebus_softc *sc)
|
||||
{
|
||||
struct emu_softc *es;
|
||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_EMUFS,
|
||||
LOW_VERSION, NULL);
|
||||
if (slot < 0) {
|
||||
return NULL;
|
||||
}
|
||||
struct emu_softc *attach_emu_to_lamebus(int emuno, struct lamebus_softc *sc) {
|
||||
struct emu_softc *es;
|
||||
int slot =
|
||||
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_EMUFS, LOW_VERSION, NULL);
|
||||
if (slot < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
es = kmalloc(sizeof(struct emu_softc));
|
||||
if (es==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
es = kmalloc(sizeof(struct emu_softc));
|
||||
if (es == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
es->e_busdata = sc;
|
||||
es->e_buspos = slot;
|
||||
es->e_unit = emuno;
|
||||
es->e_busdata = sc;
|
||||
es->e_buspos = slot;
|
||||
es->e_unit = emuno;
|
||||
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_attach_interrupt(sc, slot, es, emu_irq);
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_attach_interrupt(sc, slot, es, emu_irq);
|
||||
|
||||
return es;
|
||||
return es;
|
||||
}
|
||||
|
@ -40,147 +40,124 @@
|
||||
#include <lamebus/lamebus.h>
|
||||
|
||||
/* Register offsets within each config region */
|
||||
#define CFGREG_VID 0 /* Vendor ID */
|
||||
#define CFGREG_DID 4 /* Device ID */
|
||||
#define CFGREG_DRL 8 /* Device Revision Level */
|
||||
#define CFGREG_VID 0 /* Vendor ID */
|
||||
#define CFGREG_DID 4 /* Device ID */
|
||||
#define CFGREG_DRL 8 /* Device Revision Level */
|
||||
|
||||
/* LAMEbus controller private registers (offsets within its config region) */
|
||||
#define CTLREG_RAMSZ 0x200
|
||||
#define CTLREG_IRQS 0x204
|
||||
#define CTLREG_PWR 0x208
|
||||
#define CTLREG_IRQE 0x20c
|
||||
#define CTLREG_CPUS 0x210
|
||||
#define CTLREG_CPUE 0x214
|
||||
#define CTLREG_SELF 0x218
|
||||
#define CTLREG_RAMSZ 0x200
|
||||
#define CTLREG_IRQS 0x204
|
||||
#define CTLREG_PWR 0x208
|
||||
#define CTLREG_IRQE 0x20c
|
||||
#define CTLREG_CPUS 0x210
|
||||
#define CTLREG_CPUE 0x214
|
||||
#define CTLREG_SELF 0x218
|
||||
|
||||
/* LAMEbus CPU control registers (offsets within each per-cpu region) */
|
||||
#define CTLCPU_CIRQE 0x000
|
||||
#define CTLCPU_CIPI 0x004
|
||||
#define CTLCPU_CRAM 0x300
|
||||
|
||||
#define CTLCPU_CIRQE 0x000
|
||||
#define CTLCPU_CIPI 0x004
|
||||
#define CTLCPU_CRAM 0x300
|
||||
|
||||
/*
|
||||
* Read a config register for the given slot.
|
||||
*/
|
||||
static
|
||||
inline
|
||||
uint32_t
|
||||
read_cfg_register(struct lamebus_softc *lb, int slot, uint32_t offset)
|
||||
{
|
||||
/* Note that lb might be NULL on some platforms in some contexts. */
|
||||
offset += LB_CONFIG_SIZE*slot;
|
||||
return lamebus_read_register(lb, LB_CONTROLLER_SLOT, offset);
|
||||
static inline uint32_t read_cfg_register(struct lamebus_softc *lb, int slot,
|
||||
uint32_t offset) {
|
||||
/* Note that lb might be NULL on some platforms in some contexts. */
|
||||
offset += LB_CONFIG_SIZE * slot;
|
||||
return lamebus_read_register(lb, LB_CONTROLLER_SLOT, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a config register for a given slot.
|
||||
*/
|
||||
static
|
||||
inline
|
||||
void
|
||||
write_cfg_register(struct lamebus_softc *lb, int slot, uint32_t offset,
|
||||
uint32_t val)
|
||||
{
|
||||
offset += LB_CONFIG_SIZE*slot;
|
||||
lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val);
|
||||
static inline void write_cfg_register(struct lamebus_softc *lb, int slot,
|
||||
uint32_t offset, uint32_t val) {
|
||||
offset += LB_CONFIG_SIZE * slot;
|
||||
lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read one of the bus controller's registers.
|
||||
*/
|
||||
static
|
||||
inline
|
||||
uint32_t
|
||||
read_ctl_register(struct lamebus_softc *lb, uint32_t offset)
|
||||
{
|
||||
/* Note that lb might be NULL on some platforms in some contexts. */
|
||||
return read_cfg_register(lb, LB_CONTROLLER_SLOT, offset);
|
||||
static inline uint32_t read_ctl_register(struct lamebus_softc *lb,
|
||||
uint32_t offset) {
|
||||
/* Note that lb might be NULL on some platforms in some contexts. */
|
||||
return read_cfg_register(lb, LB_CONTROLLER_SLOT, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write one of the bus controller's registers.
|
||||
*/
|
||||
static
|
||||
inline
|
||||
void
|
||||
write_ctl_register(struct lamebus_softc *lb, uint32_t offset, uint32_t val)
|
||||
{
|
||||
write_cfg_register(lb, LB_CONTROLLER_SLOT, offset, val);
|
||||
static inline void write_ctl_register(struct lamebus_softc *lb, uint32_t offset,
|
||||
uint32_t val) {
|
||||
write_cfg_register(lb, LB_CONTROLLER_SLOT, offset, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write one of the bus controller's CPU control registers.
|
||||
*/
|
||||
static
|
||||
inline
|
||||
void
|
||||
write_ctlcpu_register(struct lamebus_softc *lb, unsigned hw_cpunum,
|
||||
uint32_t offset, uint32_t val)
|
||||
{
|
||||
offset += LB_CTLCPU_OFFSET + hw_cpunum * LB_CTLCPU_SIZE;
|
||||
lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val);
|
||||
static inline void write_ctlcpu_register(struct lamebus_softc *lb,
|
||||
unsigned hw_cpunum, uint32_t offset,
|
||||
uint32_t val) {
|
||||
offset += LB_CTLCPU_OFFSET + hw_cpunum * LB_CTLCPU_SIZE;
|
||||
lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find and create secondary CPUs.
|
||||
*/
|
||||
void
|
||||
lamebus_find_cpus(struct lamebus_softc *lamebus)
|
||||
{
|
||||
uint32_t mainboard_vid, mainboard_did;
|
||||
uint32_t cpumask, self, bit, val;
|
||||
unsigned i, numcpus, bootcpu;
|
||||
unsigned hwnum[32];
|
||||
void lamebus_find_cpus(struct lamebus_softc *lamebus) {
|
||||
uint32_t mainboard_vid, mainboard_did;
|
||||
uint32_t cpumask, self, bit, val;
|
||||
unsigned i, numcpus, bootcpu;
|
||||
unsigned hwnum[32];
|
||||
|
||||
mainboard_vid = read_cfg_register(lamebus, LB_CONTROLLER_SLOT,
|
||||
CFGREG_VID);
|
||||
mainboard_did = read_cfg_register(lamebus, LB_CONTROLLER_SLOT,
|
||||
CFGREG_DID);
|
||||
if (mainboard_vid == LB_VENDOR_CS161 &&
|
||||
mainboard_did == LBCS161_UPBUSCTL) {
|
||||
/* Old uniprocessor mainboard; no cpu registers. */
|
||||
lamebus->ls_uniprocessor = 1;
|
||||
return;
|
||||
}
|
||||
mainboard_vid = read_cfg_register(lamebus, LB_CONTROLLER_SLOT, CFGREG_VID);
|
||||
mainboard_did = read_cfg_register(lamebus, LB_CONTROLLER_SLOT, CFGREG_DID);
|
||||
if (mainboard_vid == LB_VENDOR_CS161 && mainboard_did == LBCS161_UPBUSCTL) {
|
||||
/* Old uniprocessor mainboard; no cpu registers. */
|
||||
lamebus->ls_uniprocessor = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
|
||||
self = read_ctl_register(lamebus, CTLREG_SELF);
|
||||
cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
|
||||
self = read_ctl_register(lamebus, CTLREG_SELF);
|
||||
|
||||
numcpus = 0;
|
||||
bootcpu = 0;
|
||||
for (i=0; i<32; i++) {
|
||||
bit = (uint32_t)1 << i;
|
||||
if ((cpumask & bit) != 0) {
|
||||
if (self & bit) {
|
||||
bootcpu = numcpus;
|
||||
curcpu->c_hardware_number = i;
|
||||
}
|
||||
hwnum[numcpus] = i;
|
||||
numcpus++;
|
||||
}
|
||||
}
|
||||
numcpus = 0;
|
||||
bootcpu = 0;
|
||||
for (i = 0; i < 32; i++) {
|
||||
bit = (uint32_t)1 << i;
|
||||
if ((cpumask & bit) != 0) {
|
||||
if (self & bit) {
|
||||
bootcpu = numcpus;
|
||||
curcpu->c_hardware_number = i;
|
||||
}
|
||||
hwnum[numcpus] = i;
|
||||
numcpus++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<numcpus; i++) {
|
||||
if (i != bootcpu) {
|
||||
cpu_create(hwnum[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
if (i != bootcpu) {
|
||||
cpu_create(hwnum[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* By default, route all interrupts only to the boot cpu. We
|
||||
* could be arbitrarily more elaborate, up to things like
|
||||
* dynamic load balancing.
|
||||
*/
|
||||
/*
|
||||
* By default, route all interrupts only to the boot cpu. We
|
||||
* could be arbitrarily more elaborate, up to things like
|
||||
* dynamic load balancing.
|
||||
*/
|
||||
|
||||
for (i=0; i<numcpus; i++) {
|
||||
if (i != bootcpu) {
|
||||
val = 0;
|
||||
}
|
||||
else {
|
||||
val = 0xffffffff;
|
||||
}
|
||||
write_ctlcpu_register(lamebus, hwnum[i], CTLCPU_CIRQE, val);
|
||||
}
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
if (i != bootcpu) {
|
||||
val = 0;
|
||||
} else {
|
||||
val = 0xffffffff;
|
||||
}
|
||||
write_ctlcpu_register(lamebus, hwnum[i], CTLCPU_CIRQE, val);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -193,43 +170,40 @@ lamebus_find_cpus(struct lamebus_softc *lamebus)
|
||||
* LAMEbus; if in some environment there are other CPUs about as well
|
||||
* this logic will have to be made more complex.
|
||||
*/
|
||||
void
|
||||
lamebus_start_cpus(struct lamebus_softc *lamebus)
|
||||
{
|
||||
uint32_t cpumask, self, bit;
|
||||
uint32_t ctlcpuoffset;
|
||||
uint32_t *cram;
|
||||
unsigned i;
|
||||
unsigned cpunum;
|
||||
void lamebus_start_cpus(struct lamebus_softc *lamebus) {
|
||||
uint32_t cpumask, self, bit;
|
||||
uint32_t ctlcpuoffset;
|
||||
uint32_t *cram;
|
||||
unsigned i;
|
||||
unsigned cpunum;
|
||||
|
||||
if (lamebus->ls_uniprocessor) {
|
||||
return;
|
||||
}
|
||||
if (lamebus->ls_uniprocessor) {
|
||||
return;
|
||||
}
|
||||
|
||||
cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
|
||||
self = read_ctl_register(lamebus, CTLREG_SELF);
|
||||
cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
|
||||
self = read_ctl_register(lamebus, CTLREG_SELF);
|
||||
|
||||
/* Poke in the startup address. */
|
||||
cpunum = 1;
|
||||
for (i=0; i<32; i++) {
|
||||
bit = (uint32_t)1 << i;
|
||||
if ((cpumask & bit) != 0) {
|
||||
if (self & bit) {
|
||||
continue;
|
||||
}
|
||||
ctlcpuoffset = LB_CTLCPU_OFFSET + i * LB_CTLCPU_SIZE;
|
||||
cram = lamebus_map_area(lamebus,
|
||||
LB_CONTROLLER_SLOT,
|
||||
ctlcpuoffset + CTLCPU_CRAM);
|
||||
cram[0] = (uint32_t)cpu_start_secondary;
|
||||
cram[1] = cpunum++;
|
||||
}
|
||||
}
|
||||
/* Ensure all the above writes get flushed. */
|
||||
membar_store_store();
|
||||
/* Poke in the startup address. */
|
||||
cpunum = 1;
|
||||
for (i = 0; i < 32; i++) {
|
||||
bit = (uint32_t)1 << i;
|
||||
if ((cpumask & bit) != 0) {
|
||||
if (self & bit) {
|
||||
continue;
|
||||
}
|
||||
ctlcpuoffset = LB_CTLCPU_OFFSET + i * LB_CTLCPU_SIZE;
|
||||
cram = lamebus_map_area(lamebus, LB_CONTROLLER_SLOT,
|
||||
ctlcpuoffset + CTLCPU_CRAM);
|
||||
cram[0] = (uint32_t)cpu_start_secondary;
|
||||
cram[1] = cpunum++;
|
||||
}
|
||||
}
|
||||
/* Ensure all the above writes get flushed. */
|
||||
membar_store_store();
|
||||
|
||||
/* Now, enable them all. */
|
||||
write_ctl_register(lamebus, CTLREG_CPUE, cpumask);
|
||||
/* Now, enable them all. */
|
||||
write_ctl_register(lamebus, CTLREG_CPUE, cpumask);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -247,58 +221,55 @@ lamebus_start_cpus(struct lamebus_softc *lamebus)
|
||||
* more specific checks.
|
||||
*/
|
||||
|
||||
int
|
||||
lamebus_probe(struct lamebus_softc *sc,
|
||||
uint32_t vendorid, uint32_t deviceid,
|
||||
uint32_t lowver, uint32_t *version_ret)
|
||||
{
|
||||
int slot;
|
||||
uint32_t val;
|
||||
int lamebus_probe(struct lamebus_softc *sc, uint32_t vendorid,
|
||||
uint32_t deviceid, uint32_t lowver, uint32_t *version_ret) {
|
||||
int slot;
|
||||
uint32_t val;
|
||||
|
||||
/*
|
||||
* Because the slot information in sc is used when dispatching
|
||||
* interrupts, disable interrupts while working with it.
|
||||
*/
|
||||
/*
|
||||
* Because the slot information in sc is used when dispatching
|
||||
* interrupts, disable interrupts while working with it.
|
||||
*/
|
||||
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
|
||||
for (slot=0; slot<LB_NSLOTS; slot++) {
|
||||
if (sc->ls_slotsinuse & (1<<slot)) {
|
||||
/* Slot already in use; skip */
|
||||
continue;
|
||||
}
|
||||
for (slot = 0; slot < LB_NSLOTS; slot++) {
|
||||
if (sc->ls_slotsinuse & (1 << slot)) {
|
||||
/* Slot already in use; skip */
|
||||
continue;
|
||||
}
|
||||
|
||||
val = read_cfg_register(sc, slot, CFGREG_VID);
|
||||
if (val!=vendorid) {
|
||||
/* Wrong vendor id */
|
||||
continue;
|
||||
}
|
||||
val = read_cfg_register(sc, slot, CFGREG_VID);
|
||||
if (val != vendorid) {
|
||||
/* Wrong vendor id */
|
||||
continue;
|
||||
}
|
||||
|
||||
val = read_cfg_register(sc, slot, CFGREG_DID);
|
||||
if (val != deviceid) {
|
||||
/* Wrong device id */
|
||||
continue;
|
||||
}
|
||||
val = read_cfg_register(sc, slot, CFGREG_DID);
|
||||
if (val != deviceid) {
|
||||
/* Wrong device id */
|
||||
continue;
|
||||
}
|
||||
|
||||
val = read_cfg_register(sc, slot, CFGREG_DRL);
|
||||
if (val < lowver) {
|
||||
/* Unsupported device revision */
|
||||
continue;
|
||||
}
|
||||
if (version_ret != NULL) {
|
||||
*version_ret = val;
|
||||
}
|
||||
val = read_cfg_register(sc, slot, CFGREG_DRL);
|
||||
if (val < lowver) {
|
||||
/* Unsupported device revision */
|
||||
continue;
|
||||
}
|
||||
if (version_ret != NULL) {
|
||||
*version_ret = val;
|
||||
}
|
||||
|
||||
/* Found something */
|
||||
/* Found something */
|
||||
|
||||
spinlock_release(&sc->ls_lock);
|
||||
return slot;
|
||||
}
|
||||
spinlock_release(&sc->ls_lock);
|
||||
return slot;
|
||||
}
|
||||
|
||||
/* Found nothing */
|
||||
/* Found nothing */
|
||||
|
||||
spinlock_release(&sc->ls_lock);
|
||||
return -1;
|
||||
spinlock_release(&sc->ls_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -306,360 +277,328 @@ lamebus_probe(struct lamebus_softc *sc,
|
||||
* This prevents the probe routine from returning the same device over
|
||||
* and over again.
|
||||
*/
|
||||
void
|
||||
lamebus_mark(struct lamebus_softc *sc, int slot)
|
||||
{
|
||||
uint32_t mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot>=0 && slot < LB_NSLOTS);
|
||||
void lamebus_mark(struct lamebus_softc *sc, int slot) {
|
||||
uint32_t mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
|
||||
if ((sc->ls_slotsinuse & mask)!=0) {
|
||||
panic("lamebus_mark: slot %d already in use\n", slot);
|
||||
}
|
||||
if ((sc->ls_slotsinuse & mask) != 0) {
|
||||
panic("lamebus_mark: slot %d already in use\n", slot);
|
||||
}
|
||||
|
||||
sc->ls_slotsinuse |= mask;
|
||||
sc->ls_slotsinuse |= mask;
|
||||
|
||||
spinlock_release(&sc->ls_lock);
|
||||
spinlock_release(&sc->ls_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark that a slot is no longer in use.
|
||||
*/
|
||||
void
|
||||
lamebus_unmark(struct lamebus_softc *sc, int slot)
|
||||
{
|
||||
uint32_t mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot>=0 && slot < LB_NSLOTS);
|
||||
void lamebus_unmark(struct lamebus_softc *sc, int slot) {
|
||||
uint32_t mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
|
||||
if ((sc->ls_slotsinuse & mask)==0) {
|
||||
panic("lamebus_mark: slot %d not marked in use\n", slot);
|
||||
}
|
||||
if ((sc->ls_slotsinuse & mask) == 0) {
|
||||
panic("lamebus_mark: slot %d not marked in use\n", slot);
|
||||
}
|
||||
|
||||
sc->ls_slotsinuse &= ~mask;
|
||||
sc->ls_slotsinuse &= ~mask;
|
||||
|
||||
spinlock_release(&sc->ls_lock);
|
||||
spinlock_release(&sc->ls_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a function (and a device context pointer) to be called
|
||||
* when a particular slot signals an interrupt.
|
||||
*/
|
||||
void
|
||||
lamebus_attach_interrupt(struct lamebus_softc *sc, int slot,
|
||||
void *devdata,
|
||||
void (*irqfunc)(void *devdata))
|
||||
{
|
||||
uint32_t mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot>=0 && slot < LB_NSLOTS);
|
||||
void lamebus_attach_interrupt(struct lamebus_softc *sc, int slot, void *devdata,
|
||||
void (*irqfunc)(void *devdata)) {
|
||||
uint32_t mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
|
||||
if ((sc->ls_slotsinuse & mask)==0) {
|
||||
panic("lamebus_attach_interrupt: slot %d not marked in use\n",
|
||||
slot);
|
||||
}
|
||||
if ((sc->ls_slotsinuse & mask) == 0) {
|
||||
panic("lamebus_attach_interrupt: slot %d not marked in use\n", slot);
|
||||
}
|
||||
|
||||
KASSERT(sc->ls_devdata[slot]==NULL);
|
||||
KASSERT(sc->ls_irqfuncs[slot]==NULL);
|
||||
KASSERT(sc->ls_devdata[slot] == NULL);
|
||||
KASSERT(sc->ls_irqfuncs[slot] == NULL);
|
||||
|
||||
sc->ls_devdata[slot] = devdata;
|
||||
sc->ls_irqfuncs[slot] = irqfunc;
|
||||
sc->ls_devdata[slot] = devdata;
|
||||
sc->ls_irqfuncs[slot] = irqfunc;
|
||||
|
||||
spinlock_release(&sc->ls_lock);
|
||||
spinlock_release(&sc->ls_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unregister a function that was being called when a particular slot
|
||||
* signaled an interrupt.
|
||||
*/
|
||||
void
|
||||
lamebus_detach_interrupt(struct lamebus_softc *sc, int slot)
|
||||
{
|
||||
uint32_t mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot>=0 && slot < LB_NSLOTS);
|
||||
void lamebus_detach_interrupt(struct lamebus_softc *sc, int slot) {
|
||||
uint32_t mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
|
||||
if ((sc->ls_slotsinuse & mask)==0) {
|
||||
panic("lamebus_detach_interrupt: slot %d not marked in use\n",
|
||||
slot);
|
||||
}
|
||||
if ((sc->ls_slotsinuse & mask) == 0) {
|
||||
panic("lamebus_detach_interrupt: slot %d not marked in use\n", slot);
|
||||
}
|
||||
|
||||
KASSERT(sc->ls_irqfuncs[slot]!=NULL);
|
||||
KASSERT(sc->ls_irqfuncs[slot] != NULL);
|
||||
|
||||
sc->ls_devdata[slot] = NULL;
|
||||
sc->ls_irqfuncs[slot] = NULL;
|
||||
sc->ls_devdata[slot] = NULL;
|
||||
sc->ls_irqfuncs[slot] = NULL;
|
||||
|
||||
spinlock_release(&sc->ls_lock);
|
||||
spinlock_release(&sc->ls_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mask/unmask an interrupt using the global IRQE register.
|
||||
*/
|
||||
void
|
||||
lamebus_mask_interrupt(struct lamebus_softc *lamebus, int slot)
|
||||
{
|
||||
uint32_t bits, mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||
void lamebus_mask_interrupt(struct lamebus_softc *lamebus, int slot) {
|
||||
uint32_t bits, mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||
|
||||
spinlock_acquire(&lamebus->ls_lock);
|
||||
bits = read_ctl_register(lamebus, CTLREG_IRQE);
|
||||
bits &= ~mask;
|
||||
write_ctl_register(lamebus, CTLREG_IRQE, bits);
|
||||
spinlock_release(&lamebus->ls_lock);
|
||||
spinlock_acquire(&lamebus->ls_lock);
|
||||
bits = read_ctl_register(lamebus, CTLREG_IRQE);
|
||||
bits &= ~mask;
|
||||
write_ctl_register(lamebus, CTLREG_IRQE, bits);
|
||||
spinlock_release(&lamebus->ls_lock);
|
||||
}
|
||||
|
||||
void
|
||||
lamebus_unmask_interrupt(struct lamebus_softc *lamebus, int slot)
|
||||
{
|
||||
uint32_t bits, mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||
void lamebus_unmask_interrupt(struct lamebus_softc *lamebus, int slot) {
|
||||
uint32_t bits, mask = ((uint32_t)1) << slot;
|
||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||
|
||||
spinlock_acquire(&lamebus->ls_lock);
|
||||
bits = read_ctl_register(lamebus, CTLREG_IRQE);
|
||||
bits |= mask;
|
||||
write_ctl_register(lamebus, CTLREG_IRQE, bits);
|
||||
spinlock_release(&lamebus->ls_lock);
|
||||
spinlock_acquire(&lamebus->ls_lock);
|
||||
bits = read_ctl_register(lamebus, CTLREG_IRQE);
|
||||
bits |= mask;
|
||||
write_ctl_register(lamebus, CTLREG_IRQE, bits);
|
||||
spinlock_release(&lamebus->ls_lock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* LAMEbus interrupt handling function. (Machine-independent!)
|
||||
*/
|
||||
void
|
||||
lamebus_interrupt(struct lamebus_softc *lamebus)
|
||||
{
|
||||
/*
|
||||
* Note that despite the fact that "spl" stands for "set
|
||||
* priority level", we don't actually support interrupt
|
||||
* priorities. When an interrupt happens, we look through the
|
||||
* slots to find the first interrupting device and call its
|
||||
* interrupt routine, no matter what that device is.
|
||||
*
|
||||
* Note that the entire LAMEbus uses only one on-cpu interrupt line.
|
||||
* Thus, we do not use any on-cpu interrupt priority system either.
|
||||
*/
|
||||
void lamebus_interrupt(struct lamebus_softc *lamebus) {
|
||||
/*
|
||||
* Note that despite the fact that "spl" stands for "set
|
||||
* priority level", we don't actually support interrupt
|
||||
* priorities. When an interrupt happens, we look through the
|
||||
* slots to find the first interrupting device and call its
|
||||
* interrupt routine, no matter what that device is.
|
||||
*
|
||||
* Note that the entire LAMEbus uses only one on-cpu interrupt line.
|
||||
* Thus, we do not use any on-cpu interrupt priority system either.
|
||||
*/
|
||||
|
||||
int slot;
|
||||
uint32_t mask;
|
||||
uint32_t irqs;
|
||||
void (*handler)(void *);
|
||||
void *data;
|
||||
int slot;
|
||||
uint32_t mask;
|
||||
uint32_t irqs;
|
||||
void (*handler)(void *);
|
||||
void *data;
|
||||
|
||||
/* For keeping track of how many bogus things happen in a row. */
|
||||
static int duds = 0;
|
||||
int duds_this_time = 0;
|
||||
/* For keeping track of how many bogus things happen in a row. */
|
||||
static int duds = 0;
|
||||
int duds_this_time = 0;
|
||||
|
||||
/* and we better have a valid bus instance. */
|
||||
KASSERT(lamebus != NULL);
|
||||
/* and we better have a valid bus instance. */
|
||||
KASSERT(lamebus != NULL);
|
||||
|
||||
/* Lock the softc */
|
||||
spinlock_acquire(&lamebus->ls_lock);
|
||||
/* Lock the softc */
|
||||
spinlock_acquire(&lamebus->ls_lock);
|
||||
|
||||
/*
|
||||
* Read the LAMEbus controller register that tells us which
|
||||
* slots are asserting an interrupt condition.
|
||||
*/
|
||||
irqs = read_ctl_register(lamebus, CTLREG_IRQS);
|
||||
/*
|
||||
* Read the LAMEbus controller register that tells us which
|
||||
* slots are asserting an interrupt condition.
|
||||
*/
|
||||
irqs = read_ctl_register(lamebus, CTLREG_IRQS);
|
||||
|
||||
if (irqs == 0) {
|
||||
/*
|
||||
* Huh? None of them? Must be a glitch.
|
||||
*/
|
||||
kprintf("lamebus: stray interrupt on cpu %u\n",
|
||||
curcpu->c_number);
|
||||
duds++;
|
||||
duds_this_time++;
|
||||
if (irqs == 0) {
|
||||
/*
|
||||
* Huh? None of them? Must be a glitch.
|
||||
*/
|
||||
kprintf("lamebus: stray interrupt on cpu %u\n", curcpu->c_number);
|
||||
duds++;
|
||||
duds_this_time++;
|
||||
|
||||
/*
|
||||
* We could just return now, but instead we'll
|
||||
* continue ahead. Because irqs == 0, nothing in the
|
||||
* loop will execute, and passing through it gets us
|
||||
* to the code that checks how many duds we've
|
||||
* seen. This is important, because we just might get
|
||||
* a stray interrupt that latches itself on. If that
|
||||
* happens, we're pretty much toast, but it's better
|
||||
* to panic and hopefully reset the system than to
|
||||
* loop forever printing "stray interrupt".
|
||||
*/
|
||||
}
|
||||
/*
|
||||
* We could just return now, but instead we'll
|
||||
* continue ahead. Because irqs == 0, nothing in the
|
||||
* loop will execute, and passing through it gets us
|
||||
* to the code that checks how many duds we've
|
||||
* seen. This is important, because we just might get
|
||||
* a stray interrupt that latches itself on. If that
|
||||
* happens, we're pretty much toast, but it's better
|
||||
* to panic and hopefully reset the system than to
|
||||
* loop forever printing "stray interrupt".
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through the bits in the value we got back to see which
|
||||
* ones are set.
|
||||
*/
|
||||
/*
|
||||
* Go through the bits in the value we got back to see which
|
||||
* ones are set.
|
||||
*/
|
||||
|
||||
for (mask=1, slot=0; slot<LB_NSLOTS; mask<<=1, slot++) {
|
||||
if ((irqs & mask) == 0) {
|
||||
/* Nope. */
|
||||
continue;
|
||||
}
|
||||
for (mask = 1, slot = 0; slot < LB_NSLOTS; mask <<= 1, slot++) {
|
||||
if ((irqs & mask) == 0) {
|
||||
/* Nope. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* This slot is signalling an interrupt.
|
||||
*/
|
||||
/*
|
||||
* This slot is signalling an interrupt.
|
||||
*/
|
||||
|
||||
if ((lamebus->ls_slotsinuse & mask)==0) {
|
||||
/*
|
||||
* No device driver is using this slot.
|
||||
*/
|
||||
duds++;
|
||||
duds_this_time++;
|
||||
continue;
|
||||
}
|
||||
if ((lamebus->ls_slotsinuse & mask) == 0) {
|
||||
/*
|
||||
* No device driver is using this slot.
|
||||
*/
|
||||
duds++;
|
||||
duds_this_time++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lamebus->ls_irqfuncs[slot]==NULL) {
|
||||
/*
|
||||
* The device driver hasn't installed an interrupt
|
||||
* handler.
|
||||
*/
|
||||
duds++;
|
||||
duds_this_time++;
|
||||
continue;
|
||||
}
|
||||
if (lamebus->ls_irqfuncs[slot] == NULL) {
|
||||
/*
|
||||
* The device driver hasn't installed an interrupt
|
||||
* handler.
|
||||
*/
|
||||
duds++;
|
||||
duds_this_time++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the interrupt handler. Release the spinlock
|
||||
* while we do so, in case other CPUs are handling
|
||||
* interrupts on other devices.
|
||||
*/
|
||||
handler = lamebus->ls_irqfuncs[slot];
|
||||
data = lamebus->ls_devdata[slot];
|
||||
spinlock_release(&lamebus->ls_lock);
|
||||
/*
|
||||
* Call the interrupt handler. Release the spinlock
|
||||
* while we do so, in case other CPUs are handling
|
||||
* interrupts on other devices.
|
||||
*/
|
||||
handler = lamebus->ls_irqfuncs[slot];
|
||||
data = lamebus->ls_devdata[slot];
|
||||
spinlock_release(&lamebus->ls_lock);
|
||||
|
||||
handler(data);
|
||||
handler(data);
|
||||
|
||||
spinlock_acquire(&lamebus->ls_lock);
|
||||
spinlock_acquire(&lamebus->ls_lock);
|
||||
|
||||
/*
|
||||
* Reload the mask of pending IRQs - if we just called
|
||||
* hardclock, we might not have come back to this
|
||||
* context for some time, and it might have changed.
|
||||
*/
|
||||
/*
|
||||
* Reload the mask of pending IRQs - if we just called
|
||||
* hardclock, we might not have come back to this
|
||||
* context for some time, and it might have changed.
|
||||
*/
|
||||
|
||||
irqs = read_ctl_register(lamebus, CTLREG_IRQS);
|
||||
}
|
||||
irqs = read_ctl_register(lamebus, CTLREG_IRQS);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get interrupts for a slot with no driver or no
|
||||
* interrupt handler, it's fairly serious. Because LAMEbus
|
||||
* uses level-triggered interrupts, if we don't shut off the
|
||||
* condition, we'll keep getting interrupted continuously and
|
||||
* the system will make no progress. But we don't know how to
|
||||
* do that if there's no driver or no interrupt handler.
|
||||
*
|
||||
* So, if we get too many dud interrupts, panic, since it's
|
||||
* better to panic and reset than to hang.
|
||||
*
|
||||
* If we get through here without seeing any duds this time,
|
||||
* the condition, whatever it was, has gone away. It might be
|
||||
* some stupid device we don't have a driver for, or it might
|
||||
* have been an electrical transient. In any case, warn and
|
||||
* clear the dud count.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If we get interrupts for a slot with no driver or no
|
||||
* interrupt handler, it's fairly serious. Because LAMEbus
|
||||
* uses level-triggered interrupts, if we don't shut off the
|
||||
* condition, we'll keep getting interrupted continuously and
|
||||
* the system will make no progress. But we don't know how to
|
||||
* do that if there's no driver or no interrupt handler.
|
||||
*
|
||||
* So, if we get too many dud interrupts, panic, since it's
|
||||
* better to panic and reset than to hang.
|
||||
*
|
||||
* If we get through here without seeing any duds this time,
|
||||
* the condition, whatever it was, has gone away. It might be
|
||||
* some stupid device we don't have a driver for, or it might
|
||||
* have been an electrical transient. In any case, warn and
|
||||
* clear the dud count.
|
||||
*/
|
||||
if (duds_this_time == 0 && duds > 0) {
|
||||
kprintf("lamebus: %d dud interrupts\n", duds);
|
||||
duds = 0;
|
||||
}
|
||||
|
||||
if (duds_this_time == 0 && duds > 0) {
|
||||
kprintf("lamebus: %d dud interrupts\n", duds);
|
||||
duds = 0;
|
||||
}
|
||||
if (duds > 10000) {
|
||||
panic("lamebus: too many (%d) dud interrupts\n", duds);
|
||||
}
|
||||
|
||||
if (duds > 10000) {
|
||||
panic("lamebus: too many (%d) dud interrupts\n", duds);
|
||||
}
|
||||
|
||||
/* Unlock the softc */
|
||||
spinlock_release(&lamebus->ls_lock);
|
||||
/* Unlock the softc */
|
||||
spinlock_release(&lamebus->ls_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Have the bus controller power the system off.
|
||||
*/
|
||||
void
|
||||
lamebus_poweroff(struct lamebus_softc *lamebus)
|
||||
{
|
||||
/*
|
||||
* Write 0 to the power register to shut the system off.
|
||||
*/
|
||||
void lamebus_poweroff(struct lamebus_softc *lamebus) {
|
||||
/*
|
||||
* Write 0 to the power register to shut the system off.
|
||||
*/
|
||||
|
||||
cpu_irqoff();
|
||||
write_ctl_register(lamebus, CTLREG_PWR, 0);
|
||||
cpu_irqoff();
|
||||
write_ctl_register(lamebus, CTLREG_PWR, 0);
|
||||
|
||||
/* The power doesn't go off instantly... so halt the cpu. */
|
||||
cpu_halt();
|
||||
/* The power doesn't go off instantly... so halt the cpu. */
|
||||
cpu_halt();
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask the bus controller how much memory we have.
|
||||
*/
|
||||
uint32_t
|
||||
lamebus_ramsize(void)
|
||||
{
|
||||
/*
|
||||
* Note that this has to work before bus initialization.
|
||||
* On machines where lamebus_read_register doesn't work
|
||||
* before bus initialization, this function can't be used
|
||||
* for initial RAM size lookup.
|
||||
*/
|
||||
uint32_t lamebus_ramsize(void) {
|
||||
/*
|
||||
* Note that this has to work before bus initialization.
|
||||
* On machines where lamebus_read_register doesn't work
|
||||
* before bus initialization, this function can't be used
|
||||
* for initial RAM size lookup.
|
||||
*/
|
||||
|
||||
return read_ctl_register(NULL, CTLREG_RAMSZ);
|
||||
return read_ctl_register(NULL, CTLREG_RAMSZ);
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn on or off the interprocessor interrupt line for a given CPU.
|
||||
*/
|
||||
void
|
||||
lamebus_assert_ipi(struct lamebus_softc *lamebus, struct cpu *target)
|
||||
{
|
||||
if (lamebus->ls_uniprocessor) {
|
||||
return;
|
||||
}
|
||||
write_ctlcpu_register(lamebus, target->c_hardware_number,
|
||||
CTLCPU_CIPI, 1);
|
||||
void lamebus_assert_ipi(struct lamebus_softc *lamebus, struct cpu *target) {
|
||||
if (lamebus->ls_uniprocessor) {
|
||||
return;
|
||||
}
|
||||
write_ctlcpu_register(lamebus, target->c_hardware_number, CTLCPU_CIPI, 1);
|
||||
}
|
||||
|
||||
void
|
||||
lamebus_clear_ipi(struct lamebus_softc *lamebus, struct cpu *target)
|
||||
{
|
||||
if (lamebus->ls_uniprocessor) {
|
||||
return;
|
||||
}
|
||||
write_ctlcpu_register(lamebus, target->c_hardware_number,
|
||||
CTLCPU_CIPI, 0);
|
||||
void lamebus_clear_ipi(struct lamebus_softc *lamebus, struct cpu *target) {
|
||||
if (lamebus->ls_uniprocessor) {
|
||||
return;
|
||||
}
|
||||
write_ctlcpu_register(lamebus, target->c_hardware_number, CTLCPU_CIPI, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initial setup.
|
||||
* Should be called from mainbus_bootstrap().
|
||||
*/
|
||||
struct lamebus_softc *
|
||||
lamebus_init(void)
|
||||
{
|
||||
struct lamebus_softc *lamebus;
|
||||
int i;
|
||||
struct lamebus_softc *lamebus_init(void) {
|
||||
struct lamebus_softc *lamebus;
|
||||
int i;
|
||||
|
||||
/* Allocate space for lamebus data */
|
||||
lamebus = kmalloc(sizeof(struct lamebus_softc));
|
||||
if (lamebus==NULL) {
|
||||
panic("lamebus_init: Out of memory\n");
|
||||
}
|
||||
/* Allocate space for lamebus data */
|
||||
lamebus = kmalloc(sizeof(struct lamebus_softc));
|
||||
if (lamebus == NULL) {
|
||||
panic("lamebus_init: Out of memory\n");
|
||||
}
|
||||
|
||||
spinlock_init(&lamebus->ls_lock);
|
||||
spinlock_init(&lamebus->ls_lock);
|
||||
|
||||
/*
|
||||
* Initialize the LAMEbus data structure.
|
||||
*/
|
||||
lamebus->ls_slotsinuse = 1 << LB_CONTROLLER_SLOT;
|
||||
/*
|
||||
* Initialize the LAMEbus data structure.
|
||||
*/
|
||||
lamebus->ls_slotsinuse = 1 << LB_CONTROLLER_SLOT;
|
||||
|
||||
for (i=0; i<LB_NSLOTS; i++) {
|
||||
lamebus->ls_devdata[i] = NULL;
|
||||
lamebus->ls_irqfuncs[i] = NULL;
|
||||
}
|
||||
for (i = 0; i < LB_NSLOTS; i++) {
|
||||
lamebus->ls_devdata[i] = NULL;
|
||||
lamebus->ls_irqfuncs[i] = NULL;
|
||||
}
|
||||
|
||||
lamebus->ls_uniprocessor = 0;
|
||||
lamebus->ls_uniprocessor = 0;
|
||||
|
||||
return lamebus;
|
||||
return lamebus;
|
||||
}
|
||||
|
@ -39,39 +39,38 @@
|
||||
* Machine-independent definitions.
|
||||
*/
|
||||
|
||||
|
||||
/* Vendors */
|
||||
#define LB_VENDOR_CS161 1
|
||||
#define LB_VENDOR_CS161 1
|
||||
|
||||
/* CS161 devices */
|
||||
#define LBCS161_UPBUSCTL 1
|
||||
#define LBCS161_TIMER 2
|
||||
#define LBCS161_DISK 3
|
||||
#define LBCS161_SERIAL 4
|
||||
#define LBCS161_SCREEN 5
|
||||
#define LBCS161_NET 6
|
||||
#define LBCS161_EMUFS 7
|
||||
#define LBCS161_TRACE 8
|
||||
#define LBCS161_RANDOM 9
|
||||
#define LBCS161_MPBUSCTL 10
|
||||
#define LBCS161_UPBUSCTL 1
|
||||
#define LBCS161_TIMER 2
|
||||
#define LBCS161_DISK 3
|
||||
#define LBCS161_SERIAL 4
|
||||
#define LBCS161_SCREEN 5
|
||||
#define LBCS161_NET 6
|
||||
#define LBCS161_EMUFS 7
|
||||
#define LBCS161_TRACE 8
|
||||
#define LBCS161_RANDOM 9
|
||||
#define LBCS161_MPBUSCTL 10
|
||||
|
||||
/* LAMEbus controller always goes in slot 31 */
|
||||
#define LB_CONTROLLER_SLOT 31
|
||||
#define LB_CONTROLLER_SLOT 31
|
||||
|
||||
/* Number of slots */
|
||||
#define LB_NSLOTS 32
|
||||
#define LB_NSLOTS 32
|
||||
|
||||
/* LAMEbus controller per-slot config space */
|
||||
#define LB_CONFIG_SIZE 1024
|
||||
#define LB_CONFIG_SIZE 1024
|
||||
|
||||
/* LAMEbus controller per-cpu control space */
|
||||
#define LB_CTLCPU_SIZE 1024
|
||||
#define LB_CTLCPU_SIZE 1024
|
||||
|
||||
/* LAMEbus controller slot offset to per-cpu control space */
|
||||
#define LB_CTLCPU_OFFSET 32768
|
||||
#define LB_CTLCPU_OFFSET 32768
|
||||
|
||||
/* LAMEbus mapping size per slot */
|
||||
#define LB_SLOT_SIZE 65536
|
||||
#define LB_SLOT_SIZE 65536
|
||||
|
||||
/* Pointer to kind of function called on interrupt */
|
||||
typedef void (*lb_irqfunc)(void *devdata);
|
||||
@ -80,15 +79,15 @@ typedef void (*lb_irqfunc)(void *devdata);
|
||||
* Driver data
|
||||
*/
|
||||
struct lamebus_softc {
|
||||
struct spinlock ls_lock;
|
||||
struct spinlock ls_lock;
|
||||
|
||||
/* Accessed from interrupts; synchronized with ls_lock */
|
||||
uint32_t ls_slotsinuse;
|
||||
void *ls_devdata[LB_NSLOTS];
|
||||
lb_irqfunc ls_irqfuncs[LB_NSLOTS];
|
||||
/* Accessed from interrupts; synchronized with ls_lock */
|
||||
uint32_t ls_slotsinuse;
|
||||
void *ls_devdata[LB_NSLOTS];
|
||||
lb_irqfunc ls_irqfuncs[LB_NSLOTS];
|
||||
|
||||
/* Read-only once set early in boot */
|
||||
unsigned ls_uniprocessor;
|
||||
/* Read-only once set early in boot */
|
||||
unsigned ls_uniprocessor;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -113,9 +112,8 @@ void lamebus_start_cpus(struct lamebus_softc *lamebus);
|
||||
*
|
||||
* Returns a slot number (0-31) or -1 if no such device is found.
|
||||
*/
|
||||
int lamebus_probe(struct lamebus_softc *,
|
||||
uint32_t vendorid, uint32_t deviceid,
|
||||
uint32_t lowver, uint32_t *version_ret);
|
||||
int lamebus_probe(struct lamebus_softc *, uint32_t vendorid, uint32_t deviceid,
|
||||
uint32_t lowver, uint32_t *version_ret);
|
||||
|
||||
/*
|
||||
* Mark a slot in-use (that is, has a device driver attached to it),
|
||||
@ -128,9 +126,8 @@ void lamebus_unmark(struct lamebus_softc *, int slot);
|
||||
/*
|
||||
* Attach to an interrupt.
|
||||
*/
|
||||
void lamebus_attach_interrupt(struct lamebus_softc *, int slot,
|
||||
void *devdata,
|
||||
void (*irqfunc)(void *devdata));
|
||||
void lamebus_attach_interrupt(struct lamebus_softc *, int slot, void *devdata,
|
||||
void (*irqfunc)(void *devdata));
|
||||
/*
|
||||
* Detach from interrupt.
|
||||
*/
|
||||
@ -168,15 +165,13 @@ void lamebus_clear_ipi(struct lamebus_softc *, struct cpu *targetcpu);
|
||||
* (Machine dependent.)
|
||||
*/
|
||||
uint32_t lamebus_read_register(struct lamebus_softc *, int slot,
|
||||
uint32_t offset);
|
||||
void lamebus_write_register(struct lamebus_softc *, int slot,
|
||||
uint32_t offset, uint32_t val);
|
||||
uint32_t offset);
|
||||
void lamebus_write_register(struct lamebus_softc *, int slot, uint32_t offset,
|
||||
uint32_t val);
|
||||
|
||||
/*
|
||||
* Map a buffer that starts at offset OFFSET within slot SLOT.
|
||||
*/
|
||||
void *lamebus_map_area(struct lamebus_softc *, int slot,
|
||||
uint32_t offset);
|
||||
|
||||
void *lamebus_map_area(struct lamebus_softc *, int slot, uint32_t offset);
|
||||
|
||||
#endif /* _LAMEBUS_H_ */
|
||||
|
@ -43,68 +43,60 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Registers (offsets within slot) */
|
||||
#define LHD_REG_NSECT 0 /* Number of sectors */
|
||||
#define LHD_REG_STAT 4 /* Status */
|
||||
#define LHD_REG_SECT 8 /* Sector for I/O */
|
||||
#define LHD_REG_RPM 12 /* Disk rotation speed (revs per minute) */
|
||||
#define LHD_REG_NSECT 0 /* Number of sectors */
|
||||
#define LHD_REG_STAT 4 /* Status */
|
||||
#define LHD_REG_SECT 8 /* Sector for I/O */
|
||||
#define LHD_REG_RPM 12 /* Disk rotation speed (revs per minute) */
|
||||
|
||||
/* Status codes */
|
||||
#define LHD_IDLE 0 /* Device idle */
|
||||
#define LHD_WORKING 1 /* Operation in progress */
|
||||
#define LHD_OK 4 /* Operation succeeded */
|
||||
#define LHD_INVSECT 12 /* Invalid sector requested */
|
||||
#define LHD_MEDIA 20 /* Media error */
|
||||
#define LHD_ISWRITE 2 /* OR with above: I/O is a write */
|
||||
#define LHD_STATEMASK 0x1d /* mask for masking out LHD_ISWRITE */
|
||||
#define LHD_IDLE 0 /* Device idle */
|
||||
#define LHD_WORKING 1 /* Operation in progress */
|
||||
#define LHD_OK 4 /* Operation succeeded */
|
||||
#define LHD_INVSECT 12 /* Invalid sector requested */
|
||||
#define LHD_MEDIA 20 /* Media error */
|
||||
#define LHD_ISWRITE 2 /* OR with above: I/O is a write */
|
||||
#define LHD_STATEMASK 0x1d /* mask for masking out LHD_ISWRITE */
|
||||
|
||||
/* Buffer (offset within slot) */
|
||||
#define LHD_BUFFER 32768
|
||||
#define LHD_BUFFER 32768
|
||||
|
||||
/*
|
||||
* Shortcut for reading a register.
|
||||
*/
|
||||
static
|
||||
inline
|
||||
uint32_t lhd_rdreg(struct lhd_softc *lh, uint32_t reg)
|
||||
{
|
||||
return bus_read_register(lh->lh_busdata, lh->lh_buspos, reg);
|
||||
static inline uint32_t lhd_rdreg(struct lhd_softc *lh, uint32_t reg) {
|
||||
return bus_read_register(lh->lh_busdata, lh->lh_buspos, reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shortcut for writing a register.
|
||||
*/
|
||||
static
|
||||
inline
|
||||
void lhd_wreg(struct lhd_softc *lh, uint32_t reg, uint32_t val)
|
||||
{
|
||||
bus_write_register(lh->lh_busdata, lh->lh_buspos, reg, val);
|
||||
static inline void lhd_wreg(struct lhd_softc *lh, uint32_t reg, uint32_t val) {
|
||||
bus_write_register(lh->lh_busdata, lh->lh_buspos, reg, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a result code from the hardware to an errno value.
|
||||
*/
|
||||
static
|
||||
int lhd_code_to_errno(struct lhd_softc *lh, int code)
|
||||
{
|
||||
switch (code & LHD_STATEMASK) {
|
||||
case LHD_OK: return 0;
|
||||
case LHD_INVSECT: return EINVAL;
|
||||
case LHD_MEDIA: return EIO;
|
||||
}
|
||||
kprintf("lhd%d: Unknown result code %d\n", lh->lh_unit, code);
|
||||
return EAGAIN;
|
||||
static int lhd_code_to_errno(struct lhd_softc *lh, int code) {
|
||||
switch (code & LHD_STATEMASK) {
|
||||
case LHD_OK:
|
||||
return 0;
|
||||
case LHD_INVSECT:
|
||||
return EINVAL;
|
||||
case LHD_MEDIA:
|
||||
return EIO;
|
||||
}
|
||||
kprintf("lhd%d: Unknown result code %d\n", lh->lh_unit, code);
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Record that an I/O has completed: save the result and poke the
|
||||
* completion semaphore.
|
||||
*/
|
||||
static
|
||||
void
|
||||
lhd_iodone(struct lhd_softc *lh, int err)
|
||||
{
|
||||
lh->lh_result = err;
|
||||
V(lh->lh_done);
|
||||
static void lhd_iodone(struct lhd_softc *lh, int err) {
|
||||
lh->lh_result = err;
|
||||
V(lh->lh_done);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -112,57 +104,49 @@ lhd_iodone(struct lhd_softc *lh, int err)
|
||||
* Read the status register; if an operation finished, clear the status
|
||||
* register and report completion.
|
||||
*/
|
||||
void
|
||||
lhd_irq(void *vlh)
|
||||
{
|
||||
struct lhd_softc *lh = vlh;
|
||||
uint32_t val;
|
||||
void lhd_irq(void *vlh) {
|
||||
struct lhd_softc *lh = vlh;
|
||||
uint32_t val;
|
||||
|
||||
val = lhd_rdreg(lh, LHD_REG_STAT);
|
||||
val = lhd_rdreg(lh, LHD_REG_STAT);
|
||||
|
||||
switch (val & LHD_STATEMASK) {
|
||||
case LHD_IDLE:
|
||||
case LHD_WORKING:
|
||||
break;
|
||||
case LHD_OK:
|
||||
case LHD_INVSECT:
|
||||
case LHD_MEDIA:
|
||||
lhd_wreg(lh, LHD_REG_STAT, 0);
|
||||
lhd_iodone(lh, lhd_code_to_errno(lh, val));
|
||||
break;
|
||||
}
|
||||
switch (val & LHD_STATEMASK) {
|
||||
case LHD_IDLE:
|
||||
case LHD_WORKING:
|
||||
break;
|
||||
case LHD_OK:
|
||||
case LHD_INVSECT:
|
||||
case LHD_MEDIA:
|
||||
lhd_wreg(lh, LHD_REG_STAT, 0);
|
||||
lhd_iodone(lh, lhd_code_to_errno(lh, val));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called when we are open()'d.
|
||||
*/
|
||||
static
|
||||
int
|
||||
lhd_eachopen(struct device *d, int openflags)
|
||||
{
|
||||
/*
|
||||
* Don't need to do anything.
|
||||
*/
|
||||
(void)d;
|
||||
(void)openflags;
|
||||
static int lhd_eachopen(struct device *d, int openflags) {
|
||||
/*
|
||||
* Don't need to do anything.
|
||||
*/
|
||||
(void)d;
|
||||
(void)openflags;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function for handling ioctls.
|
||||
*/
|
||||
static
|
||||
int
|
||||
lhd_ioctl(struct device *d, int op, userptr_t data)
|
||||
{
|
||||
/*
|
||||
* We don't support any ioctls.
|
||||
*/
|
||||
(void)d;
|
||||
(void)op;
|
||||
(void)data;
|
||||
return EIOCTL;
|
||||
static int lhd_ioctl(struct device *d, int op, userptr_t data) {
|
||||
/*
|
||||
* We don't support any ioctls.
|
||||
*/
|
||||
(void)d;
|
||||
(void)op;
|
||||
(void)data;
|
||||
return EIOCTL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -182,127 +166,122 @@ lhd_reset(struct lhd_softc *lh)
|
||||
/*
|
||||
* I/O function (for both reads and writes)
|
||||
*/
|
||||
static
|
||||
int
|
||||
lhd_io(struct device *d, struct uio *uio)
|
||||
{
|
||||
struct lhd_softc *lh = d->d_data;
|
||||
static int lhd_io(struct device *d, struct uio *uio) {
|
||||
struct lhd_softc *lh = d->d_data;
|
||||
|
||||
uint32_t sector = uio->uio_offset / LHD_SECTSIZE;
|
||||
uint32_t sectoff = uio->uio_offset % LHD_SECTSIZE;
|
||||
uint32_t len = uio->uio_resid / LHD_SECTSIZE;
|
||||
uint32_t lenoff = uio->uio_resid % LHD_SECTSIZE;
|
||||
uint32_t i;
|
||||
uint32_t statval = LHD_WORKING;
|
||||
int result;
|
||||
uint32_t sector = uio->uio_offset / LHD_SECTSIZE;
|
||||
uint32_t sectoff = uio->uio_offset % LHD_SECTSIZE;
|
||||
uint32_t len = uio->uio_resid / LHD_SECTSIZE;
|
||||
uint32_t lenoff = uio->uio_resid % LHD_SECTSIZE;
|
||||
uint32_t i;
|
||||
uint32_t statval = LHD_WORKING;
|
||||
int result;
|
||||
|
||||
/* Don't allow I/O that isn't sector-aligned. */
|
||||
if (sectoff != 0 || lenoff != 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
/* Don't allow I/O that isn't sector-aligned. */
|
||||
if (sectoff != 0 || lenoff != 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Don't allow I/O past the end of the disk. */
|
||||
/* XXX this check can overflow */
|
||||
if (sector+len > lh->lh_dev.d_blocks) {
|
||||
return EINVAL;
|
||||
}
|
||||
/* Don't allow I/O past the end of the disk. */
|
||||
/* XXX this check can overflow */
|
||||
if (sector + len > lh->lh_dev.d_blocks) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Set up the value to write into the status register. */
|
||||
if (uio->uio_rw==UIO_WRITE) {
|
||||
statval |= LHD_ISWRITE;
|
||||
}
|
||||
/* Set up the value to write into the status register. */
|
||||
if (uio->uio_rw == UIO_WRITE) {
|
||||
statval |= LHD_ISWRITE;
|
||||
}
|
||||
|
||||
/* Loop over all the sectors we were asked to do. */
|
||||
for (i=0; i<len; i++) {
|
||||
/* Loop over all the sectors we were asked to do. */
|
||||
for (i = 0; i < len; i++) {
|
||||
|
||||
/* Wait until nobody else is using the device. */
|
||||
P(lh->lh_clear);
|
||||
/* Wait until nobody else is using the device. */
|
||||
P(lh->lh_clear);
|
||||
|
||||
/*
|
||||
* Are we writing? If so, transfer the data to the
|
||||
* on-card buffer.
|
||||
*/
|
||||
if (uio->uio_rw == UIO_WRITE) {
|
||||
result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio);
|
||||
membar_store_store();
|
||||
if (result) {
|
||||
V(lh->lh_clear);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Are we writing? If so, transfer the data to the
|
||||
* on-card buffer.
|
||||
*/
|
||||
if (uio->uio_rw == UIO_WRITE) {
|
||||
result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio);
|
||||
membar_store_store();
|
||||
if (result) {
|
||||
V(lh->lh_clear);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tell it what sector we want... */
|
||||
lhd_wreg(lh, LHD_REG_SECT, sector+i);
|
||||
/* Tell it what sector we want... */
|
||||
lhd_wreg(lh, LHD_REG_SECT, sector + i);
|
||||
|
||||
/* and start the operation. */
|
||||
lhd_wreg(lh, LHD_REG_STAT, statval);
|
||||
/* and start the operation. */
|
||||
lhd_wreg(lh, LHD_REG_STAT, statval);
|
||||
|
||||
/* Now wait until the interrupt handler tells us we're done. */
|
||||
P(lh->lh_done);
|
||||
/* Now wait until the interrupt handler tells us we're done. */
|
||||
P(lh->lh_done);
|
||||
|
||||
/* Get the result value saved by the interrupt handler. */
|
||||
result = lh->lh_result;
|
||||
/* Get the result value saved by the interrupt handler. */
|
||||
result = lh->lh_result;
|
||||
|
||||
/*
|
||||
* Are we reading? If so, and if we succeeded,
|
||||
* transfer the data out of the on-card buffer.
|
||||
*/
|
||||
if (result==0 && uio->uio_rw==UIO_READ) {
|
||||
membar_load_load();
|
||||
result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio);
|
||||
}
|
||||
/*
|
||||
* Are we reading? If so, and if we succeeded,
|
||||
* transfer the data out of the on-card buffer.
|
||||
*/
|
||||
if (result == 0 && uio->uio_rw == UIO_READ) {
|
||||
membar_load_load();
|
||||
result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio);
|
||||
}
|
||||
|
||||
/* Tell another thread it's cleared to go ahead. */
|
||||
V(lh->lh_clear);
|
||||
/* Tell another thread it's cleared to go ahead. */
|
||||
V(lh->lh_clear);
|
||||
|
||||
/* If we failed, return the error. */
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
/* If we failed, return the error. */
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct device_ops lhd_devops = {
|
||||
.devop_eachopen = lhd_eachopen,
|
||||
.devop_io = lhd_io,
|
||||
.devop_ioctl = lhd_ioctl,
|
||||
.devop_eachopen = lhd_eachopen,
|
||||
.devop_io = lhd_io,
|
||||
.devop_ioctl = lhd_ioctl,
|
||||
};
|
||||
|
||||
/*
|
||||
* Setup routine called by autoconf.c when an lhd is found.
|
||||
*/
|
||||
int
|
||||
config_lhd(struct lhd_softc *lh, int lhdno)
|
||||
{
|
||||
char name[32];
|
||||
int config_lhd(struct lhd_softc *lh, int lhdno) {
|
||||
char name[32];
|
||||
|
||||
/* Figure out what our name is. */
|
||||
snprintf(name, sizeof(name), "lhd%d", lhdno);
|
||||
/* Figure out what our name is. */
|
||||
snprintf(name, sizeof(name), "lhd%d", lhdno);
|
||||
|
||||
/* Get a pointer to the on-chip buffer. */
|
||||
lh->lh_buf = bus_map_area(lh->lh_busdata, lh->lh_buspos, LHD_BUFFER);
|
||||
/* Get a pointer to the on-chip buffer. */
|
||||
lh->lh_buf = bus_map_area(lh->lh_busdata, lh->lh_buspos, LHD_BUFFER);
|
||||
|
||||
/* Create the semaphores. */
|
||||
lh->lh_clear = sem_create("lhd-clear", 1);
|
||||
if (lh->lh_clear == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
lh->lh_done = sem_create("lhd-done", 0);
|
||||
if (lh->lh_done == NULL) {
|
||||
sem_destroy(lh->lh_clear);
|
||||
lh->lh_clear = NULL;
|
||||
return ENOMEM;
|
||||
}
|
||||
/* Create the semaphores. */
|
||||
lh->lh_clear = sem_create("lhd-clear", 1);
|
||||
if (lh->lh_clear == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
lh->lh_done = sem_create("lhd-done", 0);
|
||||
if (lh->lh_done == NULL) {
|
||||
sem_destroy(lh->lh_clear);
|
||||
lh->lh_clear = NULL;
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/* Set up the VFS device structure. */
|
||||
lh->lh_dev.d_ops = &lhd_devops;
|
||||
lh->lh_dev.d_blocks = bus_read_register(lh->lh_busdata, lh->lh_buspos,
|
||||
LHD_REG_NSECT);
|
||||
lh->lh_dev.d_blocksize = LHD_SECTSIZE;
|
||||
lh->lh_dev.d_data = lh;
|
||||
/* Set up the VFS device structure. */
|
||||
lh->lh_dev.d_ops = &lhd_devops;
|
||||
lh->lh_dev.d_blocks =
|
||||
bus_read_register(lh->lh_busdata, lh->lh_buspos, LHD_REG_NSECT);
|
||||
lh->lh_dev.d_blocksize = LHD_SECTSIZE;
|
||||
lh->lh_dev.d_data = lh;
|
||||
|
||||
/* Add the VFS device structure to the VFS device list. */
|
||||
return vfs_adddev(name, &lh->lh_dev, 1);
|
||||
/* Add the VFS device structure to the VFS device list. */
|
||||
return vfs_adddev(name, &lh->lh_dev, 1);
|
||||
}
|
||||
|
@ -35,30 +35,30 @@
|
||||
/*
|
||||
* Our sector size
|
||||
*/
|
||||
#define LHD_SECTSIZE 512
|
||||
#define LHD_SECTSIZE 512
|
||||
|
||||
/*
|
||||
* Hardware device data associated with lhd (LAMEbus hard disk)
|
||||
*/
|
||||
struct lhd_softc {
|
||||
/* Initialized by lower-level attach code */
|
||||
void *lh_busdata; /* The bus we're on */
|
||||
uint32_t lh_buspos; /* Our slot on that bus */
|
||||
int lh_unit; /* What number lhd we are */
|
||||
/* Initialized by lower-level attach code */
|
||||
void *lh_busdata; /* The bus we're on */
|
||||
uint32_t lh_buspos; /* Our slot on that bus */
|
||||
int lh_unit; /* What number lhd we are */
|
||||
|
||||
/*
|
||||
* Initialized by config_lhd
|
||||
*/
|
||||
/*
|
||||
* Initialized by config_lhd
|
||||
*/
|
||||
|
||||
void *lh_buf; /* Pointer to on-card I/O buffer */
|
||||
int lh_result; /* Result from I/O operation */
|
||||
struct semaphore *lh_clear; /* Synchronization */
|
||||
struct semaphore *lh_done;
|
||||
void *lh_buf; /* Pointer to on-card I/O buffer */
|
||||
int lh_result; /* Result from I/O operation */
|
||||
struct semaphore *lh_clear; /* Synchronization */
|
||||
struct semaphore *lh_done;
|
||||
|
||||
struct device lh_dev; /* VFS device structure */
|
||||
struct device lh_dev; /* VFS device structure */
|
||||
};
|
||||
|
||||
/* Functions called by lower-level drivers */
|
||||
void lhd_irq(/*struct lhd_softc*/ void *); /* Interrupt handler */
|
||||
void lhd_irq(/*struct lhd_softc*/ void *); /* Interrupt handler */
|
||||
|
||||
#endif /* _LAMEBUS_LHD_H_ */
|
||||
|
@ -37,33 +37,31 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Lowest revision we support */
|
||||
#define LOW_VERSION 2
|
||||
#define LOW_VERSION 2
|
||||
|
||||
struct lhd_softc *
|
||||
attach_lhd_to_lamebus(int lhdno, struct lamebus_softc *sc)
|
||||
{
|
||||
struct lhd_softc *lh;
|
||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_DISK,
|
||||
LOW_VERSION, NULL);
|
||||
if (slot < 0) {
|
||||
/* None found */
|
||||
return NULL;
|
||||
}
|
||||
struct lhd_softc *attach_lhd_to_lamebus(int lhdno, struct lamebus_softc *sc) {
|
||||
struct lhd_softc *lh;
|
||||
int slot =
|
||||
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_DISK, LOW_VERSION, NULL);
|
||||
if (slot < 0) {
|
||||
/* None found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lh = kmalloc(sizeof(struct lhd_softc));
|
||||
if (lh==NULL) {
|
||||
/* Out of memory */
|
||||
return NULL;
|
||||
}
|
||||
lh = kmalloc(sizeof(struct lhd_softc));
|
||||
if (lh == NULL) {
|
||||
/* Out of memory */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Record what the lhd is attached to */
|
||||
lh->lh_busdata = sc;
|
||||
lh->lh_buspos = slot;
|
||||
lh->lh_unit = lhdno;
|
||||
/* Record what the lhd is attached to */
|
||||
lh->lh_busdata = sc;
|
||||
lh->lh_buspos = slot;
|
||||
lh->lh_unit = lhdno;
|
||||
|
||||
/* Mark the slot in use and collect interrupts */
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_attach_interrupt(sc, slot, lh, lhd_irq);
|
||||
/* Mark the slot in use and collect interrupts */
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_attach_interrupt(sc, slot, lh, lhd_irq);
|
||||
|
||||
return lh;
|
||||
return lh;
|
||||
}
|
||||
|
@ -33,14 +33,10 @@
|
||||
/*#include <lamebus/lnet.h>*/ /* not yet */
|
||||
#include "autoconf.h"
|
||||
|
||||
int
|
||||
config_lnet(struct lnet_softc *sc, int lnetno)
|
||||
{
|
||||
(void)sc;
|
||||
int config_lnet(struct lnet_softc *sc, int lnetno) {
|
||||
(void)sc;
|
||||
|
||||
kprintf("lnet%d: No network support in system\n", lnetno);
|
||||
kprintf("lnet%d: No network support in system\n", lnetno);
|
||||
|
||||
return ENODEV;
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
|
||||
|
@ -33,20 +33,19 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Lowest revision we support */
|
||||
#define LOW_VERSION 1
|
||||
#define LOW_VERSION 1
|
||||
/* Highest revision we support */
|
||||
#define HIGH_VERSION 1
|
||||
#define HIGH_VERSION 1
|
||||
|
||||
struct lnet_softc *
|
||||
attach_lnet_to_lamebus(int lnetno, struct lamebus_softc *sc)
|
||||
{
|
||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_NET,
|
||||
LOW_VERSION, HIGH_VERSION);
|
||||
if (slot < 0) {
|
||||
return NULL;
|
||||
}
|
||||
struct lnet_softc *attach_lnet_to_lamebus(int lnetno,
|
||||
struct lamebus_softc *sc) {
|
||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_NET, LOW_VERSION,
|
||||
HIGH_VERSION);
|
||||
if (slot < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kprintf("lnet%d: No network support in system\n", lnetno);
|
||||
kprintf("lnet%d: No network support in system\n", lnetno);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -38,48 +38,39 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Registers (offsets within slot) */
|
||||
#define LR_REG_RAND 0 /* random register */
|
||||
#define LR_REG_RAND 0 /* random register */
|
||||
|
||||
/* Constants */
|
||||
#define LR_RANDMAX 0xffffffff
|
||||
#define LR_RANDMAX 0xffffffff
|
||||
|
||||
int
|
||||
config_lrandom(struct lrandom_softc *lr, int lrandomno)
|
||||
{
|
||||
(void)lrandomno;
|
||||
(void)lr;
|
||||
return 0;
|
||||
int config_lrandom(struct lrandom_softc *lr, int lrandomno) {
|
||||
(void)lrandomno;
|
||||
(void)lr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
lrandom_random(void *devdata)
|
||||
{
|
||||
struct lrandom_softc *lr = devdata;
|
||||
return bus_read_register(lr->lr_bus, lr->lr_buspos, LR_REG_RAND);
|
||||
uint32_t lrandom_random(void *devdata) {
|
||||
struct lrandom_softc *lr = devdata;
|
||||
return bus_read_register(lr->lr_bus, lr->lr_buspos, LR_REG_RAND);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
lrandom_randmax(void *devdata)
|
||||
{
|
||||
(void)devdata;
|
||||
return LR_RANDMAX;
|
||||
uint32_t lrandom_randmax(void *devdata) {
|
||||
(void)devdata;
|
||||
return LR_RANDMAX;
|
||||
}
|
||||
|
||||
int
|
||||
lrandom_read(void *devdata, struct uio *uio)
|
||||
{
|
||||
struct lrandom_softc *lr = devdata;
|
||||
uint32_t val;
|
||||
int result;
|
||||
int lrandom_read(void *devdata, struct uio *uio) {
|
||||
struct lrandom_softc *lr = devdata;
|
||||
uint32_t val;
|
||||
int result;
|
||||
|
||||
while (uio->uio_resid > 0) {
|
||||
val = bus_read_register(lr->lr_bus, lr->lr_buspos,
|
||||
LR_REG_RAND);
|
||||
result = uiomove(&val, sizeof(val), uio);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
while (uio->uio_resid > 0) {
|
||||
val = bus_read_register(lr->lr_bus, lr->lr_buspos, LR_REG_RAND);
|
||||
result = uiomove(&val, sizeof(val), uio);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
@ -33,9 +33,9 @@
|
||||
struct uio;
|
||||
|
||||
struct lrandom_softc {
|
||||
/* Initialized by lower-level attach routine */
|
||||
void *lr_bus;
|
||||
uint32_t lr_buspos;
|
||||
/* Initialized by lower-level attach routine */
|
||||
void *lr_bus;
|
||||
uint32_t lr_buspos;
|
||||
};
|
||||
|
||||
/* Functions called by higher-level drivers */
|
||||
|
@ -34,29 +34,28 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Lowest revision we support */
|
||||
#define LOW_VERSION 1
|
||||
#define LOW_VERSION 1
|
||||
|
||||
struct lrandom_softc *
|
||||
attach_lrandom_to_lamebus(int lrandomno, struct lamebus_softc *sc)
|
||||
{
|
||||
struct lrandom_softc *lr;
|
||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_RANDOM,
|
||||
LOW_VERSION, NULL);
|
||||
if (slot < 0) {
|
||||
return NULL;
|
||||
}
|
||||
struct lrandom_softc *attach_lrandom_to_lamebus(int lrandomno,
|
||||
struct lamebus_softc *sc) {
|
||||
struct lrandom_softc *lr;
|
||||
int slot =
|
||||
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_RANDOM, LOW_VERSION, NULL);
|
||||
if (slot < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lr = kmalloc(sizeof(struct lrandom_softc));
|
||||
if (lr==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
lr = kmalloc(sizeof(struct lrandom_softc));
|
||||
if (lr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)lrandomno; // unused
|
||||
(void)lrandomno; // unused
|
||||
|
||||
lr->lr_bus = sc;
|
||||
lr->lr_buspos = slot;
|
||||
lr->lr_bus = sc;
|
||||
lr->lr_buspos = slot;
|
||||
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_mark(sc, slot);
|
||||
|
||||
return lr;
|
||||
return lr;
|
||||
}
|
||||
|
@ -41,37 +41,29 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Registers (offsets within slot) */
|
||||
#define LSCR_REG_POSN 0 /* Cursor position */
|
||||
#define LSCR_REG_SIZE 4 /* Display size */
|
||||
#define LSCR_REG_CHAR 8 /* Character in */
|
||||
#define LSCR_REG_RIRQ 12 /* Read interrupt status */
|
||||
#define LSCR_REG_POSN 0 /* Cursor position */
|
||||
#define LSCR_REG_SIZE 4 /* Display size */
|
||||
#define LSCR_REG_CHAR 8 /* Character in */
|
||||
#define LSCR_REG_RIRQ 12 /* Read interrupt status */
|
||||
|
||||
/* Bits in the IRQ registers */
|
||||
#define LSCR_IRQ_ENABLE 1
|
||||
#define LSCR_IRQ_ACTIVE 2
|
||||
#define LSCR_IRQ_ENABLE 1
|
||||
#define LSCR_IRQ_ACTIVE 2
|
||||
|
||||
/* Offset within slot of screen buffer */
|
||||
#define LSCR_SCREEN 32768
|
||||
#define LSCR_SCREEN 32768
|
||||
|
||||
/* Convert a 32-bit X/Y pair to X and Y coordinates. */
|
||||
static
|
||||
inline
|
||||
void
|
||||
splitxy(uint32_t xy, unsigned *x, unsigned *y)
|
||||
{
|
||||
*x = xy >> 16;
|
||||
*y = xy & 0xffff;
|
||||
static inline void splitxy(uint32_t xy, unsigned *x, unsigned *y) {
|
||||
*x = xy >> 16;
|
||||
*y = xy & 0xffff;
|
||||
}
|
||||
|
||||
/* Convert X and Y coordinates to a single 32-bit value. */
|
||||
static
|
||||
inline
|
||||
uint32_t
|
||||
mergexy(unsigned x, unsigned y)
|
||||
{
|
||||
uint32_t val = x;
|
||||
static inline uint32_t mergexy(unsigned x, unsigned y) {
|
||||
uint32_t val = x;
|
||||
|
||||
return (val << 16) | y;
|
||||
return (val << 16) | y;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -79,29 +71,25 @@ mergexy(unsigned x, unsigned y)
|
||||
/*
|
||||
* Interrupt handler.
|
||||
*/
|
||||
void
|
||||
lscreen_irq(void *vsc)
|
||||
{
|
||||
struct lscreen_softc *sc = vsc;
|
||||
uint32_t ch, x;
|
||||
void lscreen_irq(void *vsc) {
|
||||
struct lscreen_softc *sc = vsc;
|
||||
uint32_t ch, x;
|
||||
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
|
||||
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_RIRQ);
|
||||
if (x & LSCR_IRQ_ACTIVE) {
|
||||
ch = bus_read_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSCR_REG_CHAR);
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSCR_REG_RIRQ, LSCR_IRQ_ENABLE);
|
||||
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_RIRQ);
|
||||
if (x & LSCR_IRQ_ACTIVE) {
|
||||
ch = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_CHAR);
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_RIRQ,
|
||||
LSCR_IRQ_ENABLE);
|
||||
|
||||
spinlock_release(&sc->ls_lock);
|
||||
if (sc->ls_input) {
|
||||
sc->ls_input(sc->ls_devdata, ch);
|
||||
}
|
||||
}
|
||||
else {
|
||||
spinlock_release(&sc->ls_lock);
|
||||
}
|
||||
spinlock_release(&sc->ls_lock);
|
||||
if (sc->ls_input) {
|
||||
sc->ls_input(sc->ls_devdata, ch);
|
||||
}
|
||||
} else {
|
||||
spinlock_release(&sc->ls_lock);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -109,74 +97,68 @@ lscreen_irq(void *vsc)
|
||||
/*
|
||||
* Handle a newline on the screen.
|
||||
*/
|
||||
static
|
||||
void
|
||||
lscreen_newline(struct lscreen_softc *sc)
|
||||
{
|
||||
if (sc->ls_cy >= sc->ls_height-1) {
|
||||
/*
|
||||
* Scroll
|
||||
*/
|
||||
static void lscreen_newline(struct lscreen_softc *sc) {
|
||||
if (sc->ls_cy >= sc->ls_height - 1) {
|
||||
/*
|
||||
* Scroll
|
||||
*/
|
||||
|
||||
memmove(sc->ls_screen, sc->ls_screen + sc->ls_width,
|
||||
sc->ls_width * (sc->ls_height-1));
|
||||
bzero(sc->ls_screen + sc->ls_width * (sc->ls_height-1),
|
||||
sc->ls_width);
|
||||
}
|
||||
else {
|
||||
sc->ls_cy++;
|
||||
}
|
||||
sc->ls_cx=0;
|
||||
memmove(sc->ls_screen, sc->ls_screen + sc->ls_width,
|
||||
sc->ls_width * (sc->ls_height - 1));
|
||||
bzero(sc->ls_screen + sc->ls_width * (sc->ls_height - 1), sc->ls_width);
|
||||
} else {
|
||||
sc->ls_cy++;
|
||||
}
|
||||
sc->ls_cx = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a printable character being written to the screen.
|
||||
*/
|
||||
static
|
||||
void
|
||||
lscreen_char(struct lscreen_softc *sc, int ch)
|
||||
{
|
||||
if (sc->ls_cx >= sc->ls_width) {
|
||||
lscreen_newline(sc);
|
||||
}
|
||||
static void lscreen_char(struct lscreen_softc *sc, int ch) {
|
||||
if (sc->ls_cx >= sc->ls_width) {
|
||||
lscreen_newline(sc);
|
||||
}
|
||||
|
||||
sc->ls_screen[sc->ls_cy*sc->ls_width + sc->ls_cx] = ch;
|
||||
sc->ls_cx++;
|
||||
sc->ls_screen[sc->ls_cy * sc->ls_width + sc->ls_cx] = ch;
|
||||
sc->ls_cx++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a character to the screen.
|
||||
* This should probably know about backspace and tab.
|
||||
*/
|
||||
void
|
||||
lscreen_write(void *vsc, int ch)
|
||||
{
|
||||
struct lscreen_softc *sc = vsc;
|
||||
int ccx, ccy;
|
||||
void lscreen_write(void *vsc, int ch) {
|
||||
struct lscreen_softc *sc = vsc;
|
||||
int ccx, ccy;
|
||||
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
|
||||
switch (ch) {
|
||||
case '\n': lscreen_newline(sc); break;
|
||||
default: lscreen_char(sc, ch); break;
|
||||
}
|
||||
switch (ch) {
|
||||
case '\n':
|
||||
lscreen_newline(sc);
|
||||
break;
|
||||
default:
|
||||
lscreen_char(sc, ch);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* ccx/ccy = corrected cursor position
|
||||
* (The cursor marks the next space text will appear in. But
|
||||
* at the very end of the line, it should not move off the edge.)
|
||||
*/
|
||||
ccx = sc->ls_cx;
|
||||
ccy = sc->ls_cy;
|
||||
if (ccx==sc->ls_width) {
|
||||
ccx--;
|
||||
}
|
||||
/*
|
||||
* ccx/ccy = corrected cursor position
|
||||
* (The cursor marks the next space text will appear in. But
|
||||
* at the very end of the line, it should not move off the edge.)
|
||||
*/
|
||||
ccx = sc->ls_cx;
|
||||
ccy = sc->ls_cy;
|
||||
if (ccx == sc->ls_width) {
|
||||
ccx--;
|
||||
}
|
||||
|
||||
/* Set the cursor position */
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSCR_REG_POSN, mergexy(ccx, ccy));
|
||||
/* Set the cursor position */
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_POSN,
|
||||
mergexy(ccx, ccy));
|
||||
|
||||
spinlock_release(&sc->ls_lock);
|
||||
spinlock_release(&sc->ls_lock);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -184,42 +166,36 @@ lscreen_write(void *vsc, int ch)
|
||||
/*
|
||||
* Setup routine called by autoconf.c when an lscreen is found.
|
||||
*/
|
||||
int
|
||||
config_lscreen(struct lscreen_softc *sc, int lscreenno)
|
||||
{
|
||||
uint32_t val;
|
||||
int config_lscreen(struct lscreen_softc *sc, int lscreenno) {
|
||||
uint32_t val;
|
||||
|
||||
(void)lscreenno;
|
||||
(void)lscreenno;
|
||||
|
||||
spinlock_init(&sc->ls_lock);
|
||||
spinlock_init(&sc->ls_lock);
|
||||
|
||||
/*
|
||||
* Enable interrupting.
|
||||
*/
|
||||
/*
|
||||
* Enable interrupting.
|
||||
*/
|
||||
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSCR_REG_RIRQ, LSCR_IRQ_ENABLE);
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_RIRQ,
|
||||
LSCR_IRQ_ENABLE);
|
||||
|
||||
/*
|
||||
* Get screen size.
|
||||
*/
|
||||
val = bus_read_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSCR_REG_SIZE);
|
||||
splitxy(val, &sc->ls_width, &sc->ls_height);
|
||||
/*
|
||||
* Get screen size.
|
||||
*/
|
||||
val = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_SIZE);
|
||||
splitxy(val, &sc->ls_width, &sc->ls_height);
|
||||
|
||||
/*
|
||||
* Get cursor position.
|
||||
*/
|
||||
val = bus_read_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSCR_REG_POSN);
|
||||
splitxy(val, &sc->ls_cx, &sc->ls_cy);
|
||||
/*
|
||||
* Get cursor position.
|
||||
*/
|
||||
val = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_POSN);
|
||||
splitxy(val, &sc->ls_cx, &sc->ls_cy);
|
||||
|
||||
/*
|
||||
* Get a pointer to the memory-mapped screen area.
|
||||
*/
|
||||
sc->ls_screen = bus_map_area(sc->ls_busdata, sc->ls_buspos,
|
||||
LSCR_SCREEN);
|
||||
/*
|
||||
* Get a pointer to the memory-mapped screen area.
|
||||
*/
|
||||
sc->ls_screen = bus_map_area(sc->ls_busdata, sc->ls_buspos, LSCR_SCREEN);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -34,24 +34,24 @@
|
||||
* Hardware device data for memory-mapped fullscreen text console.
|
||||
*/
|
||||
struct lscreen_softc {
|
||||
/* Initialized by config function */
|
||||
struct spinlock ls_lock; // protects data and device regs
|
||||
unsigned ls_width, ls_height; // screen size
|
||||
unsigned ls_cx, ls_cy; // cursor position
|
||||
char *ls_screen; // memory-mapped screen buffer
|
||||
/* Initialized by config function */
|
||||
struct spinlock ls_lock; // protects data and device regs
|
||||
unsigned ls_width, ls_height; // screen size
|
||||
unsigned ls_cx, ls_cy; // cursor position
|
||||
char *ls_screen; // memory-mapped screen buffer
|
||||
|
||||
/* Initialized by lower-level attachment function */
|
||||
void *ls_busdata; // bus we're on
|
||||
uint32_t ls_buspos; // position on that bus
|
||||
/* Initialized by lower-level attachment function */
|
||||
void *ls_busdata; // bus we're on
|
||||
uint32_t ls_buspos; // position on that bus
|
||||
|
||||
/* Initialized by higher-level attachment function */
|
||||
void *ls_devdata; // data and functions for
|
||||
void (*ls_start)(void *devdata); // upper device (perhaps
|
||||
void (*ls_input)(void *devdata, int ch); // console)
|
||||
/* Initialized by higher-level attachment function */
|
||||
void *ls_devdata; // data and functions for
|
||||
void (*ls_start)(void *devdata); // upper device (perhaps
|
||||
void (*ls_input)(void *devdata, int ch); // console)
|
||||
};
|
||||
|
||||
/* Functions called by lower-level drivers */
|
||||
void lscreen_irq(/*struct lser_softc*/ void *sc); // interrupt handler
|
||||
void lscreen_irq(/*struct lser_softc*/ void *sc); // interrupt handler
|
||||
|
||||
/* Functions called by higher-level drivers */
|
||||
void lscreen_write(/*struct lser_softc*/ void *sc, int ch); // output function
|
||||
|
@ -37,34 +37,33 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Lowest revision we support */
|
||||
#define LOW_VERSION 1
|
||||
#define LOW_VERSION 1
|
||||
/* Highest revision we support */
|
||||
#define HIGH_VERSION 1
|
||||
#define HIGH_VERSION 1
|
||||
|
||||
struct lscreen_softc *
|
||||
attach_lscreen_to_lamebus(int lscreenno, struct lamebus_softc *sc)
|
||||
{
|
||||
struct lscreen_softc *ls;
|
||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SCREEN,
|
||||
LOW_VERSION, HIGH_VERSION);
|
||||
if (slot < 0) {
|
||||
/* Not found */
|
||||
return NULL;
|
||||
}
|
||||
struct lscreen_softc *attach_lscreen_to_lamebus(int lscreenno,
|
||||
struct lamebus_softc *sc) {
|
||||
struct lscreen_softc *ls;
|
||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SCREEN, LOW_VERSION,
|
||||
HIGH_VERSION);
|
||||
if (slot < 0) {
|
||||
/* Not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ls = kmalloc(sizeof(struct lscreen_softc));
|
||||
if (ls==NULL) {
|
||||
/* Out of memory */
|
||||
return NULL;
|
||||
}
|
||||
ls = kmalloc(sizeof(struct lscreen_softc));
|
||||
if (ls == NULL) {
|
||||
/* Out of memory */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Record what it's attached to */
|
||||
ls->ls_busdata = sc;
|
||||
ls->ls_buspos = slot;
|
||||
/* Record what it's attached to */
|
||||
ls->ls_busdata = sc;
|
||||
ls->ls_buspos = slot;
|
||||
|
||||
/* Mark the slot in use and hook the interrupt */
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_attach_interrupt(sc, slot, ls, lscreen_irq);
|
||||
/* Mark the slot in use and hook the interrupt */
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_attach_interrupt(sc, slot, ls, lscreen_irq);
|
||||
|
||||
return ls;
|
||||
return ls;
|
||||
}
|
||||
|
@ -35,158 +35,139 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Registers (offsets within slot) */
|
||||
#define LSER_REG_CHAR 0 /* Character in/out */
|
||||
#define LSER_REG_WIRQ 4 /* Write interrupt status */
|
||||
#define LSER_REG_RIRQ 8 /* Read interrupt status */
|
||||
#define LSER_REG_CHAR 0 /* Character in/out */
|
||||
#define LSER_REG_WIRQ 4 /* Write interrupt status */
|
||||
#define LSER_REG_RIRQ 8 /* Read interrupt status */
|
||||
|
||||
/* Bits in the IRQ registers */
|
||||
#define LSER_IRQ_ENABLE 1
|
||||
#define LSER_IRQ_ACTIVE 2
|
||||
#define LSER_IRQ_FORCE 4
|
||||
#define LSER_IRQ_ENABLE 1
|
||||
#define LSER_IRQ_ACTIVE 2
|
||||
#define LSER_IRQ_FORCE 4
|
||||
|
||||
void
|
||||
lser_irq(void *vsc)
|
||||
{
|
||||
struct lser_softc *sc = vsc;
|
||||
uint32_t x;
|
||||
bool clear_to_write = false;
|
||||
bool got_a_read = false;
|
||||
uint32_t ch = 0;
|
||||
void lser_irq(void *vsc) {
|
||||
struct lser_softc *sc = vsc;
|
||||
uint32_t x;
|
||||
bool clear_to_write = false;
|
||||
bool got_a_read = false;
|
||||
uint32_t ch = 0;
|
||||
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
|
||||
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ);
|
||||
if (x & LSER_IRQ_ACTIVE) {
|
||||
x = LSER_IRQ_ENABLE;
|
||||
sc->ls_wbusy = 0;
|
||||
clear_to_write = true;
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSER_REG_WIRQ, x);
|
||||
}
|
||||
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ);
|
||||
if (x & LSER_IRQ_ACTIVE) {
|
||||
x = LSER_IRQ_ENABLE;
|
||||
sc->ls_wbusy = 0;
|
||||
clear_to_write = true;
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ, x);
|
||||
}
|
||||
|
||||
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_RIRQ);
|
||||
if (x & LSER_IRQ_ACTIVE) {
|
||||
x = LSER_IRQ_ENABLE;
|
||||
ch = bus_read_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSER_REG_CHAR);
|
||||
got_a_read = true;
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSER_REG_RIRQ, x);
|
||||
}
|
||||
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_RIRQ);
|
||||
if (x & LSER_IRQ_ACTIVE) {
|
||||
x = LSER_IRQ_ENABLE;
|
||||
ch = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_CHAR);
|
||||
got_a_read = true;
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_RIRQ, x);
|
||||
}
|
||||
|
||||
spinlock_release(&sc->ls_lock);
|
||||
spinlock_release(&sc->ls_lock);
|
||||
|
||||
if (clear_to_write && sc->ls_start != NULL) {
|
||||
sc->ls_start(sc->ls_devdata);
|
||||
}
|
||||
if (got_a_read && sc->ls_input != NULL) {
|
||||
sc->ls_input(sc->ls_devdata, ch);
|
||||
}
|
||||
if (clear_to_write && sc->ls_start != NULL) {
|
||||
sc->ls_start(sc->ls_devdata);
|
||||
}
|
||||
if (got_a_read && sc->ls_input != NULL) {
|
||||
sc->ls_input(sc->ls_devdata, ch);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lser_write(void *vls, int ch)
|
||||
{
|
||||
struct lser_softc *ls = vls;
|
||||
void lser_write(void *vls, int ch) {
|
||||
struct lser_softc *ls = vls;
|
||||
|
||||
spinlock_acquire(&ls->ls_lock);
|
||||
spinlock_acquire(&ls->ls_lock);
|
||||
|
||||
if (ls->ls_wbusy) {
|
||||
/*
|
||||
* We're not clear to write.
|
||||
*
|
||||
* This should not happen. It's the job of the driver
|
||||
* attached to us to not write until we call
|
||||
* ls->ls_start.
|
||||
*
|
||||
* (Note: if we're the console, the panic will go to
|
||||
* lser_writepolled for printing, because we hold a
|
||||
* spinlock and interrupts are off; it won't recurse.)
|
||||
*/
|
||||
panic("lser: Not clear to write\n");
|
||||
}
|
||||
ls->ls_wbusy = true;
|
||||
if (ls->ls_wbusy) {
|
||||
/*
|
||||
* We're not clear to write.
|
||||
*
|
||||
* This should not happen. It's the job of the driver
|
||||
* attached to us to not write until we call
|
||||
* ls->ls_start.
|
||||
*
|
||||
* (Note: if we're the console, the panic will go to
|
||||
* lser_writepolled for printing, because we hold a
|
||||
* spinlock and interrupts are off; it won't recurse.)
|
||||
*/
|
||||
panic("lser: Not clear to write\n");
|
||||
}
|
||||
ls->ls_wbusy = true;
|
||||
|
||||
bus_write_register(ls->ls_busdata, ls->ls_buspos, LSER_REG_CHAR, ch);
|
||||
bus_write_register(ls->ls_busdata, ls->ls_buspos, LSER_REG_CHAR, ch);
|
||||
|
||||
spinlock_release(&ls->ls_lock);
|
||||
spinlock_release(&ls->ls_lock);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
lser_poll_until_write(struct lser_softc *sc)
|
||||
{
|
||||
uint32_t val;
|
||||
static void lser_poll_until_write(struct lser_softc *sc) {
|
||||
uint32_t val;
|
||||
|
||||
KASSERT(spinlock_do_i_hold(&sc->ls_lock));
|
||||
KASSERT(spinlock_do_i_hold(&sc->ls_lock));
|
||||
|
||||
do {
|
||||
val = bus_read_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSER_REG_WIRQ);
|
||||
}
|
||||
while ((val & LSER_IRQ_ACTIVE) == 0);
|
||||
do {
|
||||
val = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ);
|
||||
} while ((val & LSER_IRQ_ACTIVE) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
lser_writepolled(void *vsc, int ch)
|
||||
{
|
||||
struct lser_softc *sc = vsc;
|
||||
bool irqpending;
|
||||
void lser_writepolled(void *vsc, int ch) {
|
||||
struct lser_softc *sc = vsc;
|
||||
bool irqpending;
|
||||
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
spinlock_acquire(&sc->ls_lock);
|
||||
|
||||
if (sc->ls_wbusy) {
|
||||
irqpending = true;
|
||||
lser_poll_until_write(sc);
|
||||
/* Clear the ready condition, but leave the IRQ asserted */
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSER_REG_WIRQ,
|
||||
LSER_IRQ_FORCE|LSER_IRQ_ENABLE);
|
||||
}
|
||||
else {
|
||||
irqpending = false;
|
||||
/* Clear the interrupt enable bit */
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSER_REG_WIRQ, 0);
|
||||
}
|
||||
if (sc->ls_wbusy) {
|
||||
irqpending = true;
|
||||
lser_poll_until_write(sc);
|
||||
/* Clear the ready condition, but leave the IRQ asserted */
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ,
|
||||
LSER_IRQ_FORCE | LSER_IRQ_ENABLE);
|
||||
} else {
|
||||
irqpending = false;
|
||||
/* Clear the interrupt enable bit */
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ, 0);
|
||||
}
|
||||
|
||||
/* Send the character. */
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_CHAR, ch);
|
||||
/* Send the character. */
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_CHAR, ch);
|
||||
|
||||
/* Wait until it's done. */
|
||||
lser_poll_until_write(sc);
|
||||
/* Wait until it's done. */
|
||||
lser_poll_until_write(sc);
|
||||
|
||||
/*
|
||||
* If there wasn't already an IRQ pending, clear the ready
|
||||
* condition and turn interruption back on. But if there was,
|
||||
* leave the register alone, with the ready condition set (and
|
||||
* the force bit still on); in due course we'll get to the
|
||||
* interrupt handler and they'll be cleared.
|
||||
*/
|
||||
if (!irqpending) {
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSER_REG_WIRQ, LSER_IRQ_ENABLE);
|
||||
}
|
||||
/*
|
||||
* If there wasn't already an IRQ pending, clear the ready
|
||||
* condition and turn interruption back on. But if there was,
|
||||
* leave the register alone, with the ready condition set (and
|
||||
* the force bit still on); in due course we'll get to the
|
||||
* interrupt handler and they'll be cleared.
|
||||
*/
|
||||
if (!irqpending) {
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ,
|
||||
LSER_IRQ_ENABLE);
|
||||
}
|
||||
|
||||
spinlock_release(&sc->ls_lock);
|
||||
spinlock_release(&sc->ls_lock);
|
||||
}
|
||||
|
||||
int
|
||||
config_lser(struct lser_softc *sc, int lserno)
|
||||
{
|
||||
(void)lserno;
|
||||
int config_lser(struct lser_softc *sc, int lserno) {
|
||||
(void)lserno;
|
||||
|
||||
/*
|
||||
* Enable interrupting.
|
||||
*/
|
||||
/*
|
||||
* Enable interrupting.
|
||||
*/
|
||||
|
||||
spinlock_init(&sc->ls_lock);
|
||||
sc->ls_wbusy = false;
|
||||
spinlock_init(&sc->ls_lock);
|
||||
sc->ls_wbusy = false;
|
||||
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSER_REG_RIRQ, LSER_IRQ_ENABLE);
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
||||
LSER_REG_WIRQ, LSER_IRQ_ENABLE);
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_RIRQ,
|
||||
LSER_IRQ_ENABLE);
|
||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ,
|
||||
LSER_IRQ_ENABLE);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
@ -33,18 +33,18 @@
|
||||
#include <spinlock.h>
|
||||
|
||||
struct lser_softc {
|
||||
/* Initialized by config function */
|
||||
struct spinlock ls_lock; /* protects ls_wbusy and device regs */
|
||||
volatile bool ls_wbusy; /* true if write in progress */
|
||||
/* Initialized by config function */
|
||||
struct spinlock ls_lock; /* protects ls_wbusy and device regs */
|
||||
volatile bool ls_wbusy; /* true if write in progress */
|
||||
|
||||
/* Initialized by lower-level attachment function */
|
||||
void *ls_busdata;
|
||||
uint32_t ls_buspos;
|
||||
/* Initialized by lower-level attachment function */
|
||||
void *ls_busdata;
|
||||
uint32_t ls_buspos;
|
||||
|
||||
/* Initialized by higher-level attachment function */
|
||||
void *ls_devdata;
|
||||
void (*ls_start)(void *devdata);
|
||||
void (*ls_input)(void *devdata, int ch);
|
||||
/* Initialized by higher-level attachment function */
|
||||
void *ls_devdata;
|
||||
void (*ls_start)(void *devdata);
|
||||
void (*ls_input)(void *devdata, int ch);
|
||||
};
|
||||
|
||||
/* Functions called by lower-level drivers */
|
||||
|
@ -34,30 +34,29 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Lowest revision we support */
|
||||
#define LOW_VERSION 1
|
||||
#define LOW_VERSION 1
|
||||
|
||||
struct lser_softc *
|
||||
attach_lser_to_lamebus(int lserno, struct lamebus_softc *sc)
|
||||
{
|
||||
struct lser_softc *ls;
|
||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SERIAL,
|
||||
LOW_VERSION, NULL);
|
||||
if (slot < 0) {
|
||||
return NULL;
|
||||
}
|
||||
struct lser_softc *attach_lser_to_lamebus(int lserno,
|
||||
struct lamebus_softc *sc) {
|
||||
struct lser_softc *ls;
|
||||
int slot =
|
||||
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SERIAL, LOW_VERSION, NULL);
|
||||
if (slot < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ls = kmalloc(sizeof(struct lser_softc));
|
||||
if (ls==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ls = kmalloc(sizeof(struct lser_softc));
|
||||
if (ls == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)lserno; // unused
|
||||
(void)lserno; // unused
|
||||
|
||||
ls->ls_busdata = sc;
|
||||
ls->ls_buspos = slot;
|
||||
ls->ls_busdata = sc;
|
||||
ls->ls_buspos = slot;
|
||||
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_attach_interrupt(sc, slot, ls, lser_irq);
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_attach_interrupt(sc, slot, ls, lser_irq);
|
||||
|
||||
return ls;
|
||||
return ls;
|
||||
}
|
||||
|
@ -39,92 +39,87 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Registers (offsets within slot) */
|
||||
#define LT_REG_SEC 0 /* time of day: seconds */
|
||||
#define LT_REG_NSEC 4 /* time of day: nanoseconds */
|
||||
#define LT_REG_ROE 8 /* Restart On countdown-timer Expiry flag */
|
||||
#define LT_REG_IRQ 12 /* Interrupt status register */
|
||||
#define LT_REG_COUNT 16 /* Time for countdown timer (usec) */
|
||||
#define LT_REG_SPKR 20 /* Beep control */
|
||||
#define LT_REG_SEC 0 /* time of day: seconds */
|
||||
#define LT_REG_NSEC 4 /* time of day: nanoseconds */
|
||||
#define LT_REG_ROE 8 /* Restart On countdown-timer Expiry flag */
|
||||
#define LT_REG_IRQ 12 /* Interrupt status register */
|
||||
#define LT_REG_COUNT 16 /* Time for countdown timer (usec) */
|
||||
#define LT_REG_SPKR 20 /* Beep control */
|
||||
|
||||
/* Granularity of countdown timer (usec) */
|
||||
#define LT_GRANULARITY 1000000
|
||||
#define LT_GRANULARITY 1000000
|
||||
|
||||
static bool havetimerclock;
|
||||
|
||||
/*
|
||||
* Setup routine called by autoconf stuff when an ltimer is found.
|
||||
*/
|
||||
int
|
||||
config_ltimer(struct ltimer_softc *lt, int ltimerno)
|
||||
{
|
||||
/*
|
||||
* Running on System/161 2.x, we always use the processor
|
||||
* on-chip timer for hardclock and we don't need ltimer as
|
||||
* hardclock.
|
||||
*
|
||||
* Ideally there should be code here that will use an ltimer
|
||||
* for hardclock if nothing else is available; e.g. if we
|
||||
* wanted to make OS/161 2.x run on System/161 1.x. However,
|
||||
* that requires a good bit more infrastructure for handling
|
||||
* timers than we have and it doesn't seem worthwhile.
|
||||
*
|
||||
* It would also require some hacking, because all CPUs need
|
||||
* to receive timer interrupts. (Exercise: how would you make
|
||||
* sure all CPUs receive exactly one timer interrupt? Remember
|
||||
* that LAMEbus uses level-triggered interrupts, so the
|
||||
* hardware interrupt line will cause repeated interrupts if
|
||||
* it's not reset on the device; but if it's reset on the
|
||||
* device before all CPUs manage to see it, those CPUs won't
|
||||
* be interrupted at all.)
|
||||
*
|
||||
* Note that the beep and rtclock devices *do* attach to
|
||||
* ltimer.
|
||||
*/
|
||||
(void)ltimerno;
|
||||
lt->lt_hardclock = 0;
|
||||
int config_ltimer(struct ltimer_softc *lt, int ltimerno) {
|
||||
/*
|
||||
* Running on System/161 2.x, we always use the processor
|
||||
* on-chip timer for hardclock and we don't need ltimer as
|
||||
* hardclock.
|
||||
*
|
||||
* Ideally there should be code here that will use an ltimer
|
||||
* for hardclock if nothing else is available; e.g. if we
|
||||
* wanted to make OS/161 2.x run on System/161 1.x. However,
|
||||
* that requires a good bit more infrastructure for handling
|
||||
* timers than we have and it doesn't seem worthwhile.
|
||||
*
|
||||
* It would also require some hacking, because all CPUs need
|
||||
* to receive timer interrupts. (Exercise: how would you make
|
||||
* sure all CPUs receive exactly one timer interrupt? Remember
|
||||
* that LAMEbus uses level-triggered interrupts, so the
|
||||
* hardware interrupt line will cause repeated interrupts if
|
||||
* it's not reset on the device; but if it's reset on the
|
||||
* device before all CPUs manage to see it, those CPUs won't
|
||||
* be interrupted at all.)
|
||||
*
|
||||
* Note that the beep and rtclock devices *do* attach to
|
||||
* ltimer.
|
||||
*/
|
||||
(void)ltimerno;
|
||||
lt->lt_hardclock = 0;
|
||||
|
||||
/*
|
||||
* We do, however, use ltimer for the timer clock, since the
|
||||
* on-chip timer can't do that.
|
||||
*/
|
||||
if (!havetimerclock) {
|
||||
havetimerclock = true;
|
||||
lt->lt_timerclock = 1;
|
||||
/*
|
||||
* We do, however, use ltimer for the timer clock, since the
|
||||
* on-chip timer can't do that.
|
||||
*/
|
||||
if (!havetimerclock) {
|
||||
havetimerclock = true;
|
||||
lt->lt_timerclock = 1;
|
||||
|
||||
/* Wire it to go off once every second. */
|
||||
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_ROE, 1);
|
||||
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_COUNT,
|
||||
LT_GRANULARITY);
|
||||
}
|
||||
/* Wire it to go off once every second. */
|
||||
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_ROE, 1);
|
||||
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_COUNT, LT_GRANULARITY);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt handler.
|
||||
*/
|
||||
void
|
||||
ltimer_irq(void *vlt)
|
||||
{
|
||||
struct ltimer_softc *lt = vlt;
|
||||
uint32_t val;
|
||||
void ltimer_irq(void *vlt) {
|
||||
struct ltimer_softc *lt = vlt;
|
||||
uint32_t val;
|
||||
|
||||
val = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_IRQ);
|
||||
if (val) {
|
||||
/*
|
||||
* Only call hardclock if we're responsible for hardclock.
|
||||
* (Any additional timer devices are unused.)
|
||||
*/
|
||||
if (lt->lt_hardclock) {
|
||||
hardclock();
|
||||
}
|
||||
/*
|
||||
* Likewise for timerclock.
|
||||
*/
|
||||
if (lt->lt_timerclock) {
|
||||
timerclock();
|
||||
}
|
||||
}
|
||||
val = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_IRQ);
|
||||
if (val) {
|
||||
/*
|
||||
* Only call hardclock if we're responsible for hardclock.
|
||||
* (Any additional timer devices are unused.)
|
||||
*/
|
||||
if (lt->lt_hardclock) {
|
||||
hardclock();
|
||||
}
|
||||
/*
|
||||
* Likewise for timerclock.
|
||||
*/
|
||||
if (lt->lt_timerclock) {
|
||||
timerclock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -132,12 +127,10 @@ ltimer_irq(void *vlt)
|
||||
* doesn't matter what value you write. This function is called if
|
||||
* the beep device is attached to this timer.
|
||||
*/
|
||||
void
|
||||
ltimer_beep(void *vlt)
|
||||
{
|
||||
struct ltimer_softc *lt = vlt;
|
||||
void ltimer_beep(void *vlt) {
|
||||
struct ltimer_softc *lt = vlt;
|
||||
|
||||
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_SPKR, 440);
|
||||
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_SPKR, 440);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -145,43 +138,37 @@ ltimer_beep(void *vlt)
|
||||
* This function gets called if the rtclock device is attached
|
||||
* to this timer.
|
||||
*/
|
||||
void
|
||||
ltimer_gettime(void *vlt, struct timespec *ts)
|
||||
{
|
||||
struct ltimer_softc *lt = vlt;
|
||||
uint32_t secs1, secs2;
|
||||
int spl;
|
||||
void ltimer_gettime(void *vlt, struct timespec *ts) {
|
||||
struct ltimer_softc *lt = vlt;
|
||||
uint32_t secs1, secs2;
|
||||
int spl;
|
||||
|
||||
/*
|
||||
* Read the seconds twice, on either side of the nanoseconds.
|
||||
* If nsecs is small, use the *later* value of seconds, in case
|
||||
* the nanoseconds turned over between the time we got the earlier
|
||||
* value and the time we got nsecs.
|
||||
*
|
||||
* Note that the clock in the ltimer device is accurate down
|
||||
* to a single processor cycle, so this might actually matter
|
||||
* now and then.
|
||||
*
|
||||
* Do it with interrupts off on the current processor to avoid
|
||||
* getting garbage if we get an interrupt among the register
|
||||
* reads.
|
||||
*/
|
||||
/*
|
||||
* Read the seconds twice, on either side of the nanoseconds.
|
||||
* If nsecs is small, use the *later* value of seconds, in case
|
||||
* the nanoseconds turned over between the time we got the earlier
|
||||
* value and the time we got nsecs.
|
||||
*
|
||||
* Note that the clock in the ltimer device is accurate down
|
||||
* to a single processor cycle, so this might actually matter
|
||||
* now and then.
|
||||
*
|
||||
* Do it with interrupts off on the current processor to avoid
|
||||
* getting garbage if we get an interrupt among the register
|
||||
* reads.
|
||||
*/
|
||||
|
||||
spl = splhigh();
|
||||
spl = splhigh();
|
||||
|
||||
secs1 = bus_read_register(lt->lt_bus, lt->lt_buspos,
|
||||
LT_REG_SEC);
|
||||
ts->tv_nsec = bus_read_register(lt->lt_bus, lt->lt_buspos,
|
||||
LT_REG_NSEC);
|
||||
secs2 = bus_read_register(lt->lt_bus, lt->lt_buspos,
|
||||
LT_REG_SEC);
|
||||
secs1 = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_SEC);
|
||||
ts->tv_nsec = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_NSEC);
|
||||
secs2 = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_SEC);
|
||||
|
||||
splx(spl);
|
||||
splx(spl);
|
||||
|
||||
if (ts->tv_nsec < 5000000) {
|
||||
ts->tv_sec = secs2;
|
||||
}
|
||||
else {
|
||||
ts->tv_sec = secs1;
|
||||
}
|
||||
if (ts->tv_nsec < 5000000) {
|
||||
ts->tv_sec = secs2;
|
||||
} else {
|
||||
ts->tv_sec = secs1;
|
||||
}
|
||||
}
|
||||
|
@ -36,21 +36,21 @@ struct timespec;
|
||||
* Hardware device data for LAMEbus timer device
|
||||
*/
|
||||
struct ltimer_softc {
|
||||
/* Initialized by config function */
|
||||
int lt_hardclock; /* true if we should call hardclock() */
|
||||
int lt_timerclock; /* true if we should call timerclock() */
|
||||
/* Initialized by config function */
|
||||
int lt_hardclock; /* true if we should call hardclock() */
|
||||
int lt_timerclock; /* true if we should call timerclock() */
|
||||
|
||||
/* Initialized by lower-level attach routine */
|
||||
void *lt_bus; /* bus we're on */
|
||||
uint32_t lt_buspos; /* position (slot) on that bus */
|
||||
/* Initialized by lower-level attach routine */
|
||||
void *lt_bus; /* bus we're on */
|
||||
uint32_t lt_buspos; /* position (slot) on that bus */
|
||||
};
|
||||
|
||||
/* Functions called by lower-level drivers */
|
||||
void ltimer_irq(/*struct ltimer_softc*/ void *lt); // interrupt handler
|
||||
void ltimer_irq(/*struct ltimer_softc*/ void *lt); // interrupt handler
|
||||
|
||||
/* Functions called by higher-level devices */
|
||||
void ltimer_beep(/*struct ltimer_softc*/ void *devdata); // for beep device
|
||||
void ltimer_beep(/*struct ltimer_softc*/ void *devdata); // for beep device
|
||||
void ltimer_gettime(/*struct ltimer_softc*/ void *devdata,
|
||||
struct timespec *ts); // for rtclock
|
||||
struct timespec *ts); // for rtclock
|
||||
|
||||
#endif /* _LAMEBUS_LTIMER_H_ */
|
||||
|
@ -37,34 +37,33 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Lowest revision we support */
|
||||
#define LOW_VERSION 1
|
||||
#define LOW_VERSION 1
|
||||
|
||||
struct ltimer_softc *
|
||||
attach_ltimer_to_lamebus(int ltimerno, struct lamebus_softc *sc)
|
||||
{
|
||||
struct ltimer_softc *lt;
|
||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TIMER,
|
||||
LOW_VERSION, NULL);
|
||||
if (slot < 0) {
|
||||
/* No ltimer (or no additional ltimer) found */
|
||||
return NULL;
|
||||
}
|
||||
struct ltimer_softc *attach_ltimer_to_lamebus(int ltimerno,
|
||||
struct lamebus_softc *sc) {
|
||||
struct ltimer_softc *lt;
|
||||
int slot =
|
||||
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TIMER, LOW_VERSION, NULL);
|
||||
if (slot < 0) {
|
||||
/* No ltimer (or no additional ltimer) found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lt = kmalloc(sizeof(struct ltimer_softc));
|
||||
if (lt==NULL) {
|
||||
/* out of memory */
|
||||
return NULL;
|
||||
}
|
||||
lt = kmalloc(sizeof(struct ltimer_softc));
|
||||
if (lt == NULL) {
|
||||
/* out of memory */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)ltimerno; // unused
|
||||
(void)ltimerno; // unused
|
||||
|
||||
/* Record what bus it's on */
|
||||
lt->lt_bus = sc;
|
||||
lt->lt_buspos = slot;
|
||||
/* Record what bus it's on */
|
||||
lt->lt_bus = sc;
|
||||
lt->lt_buspos = slot;
|
||||
|
||||
/* Mark the slot in use and hook that slot's interrupt */
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_attach_interrupt(sc, slot, lt, ltimer_irq);
|
||||
/* Mark the slot in use and hook that slot's interrupt */
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_attach_interrupt(sc, slot, lt, ltimer_irq);
|
||||
|
||||
return lt;
|
||||
return lt;
|
||||
}
|
||||
|
@ -34,83 +34,67 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Registers (offsets within slot) */
|
||||
#define LTRACE_REG_TRON 0 /* trace on */
|
||||
#define LTRACE_REG_TROFF 4 /* trace off */
|
||||
#define LTRACE_REG_DEBUG 8 /* debug code */
|
||||
#define LTRACE_REG_DUMP 12 /* dump the system */
|
||||
#define LTRACE_REG_STOP 16 /* stop for the debugger */
|
||||
#define LTRACE_REG_PROFEN 20 /* turn profiling on/off */
|
||||
#define LTRACE_REG_PROFCL 24 /* clear the profile */
|
||||
#define LTRACE_REG_TRON 0 /* trace on */
|
||||
#define LTRACE_REG_TROFF 4 /* trace off */
|
||||
#define LTRACE_REG_DEBUG 8 /* debug code */
|
||||
#define LTRACE_REG_DUMP 12 /* dump the system */
|
||||
#define LTRACE_REG_STOP 16 /* stop for the debugger */
|
||||
#define LTRACE_REG_PROFEN 20 /* turn profiling on/off */
|
||||
#define LTRACE_REG_PROFCL 24 /* clear the profile */
|
||||
|
||||
static struct ltrace_softc *the_trace;
|
||||
|
||||
void
|
||||
ltrace_on(uint32_t code)
|
||||
{
|
||||
if (the_trace != NULL) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_TRON, code);
|
||||
}
|
||||
void ltrace_on(uint32_t code) {
|
||||
if (the_trace != NULL) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_TRON, code);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ltrace_off(uint32_t code)
|
||||
{
|
||||
if (the_trace != NULL) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_TROFF, code);
|
||||
}
|
||||
void ltrace_off(uint32_t code) {
|
||||
if (the_trace != NULL) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_TROFF, code);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ltrace_debug(uint32_t code)
|
||||
{
|
||||
if (the_trace != NULL) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_DEBUG, code);
|
||||
}
|
||||
void ltrace_debug(uint32_t code) {
|
||||
if (the_trace != NULL) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_DEBUG, code);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ltrace_dump(uint32_t code)
|
||||
{
|
||||
if (the_trace != NULL) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_DUMP, code);
|
||||
}
|
||||
void ltrace_dump(uint32_t code) {
|
||||
if (the_trace != NULL) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_DUMP, code);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ltrace_stop(uint32_t code)
|
||||
{
|
||||
if (the_trace != NULL && the_trace->lt_canstop) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_STOP, code);
|
||||
}
|
||||
void ltrace_stop(uint32_t code) {
|
||||
if (the_trace != NULL && the_trace->lt_canstop) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_STOP, code);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ltrace_setprof(uint32_t onoff)
|
||||
{
|
||||
if (the_trace != NULL && the_trace->lt_canprof) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_PROFEN, onoff);
|
||||
}
|
||||
void ltrace_setprof(uint32_t onoff) {
|
||||
if (the_trace != NULL && the_trace->lt_canprof) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_PROFEN, onoff);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ltrace_eraseprof(void)
|
||||
{
|
||||
if (the_trace != NULL && the_trace->lt_canprof) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_PROFCL, 1);
|
||||
}
|
||||
void ltrace_eraseprof(void) {
|
||||
if (the_trace != NULL && the_trace->lt_canprof) {
|
||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||
LTRACE_REG_PROFCL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
config_ltrace(struct ltrace_softc *sc, int ltraceno)
|
||||
{
|
||||
(void)ltraceno;
|
||||
the_trace = sc;
|
||||
return 0;
|
||||
int config_ltrace(struct ltrace_softc *sc, int ltraceno) {
|
||||
(void)ltraceno;
|
||||
the_trace = sc;
|
||||
return 0;
|
||||
}
|
||||
|
@ -31,11 +31,11 @@
|
||||
#define _LAMEBUS_LTRACE_H_
|
||||
|
||||
struct ltrace_softc {
|
||||
/* Initialized by lower-level attachment function */
|
||||
void *lt_busdata;
|
||||
uint32_t lt_buspos;
|
||||
bool lt_canstop;
|
||||
bool lt_canprof;
|
||||
/* Initialized by lower-level attachment function */
|
||||
void *lt_busdata;
|
||||
uint32_t lt_buspos;
|
||||
bool lt_canstop;
|
||||
bool lt_canprof;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -34,36 +34,35 @@
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Lowest revision we support */
|
||||
#define LOW_VERSION 1
|
||||
#define LOW_VERSION 1
|
||||
/* Revision that supports ltrace_stop() */
|
||||
#define STOP_VERSION 2
|
||||
#define STOP_VERSION 2
|
||||
/* Revision that supports ltrace_prof() */
|
||||
#define PROF_VERSION 3
|
||||
#define PROF_VERSION 3
|
||||
|
||||
struct ltrace_softc *
|
||||
attach_ltrace_to_lamebus(int ltraceno, struct lamebus_softc *sc)
|
||||
{
|
||||
struct ltrace_softc *lt;
|
||||
uint32_t drl;
|
||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TRACE,
|
||||
LOW_VERSION, &drl);
|
||||
if (slot < 0) {
|
||||
return NULL;
|
||||
}
|
||||
struct ltrace_softc *attach_ltrace_to_lamebus(int ltraceno,
|
||||
struct lamebus_softc *sc) {
|
||||
struct ltrace_softc *lt;
|
||||
uint32_t drl;
|
||||
int slot =
|
||||
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TRACE, LOW_VERSION, &drl);
|
||||
if (slot < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lt = kmalloc(sizeof(struct ltrace_softc));
|
||||
if (lt==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
lt = kmalloc(sizeof(struct ltrace_softc));
|
||||
if (lt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)ltraceno; // unused
|
||||
(void)ltraceno; // unused
|
||||
|
||||
lt->lt_busdata = sc;
|
||||
lt->lt_buspos = slot;
|
||||
lt->lt_canstop = drl >= STOP_VERSION;
|
||||
lt->lt_canprof = drl >= PROF_VERSION;
|
||||
lt->lt_busdata = sc;
|
||||
lt->lt_buspos = slot;
|
||||
lt->lt_canstop = drl >= STOP_VERSION;
|
||||
lt->lt_canprof = drl >= PROF_VERSION;
|
||||
|
||||
lamebus_mark(sc, slot);
|
||||
lamebus_mark(sc, slot);
|
||||
|
||||
return lt;
|
||||
return lt;
|
||||
}
|
||||
|
@ -38,20 +38,19 @@
|
||||
#include <lamebus/lrandom.h>
|
||||
#include "autoconf.h"
|
||||
|
||||
struct random_softc *
|
||||
attach_random_to_lrandom(int randomno, struct lrandom_softc *ls)
|
||||
{
|
||||
struct random_softc *rs = kmalloc(sizeof(struct random_softc));
|
||||
if (rs==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
struct random_softc *attach_random_to_lrandom(int randomno,
|
||||
struct lrandom_softc *ls) {
|
||||
struct random_softc *rs = kmalloc(sizeof(struct random_softc));
|
||||
if (rs == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)randomno; // unused
|
||||
(void)randomno; // unused
|
||||
|
||||
rs->rs_devdata = ls;
|
||||
rs->rs_random = lrandom_random;
|
||||
rs->rs_randmax = lrandom_randmax;
|
||||
rs->rs_read = lrandom_read;
|
||||
rs->rs_devdata = ls;
|
||||
rs->rs_random = lrandom_random;
|
||||
rs->rs_randmax = lrandom_randmax;
|
||||
rs->rs_read = lrandom_read;
|
||||
|
||||
return rs;
|
||||
return rs;
|
||||
}
|
||||
|
@ -44,23 +44,22 @@
|
||||
#include <lamebus/ltimer.h>
|
||||
#include "autoconf.h"
|
||||
|
||||
struct rtclock_softc *
|
||||
attach_rtclock_to_ltimer(int rtclockno, struct ltimer_softc *ls)
|
||||
{
|
||||
/*
|
||||
* No need to probe; ltimer always has a clock.
|
||||
* Just allocate the rtclock, set our fields, and return it.
|
||||
*/
|
||||
struct rtclock_softc *rtc = kmalloc(sizeof(struct rtclock_softc));
|
||||
if (rtc==NULL) {
|
||||
/* Out of memory */
|
||||
return NULL;
|
||||
}
|
||||
struct rtclock_softc *attach_rtclock_to_ltimer(int rtclockno,
|
||||
struct ltimer_softc *ls) {
|
||||
/*
|
||||
* No need to probe; ltimer always has a clock.
|
||||
* Just allocate the rtclock, set our fields, and return it.
|
||||
*/
|
||||
struct rtclock_softc *rtc = kmalloc(sizeof(struct rtclock_softc));
|
||||
if (rtc == NULL) {
|
||||
/* Out of memory */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)rtclockno; // unused
|
||||
(void)rtclockno; // unused
|
||||
|
||||
rtc->rtc_devdata = ls;
|
||||
rtc->rtc_gettime = ltimer_gettime;
|
||||
rtc->rtc_devdata = ls;
|
||||
rtc->rtc_gettime = ltimer_gettime;
|
||||
|
||||
return rtc;
|
||||
return rtc;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@
|
||||
* Constants
|
||||
*/
|
||||
|
||||
#define SEMFS_ROOTDIR 0xffffffffU /* semnum for root dir */
|
||||
#define SEMFS_ROOTDIR 0xffffffffU /* semnum for root dir */
|
||||
|
||||
/*
|
||||
* A user-facing semaphore.
|
||||
@ -52,11 +52,11 @@
|
||||
* XXX: or would we? review once all this is done.
|
||||
*/
|
||||
struct semfs_sem {
|
||||
struct lock *sems_lock; /* Lock to protect count */
|
||||
struct cv *sems_cv; /* CV to wait */
|
||||
unsigned sems_count; /* Semaphore count */
|
||||
bool sems_hasvnode; /* The vnode exists */
|
||||
bool sems_linked; /* In the directory */
|
||||
struct lock *sems_lock; /* Lock to protect count */
|
||||
struct cv *sems_cv; /* CV to wait */
|
||||
unsigned sems_count; /* Semaphore count */
|
||||
bool sems_hasvnode; /* The vnode exists */
|
||||
bool sems_linked; /* In the directory */
|
||||
};
|
||||
DECLARRAY(semfs_sem, SEMFS_INLINE);
|
||||
|
||||
@ -64,8 +64,8 @@ DECLARRAY(semfs_sem, SEMFS_INLINE);
|
||||
* Directory entry; name and reference to a semaphore.
|
||||
*/
|
||||
struct semfs_direntry {
|
||||
char *semd_name; /* Name */
|
||||
unsigned semd_semnum; /* Which semaphore */
|
||||
char *semd_name; /* Name */
|
||||
unsigned semd_semnum; /* Which semaphore */
|
||||
};
|
||||
DECLARRAY(semfs_direntry, SEMFS_INLINE);
|
||||
|
||||
@ -77,9 +77,9 @@ DECLARRAY(semfs_direntry, SEMFS_INLINE);
|
||||
* practice. XXX: review after finishing)
|
||||
*/
|
||||
struct semfs_vnode {
|
||||
struct vnode semv_absvn; /* Abstract vnode */
|
||||
struct semfs *semv_semfs; /* Back-pointer to fs */
|
||||
unsigned semv_semnum; /* Which semaphore */
|
||||
struct vnode semv_absvn; /* Abstract vnode */
|
||||
struct semfs *semv_semfs; /* Back-pointer to fs */
|
||||
unsigned semv_semnum; /* Which semaphore */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -87,14 +87,14 @@ struct semfs_vnode {
|
||||
* is only one of these.
|
||||
*/
|
||||
struct semfs {
|
||||
struct fs semfs_absfs; /* Abstract fs object */
|
||||
struct fs semfs_absfs; /* Abstract fs object */
|
||||
|
||||
struct lock *semfs_tablelock; /* Lock for following */
|
||||
struct vnodearray *semfs_vnodes; /* Currently extant vnodes */
|
||||
struct semfs_semarray *semfs_sems; /* Semaphores */
|
||||
struct lock *semfs_tablelock; /* Lock for following */
|
||||
struct vnodearray *semfs_vnodes; /* Currently extant vnodes */
|
||||
struct semfs_semarray *semfs_sems; /* Semaphores */
|
||||
|
||||
struct lock *semfs_dirlock; /* Lock for following */
|
||||
struct semfs_direntryarray *semfs_dents; /* The root directory */
|
||||
struct lock *semfs_dirlock; /* Lock for following */
|
||||
struct semfs_direntryarray *semfs_dents; /* The root directory */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -104,7 +104,6 @@ struct semfs {
|
||||
DEFARRAY(semfs_sem, SEMFS_INLINE);
|
||||
DEFARRAY(semfs_direntry, SEMFS_INLINE);
|
||||
|
||||
|
||||
/*
|
||||
* Functions.
|
||||
*/
|
||||
@ -119,5 +118,4 @@ void semfs_direntry_destroy(struct semfs_direntry *);
|
||||
/* in semfs_vnops.c */
|
||||
int semfs_getvnode(struct semfs *, unsigned, struct vnode **ret);
|
||||
|
||||
|
||||
#endif /* SEMFS_H */
|
||||
|
@ -42,185 +42,163 @@
|
||||
/*
|
||||
* Sync doesn't need to do anything.
|
||||
*/
|
||||
static
|
||||
int
|
||||
semfs_sync(struct fs *fs)
|
||||
{
|
||||
(void)fs;
|
||||
return 0;
|
||||
static int semfs_sync(struct fs *fs) {
|
||||
(void)fs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have only one volume name and it's hardwired.
|
||||
*/
|
||||
static
|
||||
const char *
|
||||
semfs_getvolname(struct fs *fs)
|
||||
{
|
||||
(void)fs;
|
||||
return "sem";
|
||||
static const char *semfs_getvolname(struct fs *fs) {
|
||||
(void)fs;
|
||||
return "sem";
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the root directory vnode.
|
||||
*/
|
||||
static
|
||||
int
|
||||
semfs_getroot(struct fs *fs, struct vnode **ret)
|
||||
{
|
||||
struct semfs *semfs = fs->fs_data;
|
||||
struct vnode *vn;
|
||||
int result;
|
||||
static int semfs_getroot(struct fs *fs, struct vnode **ret) {
|
||||
struct semfs *semfs = fs->fs_data;
|
||||
struct vnode *vn;
|
||||
int result;
|
||||
|
||||
result = semfs_getvnode(semfs, SEMFS_ROOTDIR, &vn);
|
||||
if (result) {
|
||||
kprintf("semfs: couldn't load root vnode: %s\n",
|
||||
strerror(result));
|
||||
return result;
|
||||
}
|
||||
*ret = vn;
|
||||
return 0;
|
||||
result = semfs_getvnode(semfs, SEMFS_ROOTDIR, &vn);
|
||||
if (result) {
|
||||
kprintf("semfs: couldn't load root vnode: %s\n", strerror(result));
|
||||
return result;
|
||||
}
|
||||
*ret = vn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// mount and unmount logic
|
||||
|
||||
|
||||
/*
|
||||
* Destructor for struct semfs.
|
||||
*/
|
||||
static
|
||||
void
|
||||
semfs_destroy(struct semfs *semfs)
|
||||
{
|
||||
struct semfs_sem *sem;
|
||||
struct semfs_direntry *dent;
|
||||
unsigned i, num;
|
||||
static void semfs_destroy(struct semfs *semfs) {
|
||||
struct semfs_sem *sem;
|
||||
struct semfs_direntry *dent;
|
||||
unsigned i, num;
|
||||
|
||||
num = semfs_semarray_num(semfs->semfs_sems);
|
||||
for (i=0; i<num; i++) {
|
||||
sem = semfs_semarray_get(semfs->semfs_sems, i);
|
||||
semfs_sem_destroy(sem);
|
||||
}
|
||||
semfs_semarray_setsize(semfs->semfs_sems, 0);
|
||||
num = semfs_semarray_num(semfs->semfs_sems);
|
||||
for (i = 0; i < num; i++) {
|
||||
sem = semfs_semarray_get(semfs->semfs_sems, i);
|
||||
semfs_sem_destroy(sem);
|
||||
}
|
||||
semfs_semarray_setsize(semfs->semfs_sems, 0);
|
||||
|
||||
num = semfs_direntryarray_num(semfs->semfs_dents);
|
||||
for (i=0; i<num; i++) {
|
||||
dent = semfs_direntryarray_get(semfs->semfs_dents, i);
|
||||
semfs_direntry_destroy(dent);
|
||||
}
|
||||
semfs_direntryarray_setsize(semfs->semfs_dents, 0);
|
||||
num = semfs_direntryarray_num(semfs->semfs_dents);
|
||||
for (i = 0; i < num; i++) {
|
||||
dent = semfs_direntryarray_get(semfs->semfs_dents, i);
|
||||
semfs_direntry_destroy(dent);
|
||||
}
|
||||
semfs_direntryarray_setsize(semfs->semfs_dents, 0);
|
||||
|
||||
semfs_direntryarray_destroy(semfs->semfs_dents);
|
||||
lock_destroy(semfs->semfs_dirlock);
|
||||
semfs_semarray_destroy(semfs->semfs_sems);
|
||||
vnodearray_destroy(semfs->semfs_vnodes);
|
||||
lock_destroy(semfs->semfs_tablelock);
|
||||
kfree(semfs);
|
||||
semfs_direntryarray_destroy(semfs->semfs_dents);
|
||||
lock_destroy(semfs->semfs_dirlock);
|
||||
semfs_semarray_destroy(semfs->semfs_sems);
|
||||
vnodearray_destroy(semfs->semfs_vnodes);
|
||||
lock_destroy(semfs->semfs_tablelock);
|
||||
kfree(semfs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmount routine. XXX: Since semfs is attached at boot and can't be
|
||||
* remounted, maybe unmounting it shouldn't be allowed.
|
||||
*/
|
||||
static
|
||||
int
|
||||
semfs_unmount(struct fs *fs)
|
||||
{
|
||||
struct semfs *semfs = fs->fs_data;
|
||||
static int semfs_unmount(struct fs *fs) {
|
||||
struct semfs *semfs = fs->fs_data;
|
||||
|
||||
lock_acquire(semfs->semfs_tablelock);
|
||||
if (vnodearray_num(semfs->semfs_vnodes) > 0) {
|
||||
lock_release(semfs->semfs_tablelock);
|
||||
return EBUSY;
|
||||
}
|
||||
lock_acquire(semfs->semfs_tablelock);
|
||||
if (vnodearray_num(semfs->semfs_vnodes) > 0) {
|
||||
lock_release(semfs->semfs_tablelock);
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
lock_release(semfs->semfs_tablelock);
|
||||
semfs_destroy(semfs);
|
||||
lock_release(semfs->semfs_tablelock);
|
||||
semfs_destroy(semfs);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Operations table.
|
||||
*/
|
||||
static const struct fs_ops semfs_fsops = {
|
||||
.fsop_sync = semfs_sync,
|
||||
.fsop_getvolname = semfs_getvolname,
|
||||
.fsop_getroot = semfs_getroot,
|
||||
.fsop_unmount = semfs_unmount,
|
||||
.fsop_sync = semfs_sync,
|
||||
.fsop_getvolname = semfs_getvolname,
|
||||
.fsop_getroot = semfs_getroot,
|
||||
.fsop_unmount = semfs_unmount,
|
||||
};
|
||||
|
||||
/*
|
||||
* Constructor for struct semfs.
|
||||
*/
|
||||
static
|
||||
struct semfs *
|
||||
semfs_create(void)
|
||||
{
|
||||
struct semfs *semfs;
|
||||
static struct semfs *semfs_create(void) {
|
||||
struct semfs *semfs;
|
||||
|
||||
semfs = kmalloc(sizeof(*semfs));
|
||||
if (semfs == NULL) {
|
||||
goto fail_total;
|
||||
}
|
||||
semfs = kmalloc(sizeof(*semfs));
|
||||
if (semfs == NULL) {
|
||||
goto fail_total;
|
||||
}
|
||||
|
||||
semfs->semfs_tablelock = lock_create("semfs_table");
|
||||
if (semfs->semfs_tablelock == NULL) {
|
||||
goto fail_semfs;
|
||||
}
|
||||
semfs->semfs_vnodes = vnodearray_create();
|
||||
if (semfs->semfs_vnodes == NULL) {
|
||||
goto fail_tablelock;
|
||||
}
|
||||
semfs->semfs_sems = semfs_semarray_create();
|
||||
if (semfs->semfs_sems == NULL) {
|
||||
goto fail_vnodes;
|
||||
}
|
||||
semfs->semfs_tablelock = lock_create("semfs_table");
|
||||
if (semfs->semfs_tablelock == NULL) {
|
||||
goto fail_semfs;
|
||||
}
|
||||
semfs->semfs_vnodes = vnodearray_create();
|
||||
if (semfs->semfs_vnodes == NULL) {
|
||||
goto fail_tablelock;
|
||||
}
|
||||
semfs->semfs_sems = semfs_semarray_create();
|
||||
if (semfs->semfs_sems == NULL) {
|
||||
goto fail_vnodes;
|
||||
}
|
||||
|
||||
semfs->semfs_dirlock = lock_create("semfs_dir");
|
||||
if (semfs->semfs_dirlock == NULL) {
|
||||
goto fail_sems;
|
||||
}
|
||||
semfs->semfs_dents = semfs_direntryarray_create();
|
||||
if (semfs->semfs_dents == NULL) {
|
||||
goto fail_dirlock;
|
||||
}
|
||||
semfs->semfs_dirlock = lock_create("semfs_dir");
|
||||
if (semfs->semfs_dirlock == NULL) {
|
||||
goto fail_sems;
|
||||
}
|
||||
semfs->semfs_dents = semfs_direntryarray_create();
|
||||
if (semfs->semfs_dents == NULL) {
|
||||
goto fail_dirlock;
|
||||
}
|
||||
|
||||
semfs->semfs_absfs.fs_data = semfs;
|
||||
semfs->semfs_absfs.fs_ops = &semfs_fsops;
|
||||
return semfs;
|
||||
semfs->semfs_absfs.fs_data = semfs;
|
||||
semfs->semfs_absfs.fs_ops = &semfs_fsops;
|
||||
return semfs;
|
||||
|
||||
fail_dirlock:
|
||||
lock_destroy(semfs->semfs_dirlock);
|
||||
fail_sems:
|
||||
semfs_semarray_destroy(semfs->semfs_sems);
|
||||
fail_vnodes:
|
||||
vnodearray_destroy(semfs->semfs_vnodes);
|
||||
fail_tablelock:
|
||||
lock_destroy(semfs->semfs_tablelock);
|
||||
fail_semfs:
|
||||
kfree(semfs);
|
||||
fail_total:
|
||||
return NULL;
|
||||
fail_dirlock:
|
||||
lock_destroy(semfs->semfs_dirlock);
|
||||
fail_sems:
|
||||
semfs_semarray_destroy(semfs->semfs_sems);
|
||||
fail_vnodes:
|
||||
vnodearray_destroy(semfs->semfs_vnodes);
|
||||
fail_tablelock:
|
||||
lock_destroy(semfs->semfs_tablelock);
|
||||
fail_semfs:
|
||||
kfree(semfs);
|
||||
fail_total:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the semfs. There is only one semfs and it's attached as
|
||||
* "sem:" during bootup.
|
||||
*/
|
||||
void
|
||||
semfs_bootstrap(void)
|
||||
{
|
||||
struct semfs *semfs;
|
||||
int result;
|
||||
void semfs_bootstrap(void) {
|
||||
struct semfs *semfs;
|
||||
int result;
|
||||
|
||||
semfs = semfs_create();
|
||||
if (semfs == NULL) {
|
||||
panic("Out of memory creating semfs\n");
|
||||
}
|
||||
result = vfs_addfs("sem", &semfs->semfs_absfs);
|
||||
if (result) {
|
||||
panic("Attaching semfs: %s\n", strerror(result));
|
||||
}
|
||||
semfs = semfs_create();
|
||||
if (semfs == NULL) {
|
||||
panic("Out of memory creating semfs\n");
|
||||
}
|
||||
result = vfs_addfs("sem", &semfs->semfs_absfs);
|
||||
if (result) {
|
||||
panic("Attaching semfs: %s\n", strerror(result));
|
||||
}
|
||||
}
|
||||
|
@ -40,74 +40,69 @@
|
||||
/*
|
||||
* Constructor for semfs_sem.
|
||||
*/
|
||||
struct semfs_sem *
|
||||
semfs_sem_create(const char *name)
|
||||
{
|
||||
struct semfs_sem *sem;
|
||||
char lockname[32];
|
||||
char cvname[32];
|
||||
struct semfs_sem *semfs_sem_create(const char *name) {
|
||||
struct semfs_sem *sem;
|
||||
char lockname[32];
|
||||
char cvname[32];
|
||||
|
||||
snprintf(lockname, sizeof(lockname), "sem:l.%s", name);
|
||||
snprintf(cvname, sizeof(cvname), "sem:%s", name);
|
||||
snprintf(lockname, sizeof(lockname), "sem:l.%s", name);
|
||||
snprintf(cvname, sizeof(cvname), "sem:%s", name);
|
||||
|
||||
sem = kmalloc(sizeof(*sem));
|
||||
if (sem == NULL) {
|
||||
goto fail_return;
|
||||
}
|
||||
sem->sems_lock = lock_create(lockname);
|
||||
if (sem->sems_lock == NULL) {
|
||||
goto fail_sem;
|
||||
}
|
||||
sem->sems_cv = cv_create(cvname);
|
||||
if (sem->sems_cv == NULL) {
|
||||
goto fail_lock;
|
||||
}
|
||||
sem->sems_count = 0;
|
||||
sem->sems_hasvnode = false;
|
||||
sem->sems_linked = false;
|
||||
return sem;
|
||||
sem = kmalloc(sizeof(*sem));
|
||||
if (sem == NULL) {
|
||||
goto fail_return;
|
||||
}
|
||||
sem->sems_lock = lock_create(lockname);
|
||||
if (sem->sems_lock == NULL) {
|
||||
goto fail_sem;
|
||||
}
|
||||
sem->sems_cv = cv_create(cvname);
|
||||
if (sem->sems_cv == NULL) {
|
||||
goto fail_lock;
|
||||
}
|
||||
sem->sems_count = 0;
|
||||
sem->sems_hasvnode = false;
|
||||
sem->sems_linked = false;
|
||||
return sem;
|
||||
|
||||
fail_lock:
|
||||
lock_destroy(sem->sems_lock);
|
||||
fail_sem:
|
||||
kfree(sem);
|
||||
fail_return:
|
||||
return NULL;
|
||||
fail_lock:
|
||||
lock_destroy(sem->sems_lock);
|
||||
fail_sem:
|
||||
kfree(sem);
|
||||
fail_return:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destructor for semfs_sem.
|
||||
*/
|
||||
void
|
||||
semfs_sem_destroy(struct semfs_sem *sem)
|
||||
{
|
||||
cv_destroy(sem->sems_cv);
|
||||
lock_destroy(sem->sems_lock);
|
||||
kfree(sem);
|
||||
void semfs_sem_destroy(struct semfs_sem *sem) {
|
||||
cv_destroy(sem->sems_cv);
|
||||
lock_destroy(sem->sems_lock);
|
||||
kfree(sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper to insert a semfs_sem into the semaphore table.
|
||||
*/
|
||||
int
|
||||
semfs_sem_insert(struct semfs *semfs, struct semfs_sem *sem, unsigned *ret)
|
||||
{
|
||||
unsigned i, num;
|
||||
int semfs_sem_insert(struct semfs *semfs, struct semfs_sem *sem,
|
||||
unsigned *ret) {
|
||||
unsigned i, num;
|
||||
|
||||
KASSERT(lock_do_i_hold(semfs->semfs_tablelock));
|
||||
num = semfs_semarray_num(semfs->semfs_sems);
|
||||
if (num == SEMFS_ROOTDIR) {
|
||||
/* Too many */
|
||||
return ENOSPC;
|
||||
}
|
||||
for (i=0; i<num; i++) {
|
||||
if (semfs_semarray_get(semfs->semfs_sems, i) == NULL) {
|
||||
semfs_semarray_set(semfs->semfs_sems, i, sem);
|
||||
*ret = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return semfs_semarray_add(semfs->semfs_sems, sem, ret);
|
||||
KASSERT(lock_do_i_hold(semfs->semfs_tablelock));
|
||||
num = semfs_semarray_num(semfs->semfs_sems);
|
||||
if (num == SEMFS_ROOTDIR) {
|
||||
/* Too many */
|
||||
return ENOSPC;
|
||||
}
|
||||
for (i = 0; i < num; i++) {
|
||||
if (semfs_semarray_get(semfs->semfs_sems, i) == NULL) {
|
||||
semfs_semarray_set(semfs->semfs_sems, i, sem);
|
||||
*ret = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return semfs_semarray_add(semfs->semfs_sems, sem, ret);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -116,30 +111,27 @@ semfs_sem_insert(struct semfs *semfs, struct semfs_sem *sem, unsigned *ret)
|
||||
/*
|
||||
* Constructor for semfs_direntry.
|
||||
*/
|
||||
struct semfs_direntry *
|
||||
semfs_direntry_create(const char *name, unsigned semnum)
|
||||
{
|
||||
struct semfs_direntry *dent;
|
||||
struct semfs_direntry *semfs_direntry_create(const char *name,
|
||||
unsigned semnum) {
|
||||
struct semfs_direntry *dent;
|
||||
|
||||
dent = kmalloc(sizeof(*dent));
|
||||
if (dent == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
dent->semd_name = kstrdup(name);
|
||||
if (dent->semd_name == NULL) {
|
||||
kfree(dent);
|
||||
return NULL;
|
||||
}
|
||||
dent->semd_semnum = semnum;
|
||||
return dent;
|
||||
dent = kmalloc(sizeof(*dent));
|
||||
if (dent == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
dent->semd_name = kstrdup(name);
|
||||
if (dent->semd_name == NULL) {
|
||||
kfree(dent);
|
||||
return NULL;
|
||||
}
|
||||
dent->semd_semnum = semnum;
|
||||
return dent;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destructor for semfs_direntry.
|
||||
*/
|
||||
void
|
||||
semfs_direntry_destroy(struct semfs_direntry *dent)
|
||||
{
|
||||
kfree(dent->semd_name);
|
||||
kfree(dent);
|
||||
void semfs_direntry_destroy(struct semfs_direntry *dent) {
|
||||
kfree(dent->semd_name);
|
||||
kfree(dent);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user