clang-format
This commit is contained in:
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
|
* is less than either x or y (the choice to compare with x or y is
|
||||||
* arbitrary).
|
* arbitrary).
|
||||||
*/
|
*/
|
||||||
long long
|
long long __adddi3(long long a, long long b) {
|
||||||
__adddi3(long long a, long long b)
|
union uu aa, bb, sum;
|
||||||
{
|
|
||||||
union uu aa, bb, sum;
|
|
||||||
|
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
bb.ll = b;
|
bb.ll = b;
|
||||||
sum.ui[L] = aa.ui[L] + bb.ui[L];
|
sum.ui[L] = aa.ui[L] + bb.ui[L];
|
||||||
sum.ui[H] = aa.ui[H] + bb.ui[H] + (sum.ui[L] < bb.ui[L]);
|
sum.ui[H] = aa.ui[H] + bb.ui[H] + (sum.ui[L] < bb.ui[L]);
|
||||||
return (sum.ll);
|
return (sum.ll);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,14 +40,12 @@
|
|||||||
/*
|
/*
|
||||||
* Return a & b, in long long.
|
* Return a & b, in long long.
|
||||||
*/
|
*/
|
||||||
long long
|
long long __anddi3(long long a, long long b) {
|
||||||
__anddi3(long long a, long long b)
|
union uu aa, bb;
|
||||||
{
|
|
||||||
union uu aa, bb;
|
|
||||||
|
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
bb.ll = b;
|
bb.ll = b;
|
||||||
aa.ui[0] &= bb.ui[0];
|
aa.ui[0] &= bb.ui[0];
|
||||||
aa.ui[1] &= bb.ui[1];
|
aa.ui[1] &= bb.ui[1];
|
||||||
return (aa.ll);
|
return (aa.ll);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,21 +41,18 @@
|
|||||||
* Shift a (signed) long long value left (arithmetic shift left).
|
* Shift a (signed) long long value left (arithmetic shift left).
|
||||||
* This is the same as logical shift left!
|
* This is the same as logical shift left!
|
||||||
*/
|
*/
|
||||||
long long
|
long long __ashldi3(long long a, unsigned int shift) {
|
||||||
__ashldi3(long long a, unsigned int shift)
|
union uu aa;
|
||||||
{
|
|
||||||
union uu aa;
|
|
||||||
|
|
||||||
if (shift == 0)
|
if (shift == 0)
|
||||||
return(a);
|
return (a);
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
if (shift >= INT_BITS) {
|
if (shift >= INT_BITS) {
|
||||||
aa.ui[H] = aa.ui[L] << (shift - INT_BITS);
|
aa.ui[H] = aa.ui[L] << (shift - INT_BITS);
|
||||||
aa.ui[L] = 0;
|
aa.ui[L] = 0;
|
||||||
} else {
|
} else {
|
||||||
aa.ui[H] = (aa.ui[H] << shift) |
|
aa.ui[H] = (aa.ui[H] << shift) | (aa.ui[L] >> (INT_BITS - shift));
|
||||||
(aa.ui[L] >> (INT_BITS - shift));
|
aa.ui[L] <<= shift;
|
||||||
aa.ui[L] <<= shift;
|
}
|
||||||
}
|
return (aa.ll);
|
||||||
return (aa.ll);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,34 +40,31 @@
|
|||||||
/*
|
/*
|
||||||
* Shift a (signed) long long value right (arithmetic shift right).
|
* Shift a (signed) long long value right (arithmetic shift right).
|
||||||
*/
|
*/
|
||||||
long long
|
long long __ashrdi3(long long a, unsigned int shift) {
|
||||||
__ashrdi3(long long a, unsigned int shift)
|
union uu aa;
|
||||||
{
|
|
||||||
union uu aa;
|
|
||||||
|
|
||||||
if (shift == 0)
|
if (shift == 0)
|
||||||
return(a);
|
return (a);
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
if (shift >= INT_BITS) {
|
if (shift >= INT_BITS) {
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Smear bits rightward using the machine's right-shift
|
* Smear bits rightward using the machine's right-shift
|
||||||
* method, whether that is sign extension or zero fill,
|
* method, whether that is sign extension or zero fill,
|
||||||
* to get the `sign word' s. Note that shifting by
|
* to get the `sign word' s. Note that shifting by
|
||||||
* INT_BITS is undefined, so we shift (INT_BITS-1),
|
* INT_BITS is undefined, so we shift (INT_BITS-1),
|
||||||
* then 1 more, to get our answer.
|
* then 1 more, to get our answer.
|
||||||
*/
|
*/
|
||||||
/* LINTED inherits machine dependency */
|
/* LINTED inherits machine dependency */
|
||||||
s = (aa.si[H] >> (INT_BITS - 1)) >> 1;
|
s = (aa.si[H] >> (INT_BITS - 1)) >> 1;
|
||||||
/* LINTED inherits machine dependency*/
|
/* LINTED inherits machine dependency*/
|
||||||
aa.ui[L] = aa.si[H] >> (shift - INT_BITS);
|
aa.ui[L] = aa.si[H] >> (shift - INT_BITS);
|
||||||
aa.ui[H] = s;
|
aa.ui[H] = s;
|
||||||
} else {
|
} else {
|
||||||
aa.ui[L] = (aa.ui[L] >> shift) |
|
aa.ui[L] = (aa.ui[L] >> shift) | (aa.ui[H] << (INT_BITS - shift));
|
||||||
(aa.ui[H] << (INT_BITS - shift));
|
/* LINTED inherits machine dependency */
|
||||||
/* LINTED inherits machine dependency */
|
aa.si[H] >>= shift;
|
||||||
aa.si[H] >>= shift;
|
}
|
||||||
}
|
return (aa.ll);
|
||||||
return (aa.ll);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,13 +42,14 @@
|
|||||||
* Both a and b are considered signed---which means only the high word is
|
* Both a and b are considered signed---which means only the high word is
|
||||||
* signed.
|
* signed.
|
||||||
*/
|
*/
|
||||||
int
|
int __cmpdi2(long long a, long long b) {
|
||||||
__cmpdi2(long long a, long long b)
|
union uu aa, bb;
|
||||||
{
|
|
||||||
union uu aa, bb;
|
|
||||||
|
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
bb.ll = b;
|
bb.ll = b;
|
||||||
return (aa.si[H] < bb.si[H] ? 0 : aa.si[H] > bb.si[H] ? 2 :
|
return (aa.si[H] < bb.si[H] ? 0
|
||||||
aa.ui[L] < bb.ui[L] ? 0 : aa.ui[L] > bb.ui[L] ? 2 : 1);
|
: 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.
|
* Divide two signed long longs.
|
||||||
* ??? if -1/2 should produce -1 on this machine, this code is wrong
|
* ??? if -1/2 should produce -1 on this machine, this code is wrong
|
||||||
*/
|
*/
|
||||||
long long
|
long long __divdi3(long long a, long long b) {
|
||||||
__divdi3(long long a, long long b)
|
unsigned long long ua, ub, uq;
|
||||||
{
|
int neg = 0;
|
||||||
unsigned long long ua, ub, uq;
|
|
||||||
int neg = 0;
|
|
||||||
|
|
||||||
ua = a;
|
ua = a;
|
||||||
ub = b;
|
ub = b;
|
||||||
|
|
||||||
if (a < 0)
|
if (a < 0)
|
||||||
ua = -ua, neg ^= 1;
|
ua = -ua, neg ^= 1;
|
||||||
if (b < 0)
|
if (b < 0)
|
||||||
ub = -ub, neg ^= 1;
|
ub = -ub, neg ^= 1;
|
||||||
|
|
||||||
uq = __qdivrem(ua, ub, NULL);
|
uq = __qdivrem(ua, ub, NULL);
|
||||||
if (neg)
|
if (neg)
|
||||||
uq = - uq;
|
uq = -uq;
|
||||||
return uq;
|
return uq;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,14 +40,12 @@
|
|||||||
/*
|
/*
|
||||||
* Return a | b, in long long.
|
* Return a | b, in long long.
|
||||||
*/
|
*/
|
||||||
long long
|
long long __iordi3(long long a, long long b) {
|
||||||
__iordi3(long long a, long long b)
|
union uu aa, bb;
|
||||||
{
|
|
||||||
union uu aa, bb;
|
|
||||||
|
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
bb.ll = b;
|
bb.ll = b;
|
||||||
aa.ui[0] |= bb.ui[0];
|
aa.ui[0] |= bb.ui[0];
|
||||||
aa.ui[1] |= bb.ui[1];
|
aa.ui[1] |= bb.ui[1];
|
||||||
return (aa.ll);
|
return (aa.ll);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,10 +68,10 @@
|
|||||||
* one or more of the following formats.
|
* one or more of the following formats.
|
||||||
*/
|
*/
|
||||||
union uu {
|
union uu {
|
||||||
long long ll; /* as a (signed) long long */
|
long long ll; /* as a (signed) long long */
|
||||||
unsigned long long ull; /* as an unsigned long long */
|
unsigned long long ull; /* as an unsigned long long */
|
||||||
int si[2]; /* as two (signed) ints */
|
int si[2]; /* as two (signed) ints */
|
||||||
unsigned int ui[2]; /* as two unsigned ints */
|
unsigned int ui[2]; /* as two unsigned ints */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -87,15 +87,14 @@ union uu {
|
|||||||
#define L 1
|
#define L 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Total number of bits in a long long and in the pieces that make it up.
|
* 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
|
* These are used for shifting, and also below for halfword extraction
|
||||||
* and assembly.
|
* and assembly.
|
||||||
*/
|
*/
|
||||||
#define LONGLONG_BITS (sizeof(long long) * CHAR_BIT)
|
#define LONGLONG_BITS (sizeof(long long) * CHAR_BIT)
|
||||||
#define INT_BITS (sizeof(int) * CHAR_BIT)
|
#define INT_BITS (sizeof(int) * CHAR_BIT)
|
||||||
#define HALF_BITS (sizeof(int) * CHAR_BIT / 2)
|
#define HALF_BITS (sizeof(int) * CHAR_BIT / 2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract high and low shortwords from longword, and move low shortword of
|
* 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
|
* and lower halves, and to reassemble a product as a long long, shifted
|
||||||
* left (sizeof(int)*CHAR_BIT/2).
|
* left (sizeof(int)*CHAR_BIT/2).
|
||||||
*/
|
*/
|
||||||
#define HHALF(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 LHALF(x) ((unsigned int)(x) & (((int)1 << HALF_BITS) - 1))
|
||||||
#define LHUP(x) ((unsigned int)(x) << HALF_BITS)
|
#define LHUP(x) ((unsigned int)(x) << HALF_BITS)
|
||||||
|
|
||||||
long long __adddi3 ( long long, long long);
|
long long __adddi3(long long, long long);
|
||||||
long long __anddi3 ( long long, long long);
|
long long __anddi3(long long, long long);
|
||||||
long long __ashldi3 ( long long, unsigned int);
|
long long __ashldi3(long long, unsigned int);
|
||||||
long long __ashrdi3 ( long long, unsigned int);
|
long long __ashrdi3(long long, unsigned int);
|
||||||
int __cmpdi2 ( long long, long long);
|
int __cmpdi2(long long, long long);
|
||||||
long long __divdi3 ( long long, long long);
|
long long __divdi3(long long, long long);
|
||||||
long long __iordi3 ( long long, long long);
|
long long __iordi3(long long, long long);
|
||||||
long long __lshldi3 ( long long, unsigned int);
|
long long __lshldi3(long long, unsigned int);
|
||||||
long long __lshrdi3 ( long long, unsigned int);
|
long long __lshrdi3(long long, unsigned int);
|
||||||
long long __moddi3 ( long long, long long);
|
long long __moddi3(long long, long long);
|
||||||
long long __muldi3 ( long long, long long);
|
long long __muldi3(long long, long long);
|
||||||
long long __negdi2 ( long long);
|
long long __negdi2(long long);
|
||||||
long long __one_cmpldi2 ( long long);
|
long long __one_cmpldi2(long long);
|
||||||
long long __subdi3 ( long long, long long);
|
long long __subdi3(long long, long long);
|
||||||
int __ucmpdi2 (unsigned long long, unsigned long long);
|
int __ucmpdi2(unsigned long long, unsigned long long);
|
||||||
unsigned long long __udivdi3 (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);
|
unsigned long long __umoddi3(unsigned long long, unsigned long long);
|
||||||
long long __xordi3 ( long long, long long);
|
long long __xordi3(long long, long long);
|
||||||
|
|
||||||
#ifndef _KERNEL
|
#ifndef _KERNEL
|
||||||
long long __fixdfdi (double);
|
long long __fixdfdi(double);
|
||||||
long long __fixsfdi (float);
|
long long __fixsfdi(float);
|
||||||
unsigned long long __fixunsdfdi (double);
|
unsigned long long __fixunsdfdi(double);
|
||||||
unsigned long long __fixunssfdi (float);
|
unsigned long long __fixunssfdi(float);
|
||||||
double __floatdidf (long long);
|
double __floatdidf(long long);
|
||||||
float __floatdisf (long long);
|
float __floatdisf(long long);
|
||||||
double __floatunsdidf(unsigned long long);
|
double __floatunsdidf(unsigned long long);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
unsigned long long __qdivrem (unsigned long long, unsigned long long,
|
unsigned long long __qdivrem(unsigned long long, unsigned long long,
|
||||||
unsigned long long *);
|
unsigned long long *);
|
||||||
|
|||||||
@@ -41,21 +41,18 @@
|
|||||||
* Shift an (unsigned) long long value left (logical shift left).
|
* Shift an (unsigned) long long value left (logical shift left).
|
||||||
* This is the same as arithmetic shift left!
|
* This is the same as arithmetic shift left!
|
||||||
*/
|
*/
|
||||||
long long
|
long long __lshldi3(long long a, unsigned int shift) {
|
||||||
__lshldi3(long long a, unsigned int shift)
|
union uu aa;
|
||||||
{
|
|
||||||
union uu aa;
|
|
||||||
|
|
||||||
if (shift == 0)
|
if (shift == 0)
|
||||||
return(a);
|
return (a);
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
if (shift >= INT_BITS) {
|
if (shift >= INT_BITS) {
|
||||||
aa.ui[H] = aa.ui[L] << (shift - INT_BITS);
|
aa.ui[H] = aa.ui[L] << (shift - INT_BITS);
|
||||||
aa.ui[L] = 0;
|
aa.ui[L] = 0;
|
||||||
} else {
|
} else {
|
||||||
aa.ui[H] = (aa.ui[H] << shift) |
|
aa.ui[H] = (aa.ui[H] << shift) | (aa.ui[L] >> (INT_BITS - shift));
|
||||||
(aa.ui[L] >> (INT_BITS - shift));
|
aa.ui[L] <<= shift;
|
||||||
aa.ui[L] <<= shift;
|
}
|
||||||
}
|
return (aa.ll);
|
||||||
return (aa.ll);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,21 +40,18 @@
|
|||||||
/*
|
/*
|
||||||
* Shift an (unsigned) long long value right (logical shift right).
|
* Shift an (unsigned) long long value right (logical shift right).
|
||||||
*/
|
*/
|
||||||
long long
|
long long __lshrdi3(long long a, unsigned int shift) {
|
||||||
__lshrdi3(long long a, unsigned int shift)
|
union uu aa;
|
||||||
{
|
|
||||||
union uu aa;
|
|
||||||
|
|
||||||
if (shift == 0)
|
if (shift == 0)
|
||||||
return(a);
|
return (a);
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
if (shift >= INT_BITS) {
|
if (shift >= INT_BITS) {
|
||||||
aa.ui[L] = aa.ui[H] >> (shift - INT_BITS);
|
aa.ui[L] = aa.ui[H] >> (shift - INT_BITS);
|
||||||
aa.ui[H] = 0;
|
aa.ui[H] = 0;
|
||||||
} else {
|
} else {
|
||||||
aa.ui[L] = (aa.ui[L] >> shift) |
|
aa.ui[L] = (aa.ui[L] >> shift) | (aa.ui[H] << (INT_BITS - shift));
|
||||||
(aa.ui[H] << (INT_BITS - shift));
|
aa.ui[H] >>= shift;
|
||||||
aa.ui[H] >>= shift;
|
}
|
||||||
}
|
return (aa.ll);
|
||||||
return (aa.ll);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,21 +42,19 @@
|
|||||||
*
|
*
|
||||||
* XXX we assume a % b < 0 iff a < 0, but this is actually machine-dependent.
|
* XXX we assume a % b < 0 iff a < 0, but this is actually machine-dependent.
|
||||||
*/
|
*/
|
||||||
long long
|
long long __moddi3(long long a, long long b) {
|
||||||
__moddi3(long long a, long long b)
|
unsigned long long ua, ub, ur;
|
||||||
{
|
int neg = 0;
|
||||||
unsigned long long ua, ub, ur;
|
|
||||||
int neg = 0;
|
|
||||||
|
|
||||||
ua = a;
|
ua = a;
|
||||||
ub = b;
|
ub = b;
|
||||||
|
|
||||||
if (a < 0)
|
if (a < 0)
|
||||||
ua = -ua, neg ^= 1;
|
ua = -ua, neg ^= 1;
|
||||||
if (b < 0)
|
if (b < 0)
|
||||||
ub = -ub;
|
ub = -ub;
|
||||||
(void)__qdivrem(ua, ub, &ur);
|
(void)__qdivrem(ua, ub, &ur);
|
||||||
if (neg)
|
if (neg)
|
||||||
ur = -ur;
|
ur = -ur;
|
||||||
return (ur);
|
return (ur);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,67 +96,64 @@
|
|||||||
*/
|
*/
|
||||||
static long long __lmulq(unsigned int, unsigned int);
|
static long long __lmulq(unsigned int, unsigned int);
|
||||||
|
|
||||||
long long
|
long long __muldi3(long long a, long long b) {
|
||||||
__muldi3(long long a, long long b)
|
union uu u, v, low, prod;
|
||||||
{
|
unsigned int high, mid, udiff, vdiff;
|
||||||
union uu u, v, low, prod;
|
int negall, negmid;
|
||||||
unsigned int high, mid, udiff, vdiff;
|
#define u1 u.ui[H]
|
||||||
int negall, negmid;
|
#define u0 u.ui[L]
|
||||||
#define u1 u.ui[H]
|
#define v1 v.ui[H]
|
||||||
#define u0 u.ui[L]
|
#define v0 v.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,
|
* Get u and v such that u, v >= 0. When this is finished,
|
||||||
* u1, u0, v1, and v0 will be directly accessible through the
|
* u1, u0, v1, and v0 will be directly accessible through the
|
||||||
* int fields.
|
* int fields.
|
||||||
*/
|
*/
|
||||||
if (a >= 0)
|
if (a >= 0)
|
||||||
u.ll = a, negall = 0;
|
u.ll = a, negall = 0;
|
||||||
else
|
else
|
||||||
u.ll = -a, negall = 1;
|
u.ll = -a, negall = 1;
|
||||||
if (b >= 0)
|
if (b >= 0)
|
||||||
v.ll = b;
|
v.ll = b;
|
||||||
else
|
else
|
||||||
v.ll = -b, negall ^= 1;
|
v.ll = -b, negall ^= 1;
|
||||||
|
|
||||||
if (u1 == 0 && v1 == 0) {
|
if (u1 == 0 && v1 == 0) {
|
||||||
/*
|
/*
|
||||||
* An (I hope) important optimization occurs when u1 and v1
|
* An (I hope) important optimization occurs when u1 and v1
|
||||||
* are both 0. This should be common since most numbers
|
* are both 0. This should be common since most numbers
|
||||||
* are small. Here the product is just u0*v0.
|
* are small. Here the product is just u0*v0.
|
||||||
*/
|
*/
|
||||||
prod.ll = __lmulq(u0, v0);
|
prod.ll = __lmulq(u0, v0);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Compute the three intermediate products, remembering
|
* Compute the three intermediate products, remembering
|
||||||
* whether the middle term is negative. We can discard
|
* whether the middle term is negative. We can discard
|
||||||
* any upper bits in high and mid, so we can use native
|
* any upper bits in high and mid, so we can use native
|
||||||
* unsigned int * unsigned int => unsigned int arithmetic.
|
* unsigned int * unsigned int => unsigned int arithmetic.
|
||||||
*/
|
*/
|
||||||
low.ll = __lmulq(u0, v0);
|
low.ll = __lmulq(u0, v0);
|
||||||
|
|
||||||
if (u1 >= u0)
|
if (u1 >= u0)
|
||||||
negmid = 0, udiff = u1 - u0;
|
negmid = 0, udiff = u1 - u0;
|
||||||
else
|
else
|
||||||
negmid = 1, udiff = u0 - u1;
|
negmid = 1, udiff = u0 - u1;
|
||||||
if (v0 >= v1)
|
if (v0 >= v1)
|
||||||
vdiff = v0 - v1;
|
vdiff = v0 - v1;
|
||||||
else
|
else
|
||||||
vdiff = v1 - v0, negmid ^= 1;
|
vdiff = v1 - v0, negmid ^= 1;
|
||||||
mid = udiff * vdiff;
|
mid = udiff * vdiff;
|
||||||
|
|
||||||
high = u1 * v1;
|
high = u1 * v1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assemble the final product.
|
* Assemble the final product.
|
||||||
*/
|
*/
|
||||||
prod.ui[H] = high + (negmid ? -mid : mid) + low.ui[L] +
|
prod.ui[H] = high + (negmid ? -mid : mid) + low.ui[L] + low.ui[H];
|
||||||
low.ui[H];
|
prod.ui[L] = low.ui[L];
|
||||||
prod.ui[L] = low.ui[L];
|
}
|
||||||
}
|
return (negall ? -prod.ll : prod.ll);
|
||||||
return (negall ? -prod.ll : prod.ll);
|
|
||||||
#undef u1
|
#undef u1
|
||||||
#undef u0
|
#undef u0
|
||||||
#undef v1
|
#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.
|
* splits into high and low ints as HHALF(l) and LHUP(l) respectively.
|
||||||
*/
|
*/
|
||||||
static long long
|
static long long __lmulq(unsigned int u, unsigned int v) {
|
||||||
__lmulq(unsigned int u, unsigned int v)
|
unsigned int u1, u0, v1, v0, udiff, vdiff, high, mid, low;
|
||||||
{
|
unsigned int prodh, prodl, was;
|
||||||
unsigned int u1, u0, v1, v0, udiff, vdiff, high, mid, low;
|
union uu prod;
|
||||||
unsigned int prodh, prodl, was;
|
int neg;
|
||||||
union uu prod;
|
|
||||||
int neg;
|
|
||||||
|
|
||||||
u1 = HHALF(u);
|
u1 = HHALF(u);
|
||||||
u0 = LHALF(u);
|
u0 = LHALF(u);
|
||||||
v1 = HHALF(v);
|
v1 = HHALF(v);
|
||||||
v0 = LHALF(v);
|
v0 = LHALF(v);
|
||||||
|
|
||||||
low = u0 * v0;
|
low = u0 * v0;
|
||||||
|
|
||||||
/* This is the same small-number optimization as before. */
|
/* This is the same small-number optimization as before. */
|
||||||
if (u1 == 0 && v1 == 0)
|
if (u1 == 0 && v1 == 0)
|
||||||
return (low);
|
return (low);
|
||||||
|
|
||||||
if (u1 >= u0)
|
if (u1 >= u0)
|
||||||
udiff = u1 - u0, neg = 0;
|
udiff = u1 - u0, neg = 0;
|
||||||
else
|
else
|
||||||
udiff = u0 - u1, neg = 1;
|
udiff = u0 - u1, neg = 1;
|
||||||
if (v0 >= v1)
|
if (v0 >= v1)
|
||||||
vdiff = v0 - v1;
|
vdiff = v0 - v1;
|
||||||
else
|
else
|
||||||
vdiff = v1 - v0, neg ^= 1;
|
vdiff = v1 - v0, neg ^= 1;
|
||||||
mid = udiff * vdiff;
|
mid = udiff * vdiff;
|
||||||
|
|
||||||
high = u1 * v1;
|
high = u1 * v1;
|
||||||
|
|
||||||
/* prod = (high << 2N) + (high << N); */
|
/* prod = (high << 2N) + (high << N); */
|
||||||
prodh = high + HHALF(high);
|
prodh = high + HHALF(high);
|
||||||
prodl = LHUP(high);
|
prodl = LHUP(high);
|
||||||
|
|
||||||
/* if (neg) prod -= mid << N; else prod += mid << N; */
|
/* if (neg) prod -= mid << N; else prod += mid << N; */
|
||||||
if (neg) {
|
if (neg) {
|
||||||
was = prodl;
|
was = prodl;
|
||||||
prodl -= LHUP(mid);
|
prodl -= LHUP(mid);
|
||||||
prodh -= HHALF(mid) + (prodl > was);
|
prodh -= HHALF(mid) + (prodl > was);
|
||||||
} else {
|
} else {
|
||||||
was = prodl;
|
was = prodl;
|
||||||
prodl += LHUP(mid);
|
prodl += LHUP(mid);
|
||||||
prodh += HHALF(mid) + (prodl < was);
|
prodh += HHALF(mid) + (prodl < was);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prod += low << N */
|
/* prod += low << N */
|
||||||
was = prodl;
|
was = prodl;
|
||||||
prodl += LHUP(low);
|
prodl += LHUP(low);
|
||||||
prodh += HHALF(low) + (prodl < was);
|
prodh += HHALF(low) + (prodl < was);
|
||||||
/* ... + low; */
|
/* ... + low; */
|
||||||
if ((prodl += low) < low)
|
if ((prodl += low) < low)
|
||||||
prodh++;
|
prodh++;
|
||||||
|
|
||||||
/* return 4N-bit product */
|
/* return 4N-bit product */
|
||||||
prod.ui[H] = prodh;
|
prod.ui[H] = prodh;
|
||||||
prod.ui[L] = prodl;
|
prod.ui[L] = prodl;
|
||||||
return (prod.ll);
|
return (prod.ll);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,13 +40,11 @@
|
|||||||
/*
|
/*
|
||||||
* Return -a (or, equivalently, 0 - a), in long long. See subdi3.c.
|
* Return -a (or, equivalently, 0 - a), in long long. See subdi3.c.
|
||||||
*/
|
*/
|
||||||
long long
|
long long __negdi2(long long a) {
|
||||||
__negdi2(long long a)
|
union uu aa, res;
|
||||||
{
|
|
||||||
union uu aa, res;
|
|
||||||
|
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
res.ui[L] = -aa.ui[L];
|
res.ui[L] = -aa.ui[L];
|
||||||
res.ui[H] = -aa.ui[H] - (res.ui[L] > 0);
|
res.ui[H] = -aa.ui[H] - (res.ui[L] > 0);
|
||||||
return (res.ll);
|
return (res.ll);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,13 +41,11 @@
|
|||||||
* Return ~a. For some reason gcc calls this `one's complement' rather
|
* Return ~a. For some reason gcc calls this `one's complement' rather
|
||||||
* than `not'.
|
* than `not'.
|
||||||
*/
|
*/
|
||||||
long long
|
long long __one_cmpldi2(long long a) {
|
||||||
__one_cmpldi2(long long a)
|
union uu aa;
|
||||||
{
|
|
||||||
union uu aa;
|
|
||||||
|
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
aa.ui[0] = ~aa.ui[0];
|
aa.ui[0] = ~aa.ui[0];
|
||||||
aa.ui[1] = ~aa.ui[1];
|
aa.ui[1] = ~aa.ui[1];
|
||||||
return (aa.ll);
|
return (aa.ll);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,10 +42,10 @@
|
|||||||
|
|
||||||
#include "longlong.h"
|
#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. */
|
/* 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 */
|
/* select a type for digits in base B: use unsigned short if they fit */
|
||||||
#if UINT_MAX == 0xffffffffU && USHRT_MAX >= 0xffff
|
#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
|
* length dividend and divisor are 4 `digits' in this base (they are
|
||||||
* shorter if they have leading zeros).
|
* shorter if they have leading zeros).
|
||||||
*/
|
*/
|
||||||
unsigned long long
|
unsigned long long __qdivrem(unsigned long long ull, unsigned long long vll,
|
||||||
__qdivrem(unsigned long long ull, unsigned long long vll,
|
unsigned long long *arq) {
|
||||||
unsigned long long *arq)
|
union uu tmp;
|
||||||
{
|
digit *u, *v, *q;
|
||||||
union uu tmp;
|
digit v1, v2;
|
||||||
digit *u, *v, *q;
|
unsigned int qhat, rhat, t;
|
||||||
digit v1, v2;
|
int m, n, d, j, i;
|
||||||
unsigned int qhat, rhat, t;
|
digit uspace[5], vspace[5], qspace[5];
|
||||||
int m, n, d, j, i;
|
|
||||||
digit uspace[5], vspace[5], qspace[5];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Take care of special cases: divide by zero, and u < v.
|
* Take care of special cases: divide by zero, and u < v.
|
||||||
*/
|
*/
|
||||||
if (vll == 0) {
|
if (vll == 0) {
|
||||||
/* divide by zero. */
|
/* divide by zero. */
|
||||||
static volatile const unsigned int zero = 0;
|
static volatile const unsigned int zero = 0;
|
||||||
|
|
||||||
tmp.ui[H] = tmp.ui[L] = 1 / zero;
|
tmp.ui[H] = tmp.ui[L] = 1 / zero;
|
||||||
if (arq)
|
if (arq)
|
||||||
*arq = ull;
|
*arq = ull;
|
||||||
return (tmp.ll);
|
return (tmp.ll);
|
||||||
}
|
}
|
||||||
if (ull < vll) {
|
if (ull < vll) {
|
||||||
if (arq)
|
if (arq)
|
||||||
*arq = ull;
|
*arq = ull;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
u = &uspace[0];
|
u = &uspace[0];
|
||||||
v = &vspace[0];
|
v = &vspace[0];
|
||||||
q = &qspace[0];
|
q = &qspace[0];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Break dividend and divisor into digits in base B, then
|
* Break dividend and divisor into digits in base B, then
|
||||||
* count leading zeros to determine m and n. When done, we
|
* count leading zeros to determine m and n. When done, we
|
||||||
* will have:
|
* will have:
|
||||||
* u = (u[1]u[2]...u[m+n]) sub B
|
* u = (u[1]u[2]...u[m+n]) sub B
|
||||||
* v = (v[1]v[2]...v[n]) sub B
|
* v = (v[1]v[2]...v[n]) sub B
|
||||||
* v[1] != 0
|
* v[1] != 0
|
||||||
* 1 < n <= 4 (if n = 1, we use a different division algorithm)
|
* 1 < n <= 4 (if n = 1, we use a different division algorithm)
|
||||||
* m >= 0 (otherwise u < v, which we already checked)
|
* m >= 0 (otherwise u < v, which we already checked)
|
||||||
* m + n = 4
|
* m + n = 4
|
||||||
* and thus
|
* and thus
|
||||||
* m = 4 - n <= 2
|
* m = 4 - n <= 2
|
||||||
*/
|
*/
|
||||||
tmp.ull = ull;
|
tmp.ull = ull;
|
||||||
u[0] = 0;
|
u[0] = 0;
|
||||||
u[1] = (digit)HHALF(tmp.ui[H]);
|
u[1] = (digit)HHALF(tmp.ui[H]);
|
||||||
u[2] = (digit)LHALF(tmp.ui[H]);
|
u[2] = (digit)LHALF(tmp.ui[H]);
|
||||||
u[3] = (digit)HHALF(tmp.ui[L]);
|
u[3] = (digit)HHALF(tmp.ui[L]);
|
||||||
u[4] = (digit)LHALF(tmp.ui[L]);
|
u[4] = (digit)LHALF(tmp.ui[L]);
|
||||||
tmp.ull = vll;
|
tmp.ull = vll;
|
||||||
v[1] = (digit)HHALF(tmp.ui[H]);
|
v[1] = (digit)HHALF(tmp.ui[H]);
|
||||||
v[2] = (digit)LHALF(tmp.ui[H]);
|
v[2] = (digit)LHALF(tmp.ui[H]);
|
||||||
v[3] = (digit)HHALF(tmp.ui[L]);
|
v[3] = (digit)HHALF(tmp.ui[L]);
|
||||||
v[4] = (digit)LHALF(tmp.ui[L]);
|
v[4] = (digit)LHALF(tmp.ui[L]);
|
||||||
for (n = 4; v[1] == 0; v++) {
|
for (n = 4; v[1] == 0; v++) {
|
||||||
if (--n == 1) {
|
if (--n == 1) {
|
||||||
unsigned int rbj; /* r*B+u[j] (not root boy jim) */
|
unsigned int rbj; /* r*B+u[j] (not root boy jim) */
|
||||||
digit q1, q2, q3, q4;
|
digit q1, q2, q3, q4;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Change of plan, per exercise 16.
|
* Change of plan, per exercise 16.
|
||||||
* r = 0;
|
* r = 0;
|
||||||
* for j = 1..4:
|
* for j = 1..4:
|
||||||
* q[j] = floor((r*B + u[j]) / v),
|
* q[j] = floor((r*B + u[j]) / v),
|
||||||
* r = (r*B + u[j]) % v;
|
* r = (r*B + u[j]) % v;
|
||||||
* We unroll this completely here.
|
* We unroll this completely here.
|
||||||
*/
|
*/
|
||||||
t = v[2]; /* nonzero, by definition */
|
t = v[2]; /* nonzero, by definition */
|
||||||
q1 = (digit)(u[1] / t);
|
q1 = (digit)(u[1] / t);
|
||||||
rbj = COMBINE(u[1] % t, u[2]);
|
rbj = COMBINE(u[1] % t, u[2]);
|
||||||
q2 = (digit)(rbj / t);
|
q2 = (digit)(rbj / t);
|
||||||
rbj = COMBINE(rbj % t, u[3]);
|
rbj = COMBINE(rbj % t, u[3]);
|
||||||
q3 = (digit)(rbj / t);
|
q3 = (digit)(rbj / t);
|
||||||
rbj = COMBINE(rbj % t, u[4]);
|
rbj = COMBINE(rbj % t, u[4]);
|
||||||
q4 = (digit)(rbj / t);
|
q4 = (digit)(rbj / t);
|
||||||
if (arq)
|
if (arq)
|
||||||
*arq = rbj % t;
|
*arq = rbj % t;
|
||||||
tmp.ui[H] = COMBINE(q1, q2);
|
tmp.ui[H] = COMBINE(q1, q2);
|
||||||
tmp.ui[L] = COMBINE(q3, q4);
|
tmp.ui[L] = COMBINE(q3, q4);
|
||||||
return (tmp.ll);
|
return (tmp.ll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* By adjusting q once we determine m, we can guarantee that
|
* By adjusting q once we determine m, we can guarantee that
|
||||||
* there is a complete four-digit quotient at &qspace[1] when
|
* there is a complete four-digit quotient at &qspace[1] when
|
||||||
* we finally stop.
|
* we finally stop.
|
||||||
*/
|
*/
|
||||||
for (m = 4 - n; u[1] == 0; u++)
|
for (m = 4 - n; u[1] == 0; u++)
|
||||||
m--;
|
m--;
|
||||||
for (i = 4 - m; --i >= 0;)
|
for (i = 4 - m; --i >= 0;)
|
||||||
q[i] = 0;
|
q[i] = 0;
|
||||||
q += 4 - m;
|
q += 4 - m;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here we run Program D, translated from MIX to C and acquiring
|
* Here we run Program D, translated from MIX to C and acquiring
|
||||||
* a few minor changes.
|
* a few minor changes.
|
||||||
*
|
*
|
||||||
* D1: choose multiplier 1 << d to ensure v[1] >= B/2.
|
* D1: choose multiplier 1 << d to ensure v[1] >= B/2.
|
||||||
*/
|
*/
|
||||||
d = 0;
|
d = 0;
|
||||||
for (t = v[1]; t < B / 2; t <<= 1)
|
for (t = v[1]; t < B / 2; t <<= 1)
|
||||||
d++;
|
d++;
|
||||||
if (d > 0) {
|
if (d > 0) {
|
||||||
shl(&u[0], m + n, d); /* u <<= d */
|
shl(&u[0], m + n, d); /* u <<= d */
|
||||||
shl(&v[1], n - 1, d); /* v <<= d */
|
shl(&v[1], n - 1, d); /* v <<= d */
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* D2: j = 0.
|
* D2: j = 0.
|
||||||
*/
|
*/
|
||||||
j = 0;
|
j = 0;
|
||||||
v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
|
v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
|
||||||
v2 = v[2]; /* for D3 */
|
v2 = v[2]; /* for D3 */
|
||||||
do {
|
do {
|
||||||
digit uj0, uj1, uj2;
|
digit uj0, uj1, uj2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* D3: Calculate qhat (\^q, in TeX notation).
|
* D3: Calculate qhat (\^q, in TeX notation).
|
||||||
* Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
|
* 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].
|
* let rhat = (u[j]*B + u[j+1]) mod v[1].
|
||||||
* While rhat < B and v[2]*qhat > rhat*B+u[j+2],
|
* While rhat < B and v[2]*qhat > rhat*B+u[j+2],
|
||||||
* decrement qhat and increase rhat correspondingly.
|
* decrement qhat and increase rhat correspondingly.
|
||||||
* Note that if rhat >= B, v[2]*qhat < rhat*B.
|
* Note that if rhat >= B, v[2]*qhat < rhat*B.
|
||||||
*/
|
*/
|
||||||
uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
|
uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
|
||||||
uj1 = u[j + 1]; /* for D3 only */
|
uj1 = u[j + 1]; /* for D3 only */
|
||||||
uj2 = u[j + 2]; /* for D3 only */
|
uj2 = u[j + 2]; /* for D3 only */
|
||||||
if (uj0 == v1) {
|
if (uj0 == v1) {
|
||||||
qhat = B;
|
qhat = B;
|
||||||
rhat = uj1;
|
rhat = uj1;
|
||||||
goto qhat_too_big;
|
goto qhat_too_big;
|
||||||
} else {
|
} else {
|
||||||
unsigned int nn = COMBINE(uj0, uj1);
|
unsigned int nn = COMBINE(uj0, uj1);
|
||||||
qhat = nn / v1;
|
qhat = nn / v1;
|
||||||
rhat = nn % v1;
|
rhat = nn % v1;
|
||||||
}
|
}
|
||||||
while (v2 * qhat > COMBINE(rhat, uj2)) {
|
while (v2 * qhat > COMBINE(rhat, uj2)) {
|
||||||
qhat_too_big:
|
qhat_too_big:
|
||||||
qhat--;
|
qhat--;
|
||||||
if ((rhat += v1) >= B)
|
if ((rhat += v1) >= B)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* D4: Multiply and subtract.
|
* D4: Multiply and subtract.
|
||||||
* The variable `t' holds any borrows across the loop.
|
* The variable `t' holds any borrows across the loop.
|
||||||
* We split this up so that we do not require v[0] = 0,
|
* We split this up so that we do not require v[0] = 0,
|
||||||
* and to eliminate a final special case.
|
* and to eliminate a final special case.
|
||||||
*/
|
*/
|
||||||
for (t = 0, i = n; i > 0; i--) {
|
for (t = 0, i = n; i > 0; i--) {
|
||||||
t = u[i + j] - v[i] * qhat - t;
|
t = u[i + j] - v[i] * qhat - t;
|
||||||
u[i + j] = (digit)LHALF(t);
|
u[i + j] = (digit)LHALF(t);
|
||||||
t = (B - HHALF(t)) & (B - 1);
|
t = (B - HHALF(t)) & (B - 1);
|
||||||
}
|
}
|
||||||
t = u[j] - t;
|
t = u[j] - t;
|
||||||
u[j] = (digit)LHALF(t);
|
u[j] = (digit)LHALF(t);
|
||||||
/*
|
/*
|
||||||
* D5: test remainder.
|
* D5: test remainder.
|
||||||
* There is a borrow if and only if HHALF(t) is nonzero;
|
* There is a borrow if and only if HHALF(t) is nonzero;
|
||||||
* in that (rare) case, qhat was too large (by exactly 1).
|
* in that (rare) case, qhat was too large (by exactly 1).
|
||||||
* Fix it by adding v[1..n] to u[j..j+n].
|
* Fix it by adding v[1..n] to u[j..j+n].
|
||||||
*/
|
*/
|
||||||
if (HHALF(t)) {
|
if (HHALF(t)) {
|
||||||
qhat--;
|
qhat--;
|
||||||
for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
|
for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
|
||||||
t += u[i + j] + v[i];
|
t += u[i + j] + v[i];
|
||||||
u[i + j] = (digit)LHALF(t);
|
u[i + j] = (digit)LHALF(t);
|
||||||
t = HHALF(t);
|
t = HHALF(t);
|
||||||
}
|
}
|
||||||
u[j] = (digit)LHALF(u[j] + t);
|
u[j] = (digit)LHALF(u[j] + t);
|
||||||
}
|
}
|
||||||
q[j] = (digit)qhat;
|
q[j] = (digit)qhat;
|
||||||
} while (++j <= m); /* D7: loop on j. */
|
} while (++j <= m); /* D7: loop on j. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If caller wants the remainder, we have to calculate it as
|
* 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..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).
|
* u[m+1..m+n], but we may need more source digits).
|
||||||
*/
|
*/
|
||||||
if (arq) {
|
if (arq) {
|
||||||
if (d) {
|
if (d) {
|
||||||
for (i = m + n; i > m; --i)
|
for (i = m + n; i > m; --i)
|
||||||
u[i] = (digit)(((unsigned int)u[i] >> d) |
|
u[i] = (digit)(((unsigned int)u[i] >> d) |
|
||||||
LHALF((unsigned int)u[i - 1] <<
|
LHALF((unsigned int)u[i - 1] << (HALF_BITS - d)));
|
||||||
(HALF_BITS - d)));
|
u[i] = 0;
|
||||||
u[i] = 0;
|
}
|
||||||
}
|
tmp.ui[H] = COMBINE(uspace[1], uspace[2]);
|
||||||
tmp.ui[H] = COMBINE(uspace[1], uspace[2]);
|
tmp.ui[L] = COMBINE(uspace[3], uspace[4]);
|
||||||
tmp.ui[L] = COMBINE(uspace[3], uspace[4]);
|
*arq = tmp.ll;
|
||||||
*arq = tmp.ll;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tmp.ui[H] = COMBINE(qspace[1], qspace[2]);
|
tmp.ui[H] = COMBINE(qspace[1], qspace[2]);
|
||||||
tmp.ui[L] = COMBINE(qspace[3], qspace[4]);
|
tmp.ui[L] = COMBINE(qspace[3], qspace[4]);
|
||||||
return (tmp.ll);
|
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).
|
* `fall out' the left (there never will be any such anyway).
|
||||||
* We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
|
* We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
|
||||||
*/
|
*/
|
||||||
static void
|
static void shl(digit *p, int len, int sh) {
|
||||||
shl(digit *p, int len, int sh)
|
int i;
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
p[i] = (digit)(LHALF((unsigned int)p[i] << sh) |
|
p[i] = (digit)(LHALF((unsigned int)p[i] << sh) |
|
||||||
((unsigned int)p[i + 1] >> (HALF_BITS - sh)));
|
((unsigned int)p[i + 1] >> (HALF_BITS - sh)));
|
||||||
p[i] = (digit)(LHALF((unsigned int)p[i] << 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
|
* carry from a single unsigned int difference x-y occurs if and only
|
||||||
* if (x-y) > x.
|
* if (x-y) > x.
|
||||||
*/
|
*/
|
||||||
long long
|
long long __subdi3(long long a, long long b) {
|
||||||
__subdi3(long long a, long long b)
|
union uu aa, bb, diff;
|
||||||
{
|
|
||||||
union uu aa, bb, diff;
|
|
||||||
|
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
bb.ll = b;
|
bb.ll = b;
|
||||||
diff.ui[L] = aa.ui[L] - bb.ui[L];
|
diff.ui[L] = aa.ui[L] - bb.ui[L];
|
||||||
diff.ui[H] = aa.ui[H] - bb.ui[H] - (diff.ui[L] > aa.ui[L]);
|
diff.ui[H] = aa.ui[H] - bb.ui[H] - (diff.ui[L] > aa.ui[L]);
|
||||||
return (diff.ll);
|
return (diff.ll);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,13 +41,14 @@
|
|||||||
* Return 0, 1, or 2 as a <, =, > b respectively.
|
* Return 0, 1, or 2 as a <, =, > b respectively.
|
||||||
* Neither a nor b are considered signed.
|
* Neither a nor b are considered signed.
|
||||||
*/
|
*/
|
||||||
int
|
int __ucmpdi2(unsigned long long a, unsigned long long b) {
|
||||||
__ucmpdi2(unsigned long long a, unsigned long long b)
|
union uu aa, bb;
|
||||||
{
|
|
||||||
union uu aa, bb;
|
|
||||||
|
|
||||||
aa.ull = a;
|
aa.ull = a;
|
||||||
bb.ull = b;
|
bb.ull = b;
|
||||||
return (aa.ui[H] < bb.ui[H] ? 0 : aa.ui[H] > bb.ui[H] ? 2 :
|
return (aa.ui[H] < bb.ui[H] ? 0
|
||||||
aa.ui[L] < bb.ui[L] ? 0 : aa.ui[L] > bb.ui[L] ? 2 : 1);
|
: 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.
|
* Divide two unsigned long longs.
|
||||||
*/
|
*/
|
||||||
unsigned long long
|
unsigned long long __udivdi3(unsigned long long a, unsigned long long b) {
|
||||||
__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.
|
* Return remainder after dividing two unsigned long longs.
|
||||||
*/
|
*/
|
||||||
unsigned long long
|
unsigned long long __umoddi3(unsigned long long a, unsigned long long b) {
|
||||||
__umoddi3(unsigned long long a, unsigned long long b)
|
unsigned long long r;
|
||||||
{
|
|
||||||
unsigned long long r;
|
|
||||||
|
|
||||||
(void)__qdivrem(a, b, &r);
|
(void)__qdivrem(a, b, &r);
|
||||||
return (r);
|
return (r);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,14 +40,12 @@
|
|||||||
/*
|
/*
|
||||||
* Return a ^ b, in long long.
|
* Return a ^ b, in long long.
|
||||||
*/
|
*/
|
||||||
long long
|
long long __xordi3(long long a, long long b) {
|
||||||
__xordi3(long long a, long long b)
|
union uu aa, bb;
|
||||||
{
|
|
||||||
union uu aa, bb;
|
|
||||||
|
|
||||||
aa.ll = a;
|
aa.ll = a;
|
||||||
bb.ll = b;
|
bb.ll = b;
|
||||||
aa.ui[0] ^= bb.ui[0];
|
aa.ui[0] ^= bb.ui[0];
|
||||||
aa.ui[1] ^= bb.ui[1];
|
aa.ui[1] ^= bb.ui[1];
|
||||||
return (aa.ll);
|
return (aa.ll);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,6 @@
|
|||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do we want to support "long long" types with %lld?
|
* 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.
|
* Define a type that holds the longest signed integer we intend to support.
|
||||||
*/
|
*/
|
||||||
#ifdef USE_LONGLONG
|
#ifdef USE_LONGLONG
|
||||||
#define INTTYPE long long
|
#define INTTYPE long long
|
||||||
#else
|
#else
|
||||||
#define INTTYPE long
|
#define INTTYPE long
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Space for a long long in base 8, plus a NUL, plus one
|
* Space for a long long in base 8, plus a NUL, plus one
|
||||||
* character extra for slop.
|
* character extra for slop.
|
||||||
@@ -87,52 +85,52 @@
|
|||||||
* Structure holding the state for printf.
|
* Structure holding the state for printf.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* Callback for sending printed string data */
|
/* Callback for sending printed string data */
|
||||||
void (*sendfunc)(void *clientdata, const char *str, size_t len);
|
void (*sendfunc)(void *clientdata, const char *str, size_t len);
|
||||||
void *clientdata;
|
void *clientdata;
|
||||||
|
|
||||||
/* The varargs argument pointer */
|
/* The varargs argument pointer */
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
/* Total count of characters printed */
|
/* Total count of characters printed */
|
||||||
int charcount;
|
int charcount;
|
||||||
|
|
||||||
/* Flag that's true if we are currently looking in a %-format */
|
/* Flag that's true if we are currently looking in a %-format */
|
||||||
int in_pct;
|
int in_pct;
|
||||||
|
|
||||||
/* Size of the integer argument to retrieve */
|
/* Size of the integer argument to retrieve */
|
||||||
enum {
|
enum {
|
||||||
INTSZ,
|
INTSZ,
|
||||||
LONGSZ,
|
LONGSZ,
|
||||||
#ifdef USE_LONGLONG
|
#ifdef USE_LONGLONG
|
||||||
LLONGSZ,
|
LLONGSZ,
|
||||||
#endif
|
#endif
|
||||||
SIZETSZ,
|
SIZETSZ,
|
||||||
} size;
|
} size;
|
||||||
|
|
||||||
/* The value of the integer argument retrieved */
|
/* The value of the integer argument retrieved */
|
||||||
unsigned INTTYPE num;
|
unsigned INTTYPE num;
|
||||||
|
|
||||||
/* Sign of the integer argument (0 = positive; -1 = negative) */
|
/* Sign of the integer argument (0 = positive; -1 = negative) */
|
||||||
int sign;
|
int sign;
|
||||||
|
|
||||||
/* Field width (number of spaces) */
|
/* Field width (number of spaces) */
|
||||||
int spacing;
|
int spacing;
|
||||||
|
|
||||||
/* Flag: align to left in field instead of right */
|
/* Flag: align to left in field instead of right */
|
||||||
int rightspc;
|
int rightspc;
|
||||||
|
|
||||||
/* Character to pad to field size with (space or 0) */
|
/* Character to pad to field size with (space or 0) */
|
||||||
int fillchar;
|
int fillchar;
|
||||||
|
|
||||||
/* Number base to print the integer argument in (8, 10, 16) */
|
/* Number base to print the integer argument in (8, 10, 16) */
|
||||||
int base;
|
int base;
|
||||||
|
|
||||||
/* Flag: if set, print 0x before hex and 0 before octal numbers */
|
/* Flag: if set, print 0x before hex and 0 before octal numbers */
|
||||||
int baseprefix;
|
int baseprefix;
|
||||||
|
|
||||||
/* Flag: alternative output format selected with %#... */
|
/* Flag: alternative output format selected with %#... */
|
||||||
int altformat;
|
int altformat;
|
||||||
} PF;
|
} PF;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -141,31 +139,25 @@ typedef struct {
|
|||||||
* We count the total length we send out so we can return it from __vprintf,
|
* 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.
|
* since that's what most printf-like functions want to return.
|
||||||
*/
|
*/
|
||||||
static
|
static void __pf_print(PF *pf, const char *txt, size_t len) {
|
||||||
void
|
pf->sendfunc(pf->clientdata, txt, len);
|
||||||
__pf_print(PF *pf, const char *txt, size_t len)
|
pf->charcount += len;
|
||||||
{
|
|
||||||
pf->sendfunc(pf->clientdata, txt, len);
|
|
||||||
pf->charcount += len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset the state for the next %-field.
|
* Reset the state for the next %-field.
|
||||||
*/
|
*/
|
||||||
static
|
static void __pf_endfield(PF *pf) {
|
||||||
void
|
pf->in_pct = 0;
|
||||||
__pf_endfield(PF *pf)
|
pf->size = INTSZ;
|
||||||
{
|
pf->num = 0;
|
||||||
pf->in_pct = 0;
|
pf->sign = 0;
|
||||||
pf->size = INTSZ;
|
pf->spacing = 0;
|
||||||
pf->num = 0;
|
pf->rightspc = 0;
|
||||||
pf->sign = 0;
|
pf->fillchar = ' ';
|
||||||
pf->spacing = 0;
|
pf->base = 0;
|
||||||
pf->rightspc = 0;
|
pf->baseprefix = 0;
|
||||||
pf->fillchar = ' ';
|
pf->altformat = 0;
|
||||||
pf->base = 0;
|
|
||||||
pf->baseprefix = 0;
|
|
||||||
pf->altformat = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -177,59 +169,54 @@ __pf_endfield(PF *pf)
|
|||||||
* 0-9 field width
|
* 0-9 field width
|
||||||
* leading 0 pad with zeros instead of spaces
|
* leading 0 pad with zeros instead of spaces
|
||||||
*/
|
*/
|
||||||
static
|
static void __pf_modifier(PF *pf, int ch) {
|
||||||
void
|
switch (ch) {
|
||||||
__pf_modifier(PF *pf, int ch)
|
case '#':
|
||||||
{
|
pf->altformat = 1;
|
||||||
switch (ch) {
|
break;
|
||||||
case '#':
|
case '-':
|
||||||
pf->altformat = 1;
|
pf->rightspc = 1;
|
||||||
break;
|
break;
|
||||||
case '-':
|
case 'l':
|
||||||
pf->rightspc = 1;
|
if (pf->size == LONGSZ) {
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
if (pf->size==LONGSZ) {
|
|
||||||
#ifdef USE_LONGLONG
|
#ifdef USE_LONGLONG
|
||||||
pf->size = LLONGSZ;
|
pf->size = LLONGSZ;
|
||||||
#endif
|
#endif
|
||||||
}
|
} else {
|
||||||
else {
|
pf->size = LONGSZ;
|
||||||
pf->size = LONGSZ;
|
}
|
||||||
}
|
break;
|
||||||
break;
|
case 'z':
|
||||||
case 'z':
|
pf->size = SIZETSZ;
|
||||||
pf->size = SIZETSZ;
|
break;
|
||||||
break;
|
case '0':
|
||||||
case '0':
|
if (pf->spacing > 0) {
|
||||||
if (pf->spacing>0) {
|
/*
|
||||||
/*
|
* Already seen some digits; this is part of the
|
||||||
* Already seen some digits; this is part of the
|
* field size.
|
||||||
* field size.
|
*/
|
||||||
*/
|
pf->spacing = pf->spacing * 10;
|
||||||
pf->spacing = pf->spacing*10;
|
} else {
|
||||||
}
|
/*
|
||||||
else {
|
* Leading zero; set the padding character to 0.
|
||||||
/*
|
*/
|
||||||
* Leading zero; set the padding character to 0.
|
pf->fillchar = '0';
|
||||||
*/
|
}
|
||||||
pf->fillchar = '0';
|
break;
|
||||||
}
|
default:
|
||||||
break;
|
/*
|
||||||
default:
|
* Invalid characters should be filtered out by a
|
||||||
/*
|
* higher-level function, so if this assert goes off
|
||||||
* Invalid characters should be filtered out by a
|
* it's our fault.
|
||||||
* higher-level function, so if this assert goes off
|
*/
|
||||||
* it's our fault.
|
assert(ch > '0' && ch <= '9');
|
||||||
*/
|
|
||||||
assert(ch>'0' && ch<='9');
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Got a digit; accumulate the field size.
|
* Got a digit; accumulate the field size.
|
||||||
*/
|
*/
|
||||||
pf->spacing = pf->spacing*10 + (ch-'0');
|
pf->spacing = pf->spacing * 10 + (ch - '0');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -237,77 +224,71 @@ __pf_modifier(PF *pf, int ch)
|
|||||||
* in pf->num, according to the size recorded in pf->size and using
|
* in pf->num, according to the size recorded in pf->size and using
|
||||||
* the numeric type specified by ch.
|
* the numeric type specified by ch.
|
||||||
*/
|
*/
|
||||||
static
|
static void __pf_getnum(PF *pf, int ch) {
|
||||||
void
|
if (ch == 'p') {
|
||||||
__pf_getnum(PF *pf, int ch)
|
/*
|
||||||
{
|
* Pointer.
|
||||||
if (ch=='p') {
|
*
|
||||||
/*
|
* uintptr_t is a C99 standard type that's an unsigned
|
||||||
* Pointer.
|
* integer the same size as a pointer.
|
||||||
*
|
*/
|
||||||
* uintptr_t is a C99 standard type that's an unsigned
|
pf->num = (uintptr_t)va_arg(pf->ap, void *);
|
||||||
* integer the same size as a pointer.
|
} else if (ch == 'd') {
|
||||||
*/
|
/* signed integer */
|
||||||
pf->num = (uintptr_t) va_arg(pf->ap, void *);
|
INTTYPE signednum = 0;
|
||||||
}
|
switch (pf->size) {
|
||||||
else if (ch=='d') {
|
case INTSZ:
|
||||||
/* signed integer */
|
/* %d */
|
||||||
INTTYPE signednum=0;
|
signednum = va_arg(pf->ap, int);
|
||||||
switch (pf->size) {
|
break;
|
||||||
case INTSZ:
|
case LONGSZ:
|
||||||
/* %d */
|
/* %ld */
|
||||||
signednum = va_arg(pf->ap, int);
|
signednum = va_arg(pf->ap, long);
|
||||||
break;
|
break;
|
||||||
case LONGSZ:
|
|
||||||
/* %ld */
|
|
||||||
signednum = va_arg(pf->ap, long);
|
|
||||||
break;
|
|
||||||
#ifdef USE_LONGLONG
|
#ifdef USE_LONGLONG
|
||||||
case LLONGSZ:
|
case LLONGSZ:
|
||||||
/* %lld */
|
/* %lld */
|
||||||
signednum = va_arg(pf->ap, long long);
|
signednum = va_arg(pf->ap, long long);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case SIZETSZ:
|
case SIZETSZ:
|
||||||
/* %zd */
|
/* %zd */
|
||||||
signednum = va_arg(pf->ap, ssize_t);
|
signednum = va_arg(pf->ap, ssize_t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for negative numbers.
|
* Check for negative numbers.
|
||||||
*/
|
*/
|
||||||
if (signednum < 0) {
|
if (signednum < 0) {
|
||||||
pf->sign = -1;
|
pf->sign = -1;
|
||||||
pf->num = -signednum;
|
pf->num = -signednum;
|
||||||
}
|
} else {
|
||||||
else {
|
pf->num = signednum;
|
||||||
pf->num = signednum;
|
}
|
||||||
}
|
} else {
|
||||||
}
|
/* unsigned integer */
|
||||||
else {
|
switch (pf->size) {
|
||||||
/* unsigned integer */
|
case INTSZ:
|
||||||
switch (pf->size) {
|
/* %u (or %o, %x) */
|
||||||
case INTSZ:
|
pf->num = va_arg(pf->ap, unsigned int);
|
||||||
/* %u (or %o, %x) */
|
break;
|
||||||
pf->num = va_arg(pf->ap, unsigned int);
|
case LONGSZ:
|
||||||
break;
|
/* %lu (or %lo, %lx) */
|
||||||
case LONGSZ:
|
pf->num = va_arg(pf->ap, unsigned long);
|
||||||
/* %lu (or %lo, %lx) */
|
break;
|
||||||
pf->num = va_arg(pf->ap, unsigned long);
|
|
||||||
break;
|
|
||||||
#ifdef USE_LONGLONG
|
#ifdef USE_LONGLONG
|
||||||
case LLONGSZ:
|
case LLONGSZ:
|
||||||
/* %llu, %llo, %llx */
|
/* %llu, %llo, %llx */
|
||||||
pf->num = va_arg(pf->ap, unsigned long long);
|
pf->num = va_arg(pf->ap, unsigned long long);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case SIZETSZ:
|
case SIZETSZ:
|
||||||
/* %zu, %zo, %zx */
|
/* %zu, %zo, %zx */
|
||||||
pf->num = va_arg(pf->ap, size_t);
|
pf->num = va_arg(pf->ap, size_t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -320,40 +301,34 @@ __pf_getnum(PF *pf, int ch)
|
|||||||
* If the "alternate format" was requested, or always for pointers,
|
* If the "alternate format" was requested, or always for pointers,
|
||||||
* note to print the C prefix for the type.
|
* note to print the C prefix for the type.
|
||||||
*/
|
*/
|
||||||
static
|
static void __pf_setbase(PF *pf, int ch) {
|
||||||
void
|
switch (ch) {
|
||||||
__pf_setbase(PF *pf, int ch)
|
case 'd':
|
||||||
{
|
case 'u':
|
||||||
switch (ch) {
|
pf->base = 10;
|
||||||
case 'd':
|
break;
|
||||||
case 'u':
|
case 'x':
|
||||||
pf->base = 10;
|
case 'p':
|
||||||
break;
|
pf->base = 16;
|
||||||
case 'x':
|
break;
|
||||||
case 'p':
|
case 'o':
|
||||||
pf->base = 16;
|
pf->base = 8;
|
||||||
break;
|
break;
|
||||||
case 'o':
|
}
|
||||||
pf->base = 8;
|
if (pf->altformat || ch == 'p') {
|
||||||
break;
|
pf->baseprefix = 1;
|
||||||
}
|
}
|
||||||
if (pf->altformat || ch=='p') {
|
|
||||||
pf->baseprefix = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function to print "spc" instances of the fill character.
|
* Function to print "spc" instances of the fill character.
|
||||||
*/
|
*/
|
||||||
static
|
static void __pf_fill(PF *pf, int spc) {
|
||||||
void
|
char f = pf->fillchar;
|
||||||
__pf_fill(PF *pf, int spc)
|
int i;
|
||||||
{
|
for (i = 0; i < spc; i++) {
|
||||||
char f = pf->fillchar;
|
__pf_print(pf, &f, 1);
|
||||||
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
|
* and the other is the sign) get printed *after* space padding but
|
||||||
* *before* zero padding, if padding is on the left.
|
* *before* zero padding, if padding is on the left.
|
||||||
*/
|
*/
|
||||||
static
|
static void __pf_printstuff(PF *pf, const char *prefix, const char *prefix2,
|
||||||
void
|
const char *stuff) {
|
||||||
__pf_printstuff(PF *pf,
|
/* Total length to print. */
|
||||||
const char *prefix, const char *prefix2,
|
int len = strlen(prefix) + strlen(prefix2) + strlen(stuff);
|
||||||
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". */
|
/* Get field width and compute amount of padding in "spc". */
|
||||||
int spc = pf->spacing;
|
int spc = pf->spacing;
|
||||||
if (spc > len) {
|
if (spc > len) {
|
||||||
spc -= len;
|
spc -= len;
|
||||||
}
|
} else {
|
||||||
else {
|
spc = 0;
|
||||||
spc = 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* If padding on left and the fill char is not 0, pad first. */
|
/* If padding on left and the fill char is not 0, pad first. */
|
||||||
if (spc > 0 && pf->rightspc==0 && pf->fillchar!='0') {
|
if (spc > 0 && pf->rightspc == 0 && pf->fillchar != '0') {
|
||||||
__pf_fill(pf, spc);
|
__pf_fill(pf, spc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print the prefixes. */
|
/* Print the prefixes. */
|
||||||
__pf_print(pf, prefix, strlen(prefix));
|
__pf_print(pf, prefix, strlen(prefix));
|
||||||
__pf_print(pf, prefix2, strlen(prefix2));
|
__pf_print(pf, prefix2, strlen(prefix2));
|
||||||
|
|
||||||
/* If padding on left and the fill char *is* 0, pad here. */
|
/* If padding on left and the fill char *is* 0, pad here. */
|
||||||
if (spc > 0 && pf->rightspc==0 && pf->fillchar=='0') {
|
if (spc > 0 && pf->rightspc == 0 && pf->fillchar == '0') {
|
||||||
__pf_fill(pf, spc);
|
__pf_fill(pf, spc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print the actual string. */
|
/* Print the actual string. */
|
||||||
__pf_print(pf, stuff, strlen(stuff));
|
__pf_print(pf, stuff, strlen(stuff));
|
||||||
|
|
||||||
/* If padding on the right, pad afterwards. */
|
/* If padding on the right, pad afterwards. */
|
||||||
if (spc > 0 && pf->rightspc!=0) {
|
if (spc > 0 && pf->rightspc != 0) {
|
||||||
__pf_fill(pf, spc);
|
__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
|
* NUMBER_BUF_SIZE is set so that the longest number string we can
|
||||||
* generate (a long long printed in octal) will fit. See above.
|
* generate (a long long printed in octal) will fit. See above.
|
||||||
*/
|
*/
|
||||||
static
|
static void __pf_printnum(PF *pf) {
|
||||||
void
|
/* Digits to print with. */
|
||||||
__pf_printnum(PF *pf)
|
const char *const digits = "0123456789abcdef";
|
||||||
{
|
|
||||||
/* Digits to print with. */
|
|
||||||
const char *const digits = "0123456789abcdef";
|
|
||||||
|
|
||||||
char buf[NUMBER_BUF_SIZE]; /* Accumulation buffer for string. */
|
char buf[NUMBER_BUF_SIZE]; /* Accumulation buffer for string. */
|
||||||
char *x; /* Current pointer into buf. */
|
char *x; /* Current pointer into buf. */
|
||||||
unsigned INTTYPE xnum; /* Current value to print. */
|
unsigned INTTYPE xnum; /* Current value to print. */
|
||||||
const char *bprefix; /* Base prefix (0, 0x, or nothing) */
|
const char *bprefix; /* Base prefix (0, 0x, or nothing) */
|
||||||
const char *sprefix; /* Sign prefix (- or nothing) */
|
const char *sprefix; /* Sign prefix (- or nothing) */
|
||||||
|
|
||||||
/* Start in the last slot of the buffer. */
|
/* Start in the last slot of the buffer. */
|
||||||
x = buf+sizeof(buf)-1;
|
x = buf + sizeof(buf) - 1;
|
||||||
|
|
||||||
/* Insert null terminator. */
|
/* Insert null terminator. */
|
||||||
*x-- = 0;
|
*x-- = 0;
|
||||||
|
|
||||||
/* Initialize value. */
|
/* Initialize value. */
|
||||||
xnum = pf->num;
|
xnum = pf->num;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert a single digit.
|
* Convert a single digit.
|
||||||
* Do this loop at least once - that way 0 prints as 0 and not "".
|
* Do this loop at least once - that way 0 prints as 0 and not "".
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
/*
|
/*
|
||||||
* Get the digit character for the least significant
|
* Get the digit character for the least significant
|
||||||
* part of xnum.
|
* part of xnum.
|
||||||
*/
|
*/
|
||||||
*x = digits[xnum % pf->base];
|
*x = digits[xnum % pf->base];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Back up the pointer to point to the next space to the left.
|
* Back up the pointer to point to the next space to the left.
|
||||||
*/
|
*/
|
||||||
x--;
|
x--;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drop the value of the digit we just printed from xnum.
|
* Drop the value of the digit we just printed from xnum.
|
||||||
*/
|
*/
|
||||||
xnum = xnum / pf->base;
|
xnum = xnum / pf->base;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If xnum hits 0 there's no more number left.
|
* If xnum hits 0 there's no more number left.
|
||||||
*/
|
*/
|
||||||
} while (xnum > 0);
|
} while (xnum > 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* x points to the *next* slot in the buffer to use.
|
* x points to the *next* slot in the buffer to use.
|
||||||
* However, we're done printing the number. So it's pointing
|
* However, we're done printing the number. So it's pointing
|
||||||
* one slot *before* the start of the actual number text.
|
* one slot *before* the start of the actual number text.
|
||||||
* So advance it by one so it actually points at the number.
|
* So advance it by one so it actually points at the number.
|
||||||
*/
|
*/
|
||||||
x++;
|
x++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If a base prefix was requested, select it.
|
* If a base prefix was requested, select it.
|
||||||
*/
|
*/
|
||||||
if (pf->baseprefix && pf->base==16) {
|
if (pf->baseprefix && pf->base == 16) {
|
||||||
bprefix = "0x";
|
bprefix = "0x";
|
||||||
}
|
} else if (pf->baseprefix && pf->base == 8) {
|
||||||
else if (pf->baseprefix && pf->base==8) {
|
bprefix = "0";
|
||||||
bprefix = "0";
|
} else {
|
||||||
}
|
bprefix = "";
|
||||||
else {
|
}
|
||||||
bprefix = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Choose the sign prefix.
|
* Choose the sign prefix.
|
||||||
*/
|
*/
|
||||||
sprefix = pf->sign ? "-" : "";
|
sprefix = pf->sign ? "-" : "";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now actually print the string we just generated.
|
* Now actually print the string we just generated.
|
||||||
*/
|
*/
|
||||||
__pf_printstuff(pf, sprefix, bprefix, x);
|
__pf_printstuff(pf, sprefix, bprefix, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process a single character out of the format string.
|
* Process a single character out of the format string.
|
||||||
*/
|
*/
|
||||||
static
|
static void __pf_send(PF *pf, int ch) {
|
||||||
void
|
/* Cannot get NULs here. */
|
||||||
__pf_send(PF *pf, int ch)
|
assert(ch != 0);
|
||||||
{
|
|
||||||
/* Cannot get NULs here. */
|
|
||||||
assert(ch!=0);
|
|
||||||
|
|
||||||
if (pf->in_pct==0 && ch!='%') {
|
if (pf->in_pct == 0 && ch != '%') {
|
||||||
/*
|
/*
|
||||||
* Not currently in a format, and not a %. Just send
|
* Not currently in a format, and not a %. Just send
|
||||||
* the character on through.
|
* the character on through.
|
||||||
*/
|
*/
|
||||||
char c = ch;
|
char c = ch;
|
||||||
__pf_print(pf, &c, 1);
|
__pf_print(pf, &c, 1);
|
||||||
}
|
} else if (pf->in_pct == 0) {
|
||||||
else if (pf->in_pct==0) {
|
/*
|
||||||
/*
|
* Not in a format, but got a %. Start a format.
|
||||||
* Not in a format, but got a %. Start a format.
|
*/
|
||||||
*/
|
pf->in_pct = 1;
|
||||||
pf->in_pct = 1;
|
} else if (strchr("#-lz0123456789", ch)) {
|
||||||
}
|
/*
|
||||||
else if (strchr("#-lz0123456789", ch)) {
|
* These are the modifier characters we recognize.
|
||||||
/*
|
* (These are the characters between the % and the type.)
|
||||||
* 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)) {
|
||||||
__pf_modifier(pf, ch);
|
/*
|
||||||
}
|
* Integer types.
|
||||||
else if (strchr("doupx", ch)) {
|
* Fetch the number, set the base, print it, then
|
||||||
/*
|
* reset for the next format.
|
||||||
* Integer types.
|
*/
|
||||||
* Fetch the number, set the base, print it, then
|
__pf_getnum(pf, ch);
|
||||||
* reset for the next format.
|
__pf_setbase(pf, ch);
|
||||||
*/
|
__pf_printnum(pf);
|
||||||
__pf_getnum(pf, ch);
|
__pf_endfield(pf);
|
||||||
__pf_setbase(pf, ch);
|
} else if (ch == 's') {
|
||||||
__pf_printnum(pf);
|
/*
|
||||||
__pf_endfield(pf);
|
* Print a string.
|
||||||
}
|
*/
|
||||||
else if (ch=='s') {
|
const char *str = va_arg(pf->ap, const char *);
|
||||||
/*
|
if (str == NULL) {
|
||||||
* Print a string.
|
str = "(null)";
|
||||||
*/
|
}
|
||||||
const char *str = va_arg(pf->ap, const char *);
|
__pf_printstuff(pf, "", "", str);
|
||||||
if (str==NULL) {
|
__pf_endfield(pf);
|
||||||
str = "(null)";
|
} else {
|
||||||
}
|
/*
|
||||||
__pf_printstuff(pf, "", "", str);
|
* %%, %c, or illegal character.
|
||||||
__pf_endfield(pf);
|
* Illegal characters are printed like %%.
|
||||||
}
|
* for example, %5k prints " k".
|
||||||
else {
|
*/
|
||||||
/*
|
char x[2];
|
||||||
* %%, %c, or illegal character.
|
if (ch == 'c') {
|
||||||
* Illegal characters are printed like %%.
|
x[0] = va_arg(pf->ap, int);
|
||||||
* for example, %5k prints " k".
|
} else {
|
||||||
*/
|
x[0] = ch;
|
||||||
char x[2];
|
}
|
||||||
if (ch=='c') {
|
x[1] = 0;
|
||||||
x[0] = va_arg(pf->ap, int);
|
__pf_printstuff(pf, "", "", x);
|
||||||
}
|
__pf_endfield(pf);
|
||||||
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,
|
* Create and initialize a printf state object,
|
||||||
* then send it each character from the format string.
|
* then send it each character from the format string.
|
||||||
*/
|
*/
|
||||||
int
|
int __vprintf(void (*func)(void *clientdata, const char *str, size_t len),
|
||||||
__vprintf(void (*func)(void *clientdata, const char *str, size_t len),
|
void *clientdata, const char *format, va_list ap) {
|
||||||
void *clientdata, const char *format, va_list ap)
|
PF pf;
|
||||||
{
|
int i;
|
||||||
PF pf;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
pf.sendfunc = func;
|
pf.sendfunc = func;
|
||||||
pf.clientdata = clientdata;
|
pf.clientdata = clientdata;
|
||||||
#ifdef va_copy
|
#ifdef va_copy
|
||||||
va_copy(pf.ap, ap);
|
va_copy(pf.ap, ap);
|
||||||
#else
|
#else
|
||||||
pf.ap = ap;
|
pf.ap = ap;
|
||||||
#endif
|
#endif
|
||||||
pf.charcount = 0;
|
pf.charcount = 0;
|
||||||
__pf_endfield(&pf);
|
__pf_endfield(&pf);
|
||||||
|
|
||||||
for (i=0; format[i]; i++) {
|
for (i = 0; format[i]; i++) {
|
||||||
__pf_send(&pf, format[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.
|
* Standard C string/IO function: printf into a character buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Context structure for snprintf: buffer to print into, maximum
|
* Context structure for snprintf: buffer to print into, maximum
|
||||||
* length, and index of the next character to write.
|
* length, and index of the next character to write.
|
||||||
@@ -58,9 +57,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t buflen;
|
size_t buflen;
|
||||||
size_t bufpos;
|
size_t bufpos;
|
||||||
} SNP;
|
} SNP;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -70,88 +69,79 @@ typedef struct {
|
|||||||
* null-terminated.
|
* null-terminated.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
static void __snprintf_send(void *mydata, const char *data, size_t len) {
|
||||||
void
|
SNP *snp = mydata;
|
||||||
__snprintf_send(void *mydata, const char *data, size_t len)
|
unsigned i;
|
||||||
{
|
|
||||||
SNP *snp = mydata;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
/* For each character we're sent... */
|
/* For each character we're sent... */
|
||||||
for (i=0; i<len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
|
|
||||||
/* If we aren't past the length, */
|
/* If we aren't past the length, */
|
||||||
if (snp->bufpos < snp->buflen) {
|
if (snp->bufpos < snp->buflen) {
|
||||||
|
|
||||||
/* store the character */
|
/* store the character */
|
||||||
snp->buf[snp->bufpos] = data[i];
|
snp->buf[snp->bufpos] = data[i];
|
||||||
|
|
||||||
/* and increment the position. */
|
/* and increment the position. */
|
||||||
snp->bufpos++;
|
snp->bufpos++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The va_list version of snprintf.
|
* The va_list version of snprintf.
|
||||||
*/
|
*/
|
||||||
int
|
int vsnprintf(char *buf, size_t len, const char *fmt, va_list ap) {
|
||||||
vsnprintf(char *buf, size_t len, const char *fmt, va_list ap)
|
int chars;
|
||||||
{
|
SNP snp;
|
||||||
int chars;
|
|
||||||
SNP snp;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fill in the context structure.
|
* Fill in the context structure.
|
||||||
* We set snp.buflen to the number of characters that can be
|
* We set snp.buflen to the number of characters that can be
|
||||||
* written (excluding the null terminator) so as not to have
|
* written (excluding the null terminator) so as not to have
|
||||||
* to special-case the possibility that we got passed a length
|
* to special-case the possibility that we got passed a length
|
||||||
* of zero elsewhere.
|
* of zero elsewhere.
|
||||||
*/
|
*/
|
||||||
snp.buf = buf;
|
snp.buf = buf;
|
||||||
if (len==0) {
|
if (len == 0) {
|
||||||
snp.buflen = 0;
|
snp.buflen = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
snp.buflen = len - 1;
|
||||||
snp.buflen = len-1;
|
}
|
||||||
}
|
snp.bufpos = 0;
|
||||||
snp.bufpos = 0;
|
|
||||||
|
|
||||||
/* Call __vprintf to do the actual work. */
|
/* Call __vprintf to do the actual work. */
|
||||||
chars = __vprintf(__snprintf_send, &snp, fmt, ap);
|
chars = __vprintf(__snprintf_send, &snp, fmt, ap);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a null terminator. If the length *we were passed* is greater
|
* Add a null terminator. If the length *we were passed* is greater
|
||||||
* than zero, we reserved a space in the buffer for the terminator,
|
* 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,
|
* so this won't overflow. If the length we were passed is zero,
|
||||||
* nothing will have been or should be written anyway, and buf
|
* nothing will have been or should be written anyway, and buf
|
||||||
* might even be NULL. (C99 explicitly endorses this possibility.)
|
* might even be NULL. (C99 explicitly endorses this possibility.)
|
||||||
*/
|
*/
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
buf[snp.bufpos] = 0;
|
buf[snp.bufpos] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the number of characters __vprintf processed.
|
* Return the number of characters __vprintf processed.
|
||||||
* According to C99, snprintf should return this number, not
|
* According to C99, snprintf should return this number, not
|
||||||
* the number of characters actually stored, and should not
|
* the number of characters actually stored, and should not
|
||||||
* return -1 on overflow but only on other errors. (All none
|
* return -1 on overflow but only on other errors. (All none
|
||||||
* of them since we don't do multibyte characters...)
|
* of them since we don't do multibyte characters...)
|
||||||
*/
|
*/
|
||||||
return chars;
|
return chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* snprintf - hand off to vsnprintf.
|
* snprintf - hand off to vsnprintf.
|
||||||
*/
|
*/
|
||||||
int
|
int snprintf(char *buf, size_t len, const char *fmt, ...) {
|
||||||
snprintf(char *buf, size_t len, const char *fmt, ...)
|
int chars;
|
||||||
{
|
va_list ap;
|
||||||
int chars;
|
va_start(ap, fmt);
|
||||||
va_list ap;
|
chars = vsnprintf(buf, len, fmt, ap);
|
||||||
va_start(ap, fmt);
|
va_end(ap);
|
||||||
chars = vsnprintf(buf, len, fmt, ap);
|
return chars;
|
||||||
va_end(ap);
|
|
||||||
return chars;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,56 +46,53 @@
|
|||||||
* really report syntax errors or overflow in any useful way.
|
* really report syntax errors or overflow in any useful way.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int atoi(const char *s) {
|
||||||
atoi(const char *s)
|
static const char digits[] = "0123456789"; /* legal digits in order */
|
||||||
{
|
unsigned val = 0; /* value we're accumulating */
|
||||||
static const char digits[] = "0123456789"; /* legal digits in order */
|
int neg = 0; /* set to true if we see a minus sign */
|
||||||
unsigned val=0; /* value we're accumulating */
|
|
||||||
int neg=0; /* set to true if we see a minus sign */
|
|
||||||
|
|
||||||
/* skip whitespace */
|
/* skip whitespace */
|
||||||
while (*s==' ' || *s=='\t') {
|
while (*s == ' ' || *s == '\t') {
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for sign */
|
/* check for sign */
|
||||||
if (*s=='-') {
|
if (*s == '-') {
|
||||||
neg=1;
|
neg = 1;
|
||||||
s++;
|
s++;
|
||||||
}
|
} else if (*s == '+') {
|
||||||
else if (*s=='+') {
|
s++;
|
||||||
s++;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* process each digit */
|
/* process each digit */
|
||||||
while (*s) {
|
while (*s) {
|
||||||
const char *where;
|
const char *where;
|
||||||
unsigned digit;
|
unsigned digit;
|
||||||
|
|
||||||
/* look for the digit in the list of digits */
|
/* look for the digit in the list of digits */
|
||||||
where = strchr(digits, *s);
|
where = strchr(digits, *s);
|
||||||
if (where==NULL) {
|
if (where == NULL) {
|
||||||
/* not found; not a digit, so stop */
|
/* not found; not a digit, so stop */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the index into the digit list, which is the value */
|
/* get the index into the digit list, which is the value */
|
||||||
digit = (where - digits);
|
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 */
|
/* shift the number over and add in the new digit */
|
||||||
val = val*10 + digit;
|
val = val * 10 + digit;
|
||||||
|
|
||||||
/* look at the next character */
|
/* look at the next character */
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle negative numbers */
|
/* handle negative numbers */
|
||||||
if (neg) {
|
if (neg) {
|
||||||
return -val;
|
return -val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* done */
|
/* done */
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,32 +45,28 @@
|
|||||||
* memory.
|
* memory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void bzero(void *vblock, size_t len) {
|
||||||
bzero(void *vblock, size_t len)
|
char *block = vblock;
|
||||||
{
|
size_t i;
|
||||||
char *block = vblock;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For performance, optimize the common case where the pointer
|
* For performance, optimize the common case where the pointer
|
||||||
* and the length are word-aligned, and write word-at-a-time
|
* and the length are word-aligned, and write word-at-a-time
|
||||||
* instead of byte-at-a-time. Otherwise, write bytes.
|
* instead of byte-at-a-time. Otherwise, write bytes.
|
||||||
*
|
*
|
||||||
* The alignment logic here should be portable. We rely on the
|
* The alignment logic here should be portable. We rely on the
|
||||||
* compiler to be reasonably intelligent about optimizing the
|
* compiler to be reasonably intelligent about optimizing the
|
||||||
* divides and moduli out. Fortunately, it is.
|
* divides and moduli out. Fortunately, it is.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((uintptr_t)block % sizeof(long) == 0 &&
|
if ((uintptr_t)block % sizeof(long) == 0 && len % sizeof(long) == 0) {
|
||||||
len % sizeof(long) == 0) {
|
long *lb = (long *)block;
|
||||||
long *lb = (long *)block;
|
for (i = 0; i < len / sizeof(long); i++) {
|
||||||
for (i=0; i<len/sizeof(long); i++) {
|
lb[i] = 0;
|
||||||
lb[i] = 0;
|
}
|
||||||
}
|
} else {
|
||||||
}
|
for (i = 0; i < len; i++) {
|
||||||
else {
|
block[i] = 0;
|
||||||
for (i=0; i<len; i++) {
|
}
|
||||||
block[i] = 0;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,43 +44,39 @@
|
|||||||
* C standard function - copy a block of memory.
|
* C standard function - copy a block of memory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void *
|
void *memcpy(void *dst, const void *src, size_t len) {
|
||||||
memcpy(void *dst, const void *src, size_t len)
|
size_t i;
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* memcpy does not support overlapping buffers, so always do it
|
* memcpy does not support overlapping buffers, so always do it
|
||||||
* forwards. (Don't change this without adjusting memmove.)
|
* forwards. (Don't change this without adjusting memmove.)
|
||||||
*
|
*
|
||||||
* For speedy copying, optimize the common case where both pointers
|
* For speedy copying, optimize the common case where both pointers
|
||||||
* and the length are word-aligned, and copy word-at-a-time instead
|
* and the length are word-aligned, and copy word-at-a-time instead
|
||||||
* of byte-at-a-time. Otherwise, copy by bytes.
|
* of byte-at-a-time. Otherwise, copy by bytes.
|
||||||
*
|
*
|
||||||
* The alignment logic below should be portable. We rely on
|
* The alignment logic below should be portable. We rely on
|
||||||
* the compiler to be reasonably intelligent about optimizing
|
* the compiler to be reasonably intelligent about optimizing
|
||||||
* the divides and modulos out. Fortunately, it is.
|
* the divides and modulos out. Fortunately, it is.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((uintptr_t)dst % sizeof(long) == 0 &&
|
if ((uintptr_t)dst % sizeof(long) == 0 &&
|
||||||
(uintptr_t)src % sizeof(long) == 0 &&
|
(uintptr_t)src % sizeof(long) == 0 && len % sizeof(long) == 0) {
|
||||||
len % sizeof(long) == 0) {
|
|
||||||
|
|
||||||
long *d = dst;
|
long *d = dst;
|
||||||
const long *s = src;
|
const long *s = src;
|
||||||
|
|
||||||
for (i=0; i<len/sizeof(long); i++) {
|
for (i = 0; i < len / sizeof(long); i++) {
|
||||||
d[i] = s[i];
|
d[i] = s[i];
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
char *d = dst;
|
||||||
char *d = dst;
|
const char *s = src;
|
||||||
const char *s = src;
|
|
||||||
|
|
||||||
for (i=0; i<len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
d[i] = s[i];
|
d[i] = s[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,73 +45,69 @@
|
|||||||
* regions correctly.
|
* regions correctly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void *
|
void *memmove(void *dst, const void *src, size_t len) {
|
||||||
memmove(void *dst, const void *src, size_t len)
|
size_t i;
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the buffers don't overlap, it doesn't matter what direction
|
* 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 copy in. If they do, it does, so just assume they always do.
|
||||||
* We don't concern ourselves with the possibility that the region
|
* We don't concern ourselves with the possibility that the region
|
||||||
* to copy might roll over across the top of memory, because it's
|
* to copy might roll over across the top of memory, because it's
|
||||||
* not going to happen.
|
* not going to happen.
|
||||||
*
|
*
|
||||||
* If the destination is above the source, we have to copy
|
* If the destination is above the source, we have to copy
|
||||||
* back to front to avoid overwriting the data we want to
|
* back to front to avoid overwriting the data we want to
|
||||||
* copy.
|
* copy.
|
||||||
*
|
*
|
||||||
* dest: dddddddd
|
* dest: dddddddd
|
||||||
* src: ssssssss ^
|
* src: ssssssss ^
|
||||||
* | ^ |___|
|
* | ^ |___|
|
||||||
* |___|
|
* |___|
|
||||||
*
|
*
|
||||||
* If the destination is below the source, we have to copy
|
* If the destination is below the source, we have to copy
|
||||||
* front to back.
|
* front to back.
|
||||||
*
|
*
|
||||||
* dest: dddddddd
|
* dest: dddddddd
|
||||||
* src: ^ ssssssss
|
* src: ^ ssssssss
|
||||||
* |___| ^ |
|
* |___| ^ |
|
||||||
* |___|
|
* |___|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((uintptr_t)dst < (uintptr_t)src) {
|
if ((uintptr_t)dst < (uintptr_t)src) {
|
||||||
/*
|
/*
|
||||||
* As author/maintainer of libc, take advantage of the
|
* As author/maintainer of libc, take advantage of the
|
||||||
* fact that we know memcpy copies forwards.
|
* fact that we know memcpy copies forwards.
|
||||||
*/
|
*/
|
||||||
return memcpy(dst, src, len);
|
return memcpy(dst, src, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy by words in the common case. Look in memcpy.c for more
|
* Copy by words in the common case. Look in memcpy.c for more
|
||||||
* information.
|
* information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((uintptr_t)dst % sizeof(long) == 0 &&
|
if ((uintptr_t)dst % sizeof(long) == 0 &&
|
||||||
(uintptr_t)src % sizeof(long) == 0 &&
|
(uintptr_t)src % sizeof(long) == 0 && len % sizeof(long) == 0) {
|
||||||
len % sizeof(long) == 0) {
|
|
||||||
|
|
||||||
long *d = dst;
|
long *d = dst;
|
||||||
const long *s = src;
|
const long *s = src;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The reason we copy index i-1 and test i>0 is that
|
* The reason we copy index i-1 and test i>0 is that
|
||||||
* i is unsigned -- so testing i>=0 doesn't work.
|
* i is unsigned -- so testing i>=0 doesn't work.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (i=len/sizeof(long); i>0; i--) {
|
for (i = len / sizeof(long); i > 0; i--) {
|
||||||
d[i-1] = s[i-1];
|
d[i - 1] = s[i - 1];
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
char *d = dst;
|
||||||
char *d = dst;
|
const char *s = src;
|
||||||
const char *s = src;
|
|
||||||
|
|
||||||
for (i=len; i>0; i--) {
|
for (i = len; i > 0; i--) {
|
||||||
d[i-1] = s[i-1];
|
d[i - 1] = s[i - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,15 +38,13 @@
|
|||||||
* C standard function - initialize a block of memory
|
* C standard function - initialize a block of memory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void *
|
void *memset(void *ptr, int ch, size_t len) {
|
||||||
memset(void *ptr, int ch, size_t len)
|
char *p = ptr;
|
||||||
{
|
size_t i;
|
||||||
char *p = ptr;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i=0; i<len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
p[i] = ch;
|
p[i] = ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,12 +43,10 @@
|
|||||||
* Standard C string function: append one string to another.
|
* Standard C string function: append one string to another.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char *
|
char *strcat(char *dest, const char *src) {
|
||||||
strcat(char *dest, const char *src)
|
size_t offset;
|
||||||
{
|
|
||||||
size_t offset;
|
|
||||||
|
|
||||||
offset = strlen(dest);
|
offset = strlen(dest);
|
||||||
strcpy(dest+offset, src);
|
strcpy(dest + offset, src);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,26 +43,24 @@
|
|||||||
* C standard string function: find leftmost instance of a character
|
* C standard string function: find leftmost instance of a character
|
||||||
* in a string.
|
* in a string.
|
||||||
*/
|
*/
|
||||||
char *
|
char *strchr(const char *s, int ch_arg) {
|
||||||
strchr(const char *s, int ch_arg)
|
/* avoid sign-extension problems */
|
||||||
{
|
const char ch = ch_arg;
|
||||||
/* avoid sign-extension problems */
|
|
||||||
const char ch = ch_arg;
|
|
||||||
|
|
||||||
/* scan from left to right */
|
/* scan from left to right */
|
||||||
while (*s) {
|
while (*s) {
|
||||||
/* if we hit it, return it */
|
/* if we hit it, return it */
|
||||||
if (*s == ch) {
|
if (*s == ch) {
|
||||||
return (char *)s;
|
return (char *)s;
|
||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we were looking for the 0, return that */
|
/* if we were looking for the 0, return that */
|
||||||
if (*s == ch) {
|
if (*s == ch) {
|
||||||
return (char *)s;
|
return (char *)s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* didn't find it */
|
/* didn't find it */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,47 +44,44 @@
|
|||||||
* sort order.
|
* sort order.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int strcmp(const char *a, const char *b) {
|
||||||
strcmp(const char *a, const char *b)
|
size_t i;
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Walk down both strings until either they're different
|
* Walk down both strings until either they're different
|
||||||
* or we hit the end of A.
|
* or we hit the end of A.
|
||||||
*
|
*
|
||||||
* If A and B strings are not the same length, when the
|
* If A and B strings are not the same length, when the
|
||||||
* shorter one ends, the two will be different, and we'll
|
* shorter one ends, the two will be different, and we'll
|
||||||
* stop before running off the end of either.
|
* stop before running off the end of either.
|
||||||
*
|
*
|
||||||
* If they *are* the same length, it's sufficient to check
|
* 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
|
* 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
|
* same as checking to make sure we haven't run off the end of
|
||||||
* B.
|
* B.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (i=0; a[i]!=0 && a[i]==b[i]; i++) {
|
for (i = 0; a[i] != 0 && a[i] == b[i]; i++) {
|
||||||
/* nothing */
|
/* nothing */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If A is greater than B, return 1. If A is less than B,
|
* 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
|
* return -1. If they're the same, return 0. Since we have
|
||||||
* stopped at the first character of difference (or the end of
|
* stopped at the first character of difference (or the end of
|
||||||
* both strings) checking the character under I accomplishes
|
* both strings) checking the character under I accomplishes
|
||||||
* this.
|
* this.
|
||||||
*
|
*
|
||||||
* Note that strcmp does not handle accented characters,
|
* Note that strcmp does not handle accented characters,
|
||||||
* internationalization, or locale sort order; strcoll() does
|
* internationalization, or locale sort order; strcoll() does
|
||||||
* that.
|
* that.
|
||||||
*
|
*
|
||||||
* The rules say we compare order in terms of *unsigned* char.
|
* The rules say we compare order in terms of *unsigned* char.
|
||||||
*/
|
*/
|
||||||
if ((unsigned char)a[i] > (unsigned char)b[i]) {
|
if ((unsigned char)a[i] > (unsigned char)b[i]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else if (a[i] == b[i]) {
|
||||||
else if (a[i] == b[i]) {
|
return 0;
|
||||||
return 0;
|
}
|
||||||
}
|
return -1;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,22 +42,20 @@
|
|||||||
/*
|
/*
|
||||||
* Standard C string function: copy one string to another.
|
* Standard C string function: copy one string to another.
|
||||||
*/
|
*/
|
||||||
char *
|
char *strcpy(char *dest, const char *src) {
|
||||||
strcpy(char *dest, const char *src)
|
size_t i;
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy characters until we hit the null terminator.
|
* Copy characters until we hit the null terminator.
|
||||||
*/
|
*/
|
||||||
for (i=0; src[i]; i++) {
|
for (i = 0; src[i]; i++) {
|
||||||
dest[i] = src[i];
|
dest[i] = src[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add null terminator to result.
|
* Add null terminator to result.
|
||||||
*/
|
*/
|
||||||
dest[i] = 0;
|
dest[i] = 0;
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,13 +43,11 @@
|
|||||||
* C standard string function: get length of a string
|
* C standard string function: get length of a string
|
||||||
*/
|
*/
|
||||||
|
|
||||||
size_t
|
size_t strlen(const char *str) {
|
||||||
strlen(const char *str)
|
size_t ret = 0;
|
||||||
{
|
|
||||||
size_t ret = 0;
|
|
||||||
|
|
||||||
while (str[ret]) {
|
while (str[ret]) {
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,27 +43,25 @@
|
|||||||
* C standard string function: find rightmost instance of a character
|
* C standard string function: find rightmost instance of a character
|
||||||
* in a string.
|
* in a string.
|
||||||
*/
|
*/
|
||||||
char *
|
char *strrchr(const char *s, int ch_arg) {
|
||||||
strrchr(const char *s, int ch_arg)
|
/* avoid sign-extension problems */
|
||||||
{
|
const char ch = ch_arg;
|
||||||
/* avoid sign-extension problems */
|
|
||||||
const char ch = ch_arg;
|
|
||||||
|
|
||||||
/* start one past the last character INCLUDING NULL TERMINATOR */
|
/* start one past the last character INCLUDING NULL TERMINATOR */
|
||||||
size_t i = strlen(s)+1;
|
size_t i = strlen(s) + 1;
|
||||||
|
|
||||||
/* go from right to left; stop at 0 */
|
/* go from right to left; stop at 0 */
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
|
|
||||||
/* decrement first */
|
/* decrement first */
|
||||||
i--;
|
i--;
|
||||||
|
|
||||||
/* now check the character we're over */
|
/* now check the character we're over */
|
||||||
if (s[i] == ch) {
|
if (s[i] == ch) {
|
||||||
return (char *)(s+i);
|
return (char *)(s + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* didn't find it */
|
/* didn't find it */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,51 +46,48 @@
|
|||||||
* The "context" argument should point to a "char *" that is preserved
|
* The "context" argument should point to a "char *" that is preserved
|
||||||
* between calls to strtok_r that wish to operate on same string.
|
* between calls to strtok_r that wish to operate on same string.
|
||||||
*/
|
*/
|
||||||
char *
|
char *strtok_r(char *string, const char *seps, char **context) {
|
||||||
strtok_r(char *string, const char *seps, char **context)
|
char *head; /* start of word */
|
||||||
{
|
char *tail; /* end of word */
|
||||||
char *head; /* start of word */
|
|
||||||
char *tail; /* end of word */
|
|
||||||
|
|
||||||
/* If we're starting up, initialize context */
|
/* If we're starting up, initialize context */
|
||||||
if (string) {
|
if (string) {
|
||||||
*context = string;
|
*context = string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get potential start of this next word */
|
/* Get potential start of this next word */
|
||||||
head = *context;
|
head = *context;
|
||||||
if (head == NULL) {
|
if (head == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip any leading separators */
|
/* Skip any leading separators */
|
||||||
while (*head && strchr(seps, *head)) {
|
while (*head && strchr(seps, *head)) {
|
||||||
head++;
|
head++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Did we hit the end? */
|
/* Did we hit the end? */
|
||||||
if (*head == 0) {
|
if (*head == 0) {
|
||||||
/* Nothing left */
|
/* Nothing left */
|
||||||
*context = NULL;
|
*context = NULL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skip over word */
|
/* skip over word */
|
||||||
tail = head;
|
tail = head;
|
||||||
while (*tail && !strchr(seps, *tail)) {
|
while (*tail && !strchr(seps, *tail)) {
|
||||||
tail++;
|
tail++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save head for next time in context */
|
/* Save head for next time in context */
|
||||||
if (*tail == 0) {
|
if (*tail == 0) {
|
||||||
*context = NULL;
|
*context = NULL;
|
||||||
}
|
} else {
|
||||||
else {
|
*tail = 0;
|
||||||
*tail = 0;
|
tail++;
|
||||||
tail++;
|
*context = tail;
|
||||||
*context = tail;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Return current word */
|
/* Return current word */
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
#ifndef _MIPS_CURRENT_H_
|
#ifndef _MIPS_CURRENT_H_
|
||||||
#define _MIPS_CURRENT_H_
|
#define _MIPS_CURRENT_H_
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Macro for current thread, or current cpu.
|
* Macro for current thread, or current cpu.
|
||||||
*
|
*
|
||||||
@@ -60,7 +59,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
register struct thread *curthread __asm("$23"); /* s7 register */
|
register struct thread *curthread __asm("$23"); /* s7 register */
|
||||||
#else
|
#else
|
||||||
#error "Don't know how to declare curthread in this compiler"
|
#error "Don't know how to declare curthread in this compiler"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -34,25 +34,23 @@
|
|||||||
* MIPS machine-dependent definitions for the ELF binary format.
|
* MIPS machine-dependent definitions for the ELF binary format.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* The ELF executable type. */
|
/* The ELF executable type. */
|
||||||
#define EM_MACHINE EM_MIPS
|
#define EM_MACHINE EM_MIPS
|
||||||
|
|
||||||
/* Linker relocation codes. SIZE DESCRIPTION */
|
/* Linker relocation codes. SIZE DESCRIPTION */
|
||||||
#define R_MIPS_NONE 0 /* --- nop */
|
#define R_MIPS_NONE 0 /* --- nop */
|
||||||
#define R_MIPS_16 1 /* u16 value */
|
#define R_MIPS_16 1 /* u16 value */
|
||||||
#define R_MIPS_32 2 /* u32 value */
|
#define R_MIPS_32 2 /* u32 value */
|
||||||
#define R_MIPS_REL32 3 /* u32 value relative to patched address */
|
#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_26 4 /* u26 j/jal instruction address field */
|
||||||
#define R_MIPS_HI16 5 /* u16 %hi(sym) as below */
|
#define R_MIPS_HI16 5 /* u16 %hi(sym) as below */
|
||||||
#define R_MIPS_LO16 6 /* s16 %lo(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_GPREL16 7 /* s16 offset from GP register */
|
||||||
#define R_MIPS_LITERAL 8 /* s16 GPREL16 for file-local symbols (?) */
|
#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_GOT16 9 /* u16 offset into global offset table */
|
||||||
#define R_MIPS_PC16 10 /* s16 PC-relative reference */
|
#define R_MIPS_PC16 10 /* s16 PC-relative reference */
|
||||||
#define R_MIPS_CALL16 11 /* u16 call through global offset table */
|
#define R_MIPS_CALL16 11 /* u16 call through global offset table */
|
||||||
#define R_MIPS_GPREL32 12 /* s32 offset from GP register */
|
#define R_MIPS_GPREL32 12 /* s32 offset from GP register */
|
||||||
/* %hi/%lo are defined so %hi(sym) << 16 + %lo(sym) = sym */
|
/* %hi/%lo are defined so %hi(sym) << 16 + %lo(sym) = sym */
|
||||||
|
|
||||||
|
|
||||||
#endif /* _MIPS_ELF_H_ */
|
#endif /* _MIPS_ELF_H_ */
|
||||||
|
|||||||
@@ -36,39 +36,37 @@
|
|||||||
#ifndef _KERN_MIPS_REGDEFS_H_
|
#ifndef _KERN_MIPS_REGDEFS_H_
|
||||||
#define _KERN_MIPS_REGDEFS_H_
|
#define _KERN_MIPS_REGDEFS_H_
|
||||||
|
|
||||||
|
#define z0 $0 /* always zero register */
|
||||||
#define z0 $0 /* always zero register */
|
#define AT $1 /* assembler temp register */
|
||||||
#define AT $1 /* assembler temp register */
|
#define v0 $2 /* value 0 */
|
||||||
#define v0 $2 /* value 0 */
|
#define v1 $3 /* value 1 */
|
||||||
#define v1 $3 /* value 1 */
|
#define a0 $4 /* argument 0 */
|
||||||
#define a0 $4 /* argument 0 */
|
#define a1 $5 /* argument 1 */
|
||||||
#define a1 $5 /* argument 1 */
|
#define a2 $6 /* argument 2 */
|
||||||
#define a2 $6 /* argument 2 */
|
#define a3 $7 /* argument 3 */
|
||||||
#define a3 $7 /* argument 3 */
|
#define t0 $8 /* temporary (caller-save) 0 */
|
||||||
#define t0 $8 /* temporary (caller-save) 0 */
|
#define t1 $9 /* temporary (caller-save) 1 */
|
||||||
#define t1 $9 /* temporary (caller-save) 1 */
|
#define t2 $10 /* temporary (caller-save) 2 */
|
||||||
#define t2 $10 /* temporary (caller-save) 2 */
|
#define t3 $11 /* temporary (caller-save) 3 */
|
||||||
#define t3 $11 /* temporary (caller-save) 3 */
|
#define t4 $12 /* temporary (caller-save) 4 */
|
||||||
#define t4 $12 /* temporary (caller-save) 4 */
|
#define t5 $13 /* temporary (caller-save) 5 */
|
||||||
#define t5 $13 /* temporary (caller-save) 5 */
|
#define t6 $14 /* temporary (caller-save) 6 */
|
||||||
#define t6 $14 /* temporary (caller-save) 6 */
|
#define t7 $15 /* temporary (caller-save) 7 */
|
||||||
#define t7 $15 /* temporary (caller-save) 7 */
|
#define s0 $16 /* saved (callee-save) 0 */
|
||||||
#define s0 $16 /* saved (callee-save) 0 */
|
#define s1 $17 /* saved (callee-save) 1 */
|
||||||
#define s1 $17 /* saved (callee-save) 1 */
|
#define s2 $18 /* saved (callee-save) 2 */
|
||||||
#define s2 $18 /* saved (callee-save) 2 */
|
#define s3 $19 /* saved (callee-save) 3 */
|
||||||
#define s3 $19 /* saved (callee-save) 3 */
|
#define s4 $20 /* saved (callee-save) 4 */
|
||||||
#define s4 $20 /* saved (callee-save) 4 */
|
#define s5 $21 /* saved (callee-save) 5 */
|
||||||
#define s5 $21 /* saved (callee-save) 5 */
|
#define s6 $22 /* saved (callee-save) 6 */
|
||||||
#define s6 $22 /* saved (callee-save) 6 */
|
#define s7 $23 /* saved (callee-save) 7 */
|
||||||
#define s7 $23 /* saved (callee-save) 7 */
|
#define t8 $24 /* temporary (caller-save) 8 */
|
||||||
#define t8 $24 /* temporary (caller-save) 8 */
|
#define t9 $25 /* temporary (caller-save) 9 */
|
||||||
#define t9 $25 /* temporary (caller-save) 9 */
|
#define k0 $26 /* kernel temporary 0 */
|
||||||
#define k0 $26 /* kernel temporary 0 */
|
#define k1 $27 /* kernel temporary 1 */
|
||||||
#define k1 $27 /* kernel temporary 1 */
|
#define gp $28 /* global pointer */
|
||||||
#define gp $28 /* global pointer */
|
#define sp $29 /* stack pointer */
|
||||||
#define sp $29 /* stack pointer */
|
#define s8 $30 /* saved (callee-save) 8 = frame pointer */
|
||||||
#define s8 $30 /* saved (callee-save) 8 = frame pointer */
|
#define ra $31 /* return address */
|
||||||
#define ra $31 /* return address */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _KERN_MIPS_REGDEFS_H_ */
|
#endif /* _KERN_MIPS_REGDEFS_H_ */
|
||||||
|
|||||||
@@ -38,10 +38,9 @@
|
|||||||
* Must save: s0-s8, sp, ra (11 registers)
|
* Must save: s0-s8, sp, ra (11 registers)
|
||||||
* Don't change __JB_REGS without adjusting mips_setjmp.S accordingly.
|
* 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 */
|
/* A jmp_buf is an array of __JB_REGS registers */
|
||||||
typedef uint32_t jmp_buf[__JB_REGS];
|
typedef uint32_t jmp_buf[__JB_REGS];
|
||||||
|
|
||||||
|
|
||||||
#endif /* _MIPS_SETJMP_H_ */
|
#endif /* _MIPS_SETJMP_H_ */
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef _KERN_MIPS_SIGNAL_H_
|
#ifndef _KERN_MIPS_SIGNAL_H_
|
||||||
#define _KERN_MIPS_SIGNAL_H_
|
#define _KERN_MIPS_SIGNAL_H_
|
||||||
|
|
||||||
@@ -39,7 +38,7 @@
|
|||||||
* probably won't.)
|
* probably won't.)
|
||||||
*/
|
*/
|
||||||
struct sigcontext {
|
struct sigcontext {
|
||||||
/* Dummy. */
|
/* Dummy. */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _KERN_MIPS_SIGNAL_H_ */
|
#endif /* _KERN_MIPS_SIGNAL_H_ */
|
||||||
|
|||||||
@@ -38,21 +38,20 @@
|
|||||||
* See kern/types.h for an explanation of the underscores.
|
* See kern/types.h for an explanation of the underscores.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Sized integer types, with convenient short names */
|
/* Sized integer types, with convenient short names */
|
||||||
typedef char __i8; /* 8-bit signed integer */
|
typedef char __i8; /* 8-bit signed integer */
|
||||||
typedef short __i16; /* 16-bit signed integer */
|
typedef short __i16; /* 16-bit signed integer */
|
||||||
typedef int __i32; /* 32-bit signed integer */
|
typedef int __i32; /* 32-bit signed integer */
|
||||||
typedef long long __i64; /* 64-bit signed integer */
|
typedef long long __i64; /* 64-bit signed integer */
|
||||||
|
|
||||||
typedef unsigned char __u8; /* 8-bit unsigned integer */
|
typedef unsigned char __u8; /* 8-bit unsigned integer */
|
||||||
typedef unsigned short __u16; /* 16-bit unsigned integer */
|
typedef unsigned short __u16; /* 16-bit unsigned integer */
|
||||||
typedef unsigned int __u32; /* 32-bit unsigned integer */
|
typedef unsigned int __u32; /* 32-bit unsigned integer */
|
||||||
typedef unsigned long long __u64; /* 64-bit unsigned integer */
|
typedef unsigned long long __u64; /* 64-bit unsigned integer */
|
||||||
|
|
||||||
/* Further standard C types */
|
/* Further standard C types */
|
||||||
typedef long __intptr_t; /* Signed pointer-sized integer */
|
typedef long __intptr_t; /* Signed pointer-sized integer */
|
||||||
typedef unsigned long __uintptr_t; /* Unsigned 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
|
* 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.
|
* errors involving size_t, try changing this.
|
||||||
*/
|
*/
|
||||||
#if 1
|
#if 1
|
||||||
typedef unsigned __size_t; /* Size of a memory region */
|
typedef unsigned __size_t; /* Size of a memory region */
|
||||||
typedef int __ssize_t; /* Signed type of same size */
|
typedef int __ssize_t; /* Signed type of same size */
|
||||||
typedef int __ptrdiff_t; /* Difference of two pointers */
|
typedef int __ptrdiff_t; /* Difference of two pointers */
|
||||||
#else
|
#else
|
||||||
typedef unsigned long __size_t; /* Size of a memory region */
|
typedef unsigned long __size_t; /* Size of a memory region */
|
||||||
typedef long __ssize_t; /* Signed type of same size */
|
typedef long __ssize_t; /* Signed type of same size */
|
||||||
typedef long __ptrdiff_t; /* Difference of two pointers */
|
typedef long __ptrdiff_t; /* Difference of two pointers */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Number of bits per byte. */
|
/* Number of bits per byte. */
|
||||||
#define __CHAR_BIT 8
|
#define __CHAR_BIT 8
|
||||||
|
|
||||||
|
|
||||||
#endif /* _KERN_MIPS_TYPES_H_ */
|
#endif /* _KERN_MIPS_TYPES_H_ */
|
||||||
|
|||||||
@@ -41,17 +41,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
MEMBAR_INLINE
|
MEMBAR_INLINE
|
||||||
void
|
void membar_any_any(void) {
|
||||||
membar_any_any(void)
|
__asm volatile(".set push;" /* save assembler mode */
|
||||||
{
|
".set mips32;" /* allow MIPS32 instructions */
|
||||||
__asm volatile(
|
"sync;" /* do it */
|
||||||
".set push;" /* save assembler mode */
|
".set pop" /* restore assembler mode */
|
||||||
".set mips32;" /* allow MIPS32 instructions */
|
: /* no outputs */
|
||||||
"sync;" /* do it */
|
: /* no inputs */
|
||||||
".set pop" /* restore assembler mode */
|
: "memory"); /* "changes" memory */
|
||||||
: /* no outputs */
|
|
||||||
: /* no inputs */
|
|
||||||
: "memory"); /* "changes" memory */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MEMBAR_INLINE void membar_load_load(void) { membar_any_any(); }
|
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_store_any(void) { membar_any_any(); }
|
||||||
MEMBAR_INLINE void membar_any_store(void) { membar_any_any(); }
|
MEMBAR_INLINE void membar_any_store(void) { membar_any_any(); }
|
||||||
|
|
||||||
|
|
||||||
#endif /* _MIPS_MEMBAR_H_ */
|
#endif /* _MIPS_MEMBAR_H_ */
|
||||||
|
|||||||
@@ -30,62 +30,61 @@
|
|||||||
#ifndef _MIPS_SPECIALREG_H_
|
#ifndef _MIPS_SPECIALREG_H_
|
||||||
#define _MIPS_SPECIALREG_H_
|
#define _MIPS_SPECIALREG_H_
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Coprocessor 0 (system processor) register numbers
|
* Coprocessor 0 (system processor) register numbers
|
||||||
*/
|
*/
|
||||||
#define c0_index $0 /* TLB entry index register */
|
#define c0_index $0 /* TLB entry index register */
|
||||||
#define c0_random $1 /* TLB random slot register */
|
#define c0_random $1 /* TLB random slot register */
|
||||||
#define c0_entrylo $2 /* TLB entry contents (low-order half) */
|
#define c0_entrylo $2 /* TLB entry contents (low-order half) */
|
||||||
/* c0_entrylo0 $2 */ /* MIPS-II and up only */
|
/* c0_entrylo0 $2 */ /* MIPS-II and up only */
|
||||||
/* c0_entrylo1 $3 */ /* MIPS-II and up only */
|
/* c0_entrylo1 $3 */ /* MIPS-II and up only */
|
||||||
#define c0_context $4 /* some precomputed pagetable stuff */
|
#define c0_context $4 /* some precomputed pagetable stuff */
|
||||||
/* c0_pagemask $5 */ /* MIPS-II and up only */
|
/* c0_pagemask $5 */ /* MIPS-II and up only */
|
||||||
/* c0_wired $6 */ /* 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_vaddr $8 /* virtual addr of failing memory access */
|
||||||
#define c0_count $9 /* cycle counter (MIPS-II and up) */
|
#define c0_count $9 /* cycle counter (MIPS-II and up) */
|
||||||
#define c0_entryhi $10 /* TLB entry contents (high-order half) */
|
#define c0_entryhi $10 /* TLB entry contents (high-order half) */
|
||||||
#define c0_compare $11 /* on-chip timer control (MIPS-II and up) */
|
#define c0_compare $11 /* on-chip timer control (MIPS-II and up) */
|
||||||
#define c0_status $12 /* processor status register */
|
#define c0_status $12 /* processor status register */
|
||||||
#define c0_cause $13 /* exception cause register */
|
#define c0_cause $13 /* exception cause register */
|
||||||
#define c0_epc $14 /* exception PC register */
|
#define c0_epc $14 /* exception PC register */
|
||||||
#define c0_prid $15 /* processor ID register */
|
#define c0_prid $15 /* processor ID register */
|
||||||
/* c0_config $16 */ /* MIPS-II and up only */
|
/* c0_config $16 */ /* MIPS-II and up only */
|
||||||
/* c0_lladdr $17 */ /* MIPS-II and up only */
|
/* c0_lladdr $17 */ /* MIPS-II and up only */
|
||||||
/* c0_watchlo $18 */ /* MIPS-II and up only */
|
/* c0_watchlo $18 */ /* MIPS-II and up only */
|
||||||
/* c0_watchhi $19 */ /* MIPS-II and up only */
|
/* c0_watchhi $19 */ /* MIPS-II and up only */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mode bits in c0_status
|
* Mode bits in c0_status
|
||||||
*/
|
*/
|
||||||
#define CST_IEc 0x00000001 /* current: interrupt enable */
|
#define CST_IEc 0x00000001 /* current: interrupt enable */
|
||||||
#define CST_KUc 0x00000002 /* current: user mode */
|
#define CST_KUc 0x00000002 /* current: user mode */
|
||||||
#define CST_IEp 0x00000004 /* previous: interrupt enable */
|
#define CST_IEp 0x00000004 /* previous: interrupt enable */
|
||||||
#define CST_KUp 0x00000008 /* previous: user mode */
|
#define CST_KUp 0x00000008 /* previous: user mode */
|
||||||
#define CST_IEo 0x00000010 /* old: interrupt enable */
|
#define CST_IEo 0x00000010 /* old: interrupt enable */
|
||||||
#define CST_KUo 0x00000020 /* old: user mode */
|
#define CST_KUo 0x00000020 /* old: user mode */
|
||||||
#define CST_MODEMASK 0x0000003f /* mask for the above */
|
#define CST_MODEMASK 0x0000003f /* mask for the above */
|
||||||
#define CST_IRQMASK 0x0000ff00 /* mask for the individual irq enable bits */
|
#define CST_IRQMASK 0x0000ff00 /* mask for the individual irq enable bits */
|
||||||
#define CST_BEV 0x00400000 /* bootstrap exception vectors flag */
|
#define CST_BEV 0x00400000 /* bootstrap exception vectors flag */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fields of the c0_cause register
|
* Fields of the c0_cause register
|
||||||
*/
|
*/
|
||||||
#define CCA_UTLB 0x00000001 /* true if UTLB exception (set by our asm) */
|
#define CCA_UTLB 0x00000001 /* true if UTLB exception (set by our asm) */
|
||||||
#define CCA_CODE 0x0000003c /* EX_foo in trapframe.h */
|
#define CCA_CODE 0x0000003c /* EX_foo in trapframe.h */
|
||||||
#define CCA_IRQS 0x0000ff00 /* Currently pending interrupts */
|
#define CCA_IRQS 0x0000ff00 /* Currently pending interrupts */
|
||||||
#define CCA_COPN 0x30000000 /* Coprocessor number for EX_CPU */
|
#define CCA_COPN 0x30000000 /* Coprocessor number for EX_CPU */
|
||||||
#define CCA_JD 0x80000000 /* True if exception happened in jump delay */
|
#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
|
* Fields of the c0_index register
|
||||||
*/
|
*/
|
||||||
#define CIN_P 0x80000000 /* nonzero -> TLB probe found nothing */
|
#define CIN_P 0x80000000 /* nonzero -> TLB probe found nothing */
|
||||||
#define CIN_INDEX 0x00003f00 /* 6-bit index into TLB */
|
#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
|
* Fields of the c0_context register
|
||||||
@@ -102,16 +101,15 @@
|
|||||||
* there's no other good place in the chip to put it. See discussions
|
* there's no other good place in the chip to put it. See discussions
|
||||||
* elsewhere.
|
* elsewhere.
|
||||||
*/
|
*/
|
||||||
#define CTX_VSHIFT 0x001ffffc /* shifted/masked copy of c0_vaddr */
|
#define CTX_VSHIFT 0x001ffffc /* shifted/masked copy of c0_vaddr */
|
||||||
#define CTX_PTBASE 0xffe00000 /* page table base address */
|
#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.
|
* Hardwired exception handler addresses.
|
||||||
*/
|
*/
|
||||||
#define EXADDR_UTLB 0x80000000
|
#define EXADDR_UTLB 0x80000000
|
||||||
#define EXADDR_GENERAL 0x80000080
|
#define EXADDR_GENERAL 0x80000080
|
||||||
|
|
||||||
|
|
||||||
#endif /* _MIPS_SPECIALREG_H_ */
|
#endif /* _MIPS_SPECIALREG_H_ */
|
||||||
|
|||||||
@@ -32,12 +32,11 @@
|
|||||||
|
|
||||||
#include <cdefs.h>
|
#include <cdefs.h>
|
||||||
|
|
||||||
|
|
||||||
/* Type of value needed to actually spin on */
|
/* Type of value needed to actually spin on */
|
||||||
typedef unsigned spinlock_data_t;
|
typedef unsigned spinlock_data_t;
|
||||||
|
|
||||||
/* Initializer for use by SPINLOCK_INITIALIZER */
|
/* Initializer for use by SPINLOCK_INITIALIZER */
|
||||||
#define SPINLOCK_DATA_INITIALIZER 0
|
#define SPINLOCK_DATA_INITIALIZER 0
|
||||||
|
|
||||||
/* Atomic operations on spinlock_data_t */
|
/* Atomic operations on spinlock_data_t */
|
||||||
SPINLOCK_INLINE
|
SPINLOCK_INLINE
|
||||||
@@ -55,10 +54,8 @@ spinlock_data_t spinlock_data_testandset(volatile spinlock_data_t *sd);
|
|||||||
* memory.
|
* memory.
|
||||||
*/
|
*/
|
||||||
SPINLOCK_INLINE
|
SPINLOCK_INLINE
|
||||||
void
|
void spinlock_data_set(volatile spinlock_data_t *sd, unsigned val) {
|
||||||
spinlock_data_set(volatile spinlock_data_t *sd, unsigned val)
|
*sd = 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.
|
* instruction, and instructions are atomic with respect to memory.
|
||||||
*/
|
*/
|
||||||
SPINLOCK_INLINE
|
SPINLOCK_INLINE
|
||||||
spinlock_data_t
|
spinlock_data_t spinlock_data_get(volatile spinlock_data_t *sd) { return *sd; }
|
||||||
spinlock_data_get(volatile spinlock_data_t *sd)
|
|
||||||
{
|
|
||||||
return *sd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test-and-set a spinlock_data_t. Use the LL/SC instructions to
|
* 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.
|
* to atomically update one machine word.
|
||||||
*/
|
*/
|
||||||
SPINLOCK_INLINE
|
SPINLOCK_INLINE
|
||||||
spinlock_data_t
|
spinlock_data_t spinlock_data_testandset(volatile spinlock_data_t *sd) {
|
||||||
spinlock_data_testandset(volatile spinlock_data_t *sd)
|
spinlock_data_t x;
|
||||||
{
|
spinlock_data_t y;
|
||||||
spinlock_data_t x;
|
|
||||||
spinlock_data_t y;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test-and-set using LL/SC.
|
* Test-and-set using LL/SC.
|
||||||
*
|
*
|
||||||
* Load the existing value into X, and use Y to store 1.
|
* Load the existing value into X, and use Y to store 1.
|
||||||
* After the SC, Y contains 1 if the store succeeded,
|
* After the SC, Y contains 1 if the store succeeded,
|
||||||
* 0 if it failed.
|
* 0 if it failed.
|
||||||
*
|
*
|
||||||
* On failure, return 1 to pretend that the spinlock
|
* On failure, return 1 to pretend that the spinlock
|
||||||
* was already held.
|
* was already held.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
y = 1;
|
y = 1;
|
||||||
__asm volatile(
|
__asm volatile(".set push;" /* save assembler mode */
|
||||||
".set push;" /* save assembler mode */
|
".set mips32;" /* allow MIPS32 instructions */
|
||||||
".set mips32;" /* allow MIPS32 instructions */
|
".set volatile;" /* avoid unwanted optimization */
|
||||||
".set volatile;" /* avoid unwanted optimization */
|
"ll %0, 0(%2);" /* x = *sd */
|
||||||
"ll %0, 0(%2);" /* x = *sd */
|
"sc %1, 0(%2);" /* *sd = y; y = success? */
|
||||||
"sc %1, 0(%2);" /* *sd = y; y = success? */
|
".set pop" /* restore assembler mode */
|
||||||
".set pop" /* restore assembler mode */
|
: "=&r"(x), "+r"(y)
|
||||||
: "=&r" (x), "+r" (y) : "r" (sd));
|
: "r"(sd));
|
||||||
if (y == 0) {
|
if (y == 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* _MIPS_SPINLOCK_H_ */
|
#endif /* _MIPS_SPINLOCK_H_ */
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
#ifndef _MIPS_THREAD_H_
|
#ifndef _MIPS_THREAD_H_
|
||||||
#define _MIPS_THREAD_H_
|
#define _MIPS_THREAD_H_
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Machine-dependent thread bits.
|
* Machine-dependent thread bits.
|
||||||
*/
|
*/
|
||||||
@@ -40,9 +39,8 @@
|
|||||||
typedef void (*badfaultfunc_t)(void);
|
typedef void (*badfaultfunc_t)(void);
|
||||||
|
|
||||||
struct thread_machdep {
|
struct thread_machdep {
|
||||||
badfaultfunc_t tm_badfaultfunc; /* fault hook used by copyin/out */
|
badfaultfunc_t tm_badfaultfunc; /* fault hook used by copyin/out */
|
||||||
jmp_buf tm_copyjmp; /* longjmp area used by copyin/out */
|
jmp_buf tm_copyjmp; /* longjmp area used by copyin/out */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif /* _MIPS_THREAD_H_ */
|
#endif /* _MIPS_THREAD_H_ */
|
||||||
|
|||||||
@@ -77,14 +77,14 @@ int tlb_probe(uint32_t entryhi, uint32_t entrylo);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Fields in the high-order word */
|
/* Fields in the high-order word */
|
||||||
#define TLBHI_VPAGE 0xfffff000
|
#define TLBHI_VPAGE 0xfffff000
|
||||||
/* TLBHI_PID 0x00000fc0 */
|
/* TLBHI_PID 0x00000fc0 */
|
||||||
|
|
||||||
/* Fields in the low-order word */
|
/* Fields in the low-order word */
|
||||||
#define TLBLO_PPAGE 0xfffff000
|
#define TLBLO_PPAGE 0xfffff000
|
||||||
#define TLBLO_NOCACHE 0x00000800
|
#define TLBLO_NOCACHE 0x00000800
|
||||||
#define TLBLO_DIRTY 0x00000400
|
#define TLBLO_DIRTY 0x00000400
|
||||||
#define TLBLO_VALID 0x00000200
|
#define TLBLO_VALID 0x00000200
|
||||||
/* TLBLO_GLOBAL 0x00000100 */
|
/* 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
|
* be passed to TLBHI_INVALID; this prevents loading the same invalid
|
||||||
* entry into multiple TLB slots.
|
* entry into multiple TLB slots.
|
||||||
*/
|
*/
|
||||||
#define TLBHI_INVALID(entryno) ((0x80000+(entryno))<<12)
|
#define TLBHI_INVALID(entryno) ((0x80000 + (entryno)) << 12)
|
||||||
#define TLBLO_INVALID() (0)
|
#define TLBLO_INVALID() (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of TLB entries in the processor.
|
* Number of TLB entries in the processor.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define NUM_TLB 64
|
#define NUM_TLB 64
|
||||||
|
|
||||||
|
|
||||||
#endif /* _MIPS_TLB_H_ */
|
#endif /* _MIPS_TLB_H_ */
|
||||||
|
|||||||
@@ -38,59 +38,59 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct trapframe {
|
struct trapframe {
|
||||||
uint32_t tf_vaddr; /* coprocessor 0 vaddr register */
|
uint32_t tf_vaddr; /* coprocessor 0 vaddr register */
|
||||||
uint32_t tf_status; /* coprocessor 0 status register */
|
uint32_t tf_status; /* coprocessor 0 status register */
|
||||||
uint32_t tf_cause; /* coprocessor 0 cause register */
|
uint32_t tf_cause; /* coprocessor 0 cause register */
|
||||||
uint32_t tf_lo;
|
uint32_t tf_lo;
|
||||||
uint32_t tf_hi;
|
uint32_t tf_hi;
|
||||||
uint32_t tf_ra; /* Saved register 31 */
|
uint32_t tf_ra; /* Saved register 31 */
|
||||||
uint32_t tf_at; /* Saved register 1 (AT) */
|
uint32_t tf_at; /* Saved register 1 (AT) */
|
||||||
uint32_t tf_v0; /* Saved register 2 (v0) */
|
uint32_t tf_v0; /* Saved register 2 (v0) */
|
||||||
uint32_t tf_v1; /* etc. */
|
uint32_t tf_v1; /* etc. */
|
||||||
uint32_t tf_a0;
|
uint32_t tf_a0;
|
||||||
uint32_t tf_a1;
|
uint32_t tf_a1;
|
||||||
uint32_t tf_a2;
|
uint32_t tf_a2;
|
||||||
uint32_t tf_a3;
|
uint32_t tf_a3;
|
||||||
uint32_t tf_t0;
|
uint32_t tf_t0;
|
||||||
uint32_t tf_t1;
|
uint32_t tf_t1;
|
||||||
uint32_t tf_t2;
|
uint32_t tf_t2;
|
||||||
uint32_t tf_t3;
|
uint32_t tf_t3;
|
||||||
uint32_t tf_t4;
|
uint32_t tf_t4;
|
||||||
uint32_t tf_t5;
|
uint32_t tf_t5;
|
||||||
uint32_t tf_t6;
|
uint32_t tf_t6;
|
||||||
uint32_t tf_t7;
|
uint32_t tf_t7;
|
||||||
uint32_t tf_s0;
|
uint32_t tf_s0;
|
||||||
uint32_t tf_s1;
|
uint32_t tf_s1;
|
||||||
uint32_t tf_s2;
|
uint32_t tf_s2;
|
||||||
uint32_t tf_s3;
|
uint32_t tf_s3;
|
||||||
uint32_t tf_s4;
|
uint32_t tf_s4;
|
||||||
uint32_t tf_s5;
|
uint32_t tf_s5;
|
||||||
uint32_t tf_s6;
|
uint32_t tf_s6;
|
||||||
uint32_t tf_s7;
|
uint32_t tf_s7;
|
||||||
uint32_t tf_t8;
|
uint32_t tf_t8;
|
||||||
uint32_t tf_t9;
|
uint32_t tf_t9;
|
||||||
uint32_t tf_gp;
|
uint32_t tf_gp;
|
||||||
uint32_t tf_sp;
|
uint32_t tf_sp;
|
||||||
uint32_t tf_s8;
|
uint32_t tf_s8;
|
||||||
uint32_t tf_epc; /* coprocessor 0 epc register */
|
uint32_t tf_epc; /* coprocessor 0 epc register */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MIPS exception codes.
|
* MIPS exception codes.
|
||||||
*/
|
*/
|
||||||
#define EX_IRQ 0 /* Interrupt */
|
#define EX_IRQ 0 /* Interrupt */
|
||||||
#define EX_MOD 1 /* TLB Modify (write to read-only page) */
|
#define EX_MOD 1 /* TLB Modify (write to read-only page) */
|
||||||
#define EX_TLBL 2 /* TLB miss on load */
|
#define EX_TLBL 2 /* TLB miss on load */
|
||||||
#define EX_TLBS 3 /* TLB miss on store */
|
#define EX_TLBS 3 /* TLB miss on store */
|
||||||
#define EX_ADEL 4 /* Address error on load */
|
#define EX_ADEL 4 /* Address error on load */
|
||||||
#define EX_ADES 5 /* Address error on store */
|
#define EX_ADES 5 /* Address error on store */
|
||||||
#define EX_IBE 6 /* Bus error on instruction fetch */
|
#define EX_IBE 6 /* Bus error on instruction fetch */
|
||||||
#define EX_DBE 7 /* Bus error on data load *or* store */
|
#define EX_DBE 7 /* Bus error on data load *or* store */
|
||||||
#define EX_SYS 8 /* Syscall */
|
#define EX_SYS 8 /* Syscall */
|
||||||
#define EX_BP 9 /* Breakpoint */
|
#define EX_BP 9 /* Breakpoint */
|
||||||
#define EX_RI 10 /* Reserved (illegal) instruction */
|
#define EX_RI 10 /* Reserved (illegal) instruction */
|
||||||
#define EX_CPU 11 /* Coprocessor unusable */
|
#define EX_CPU 11 /* Coprocessor unusable */
|
||||||
#define EX_OVF 12 /* Arithmetic overflow */
|
#define EX_OVF 12 /* Arithmetic overflow */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function to enter user mode. Does not return. The trapframe must
|
* 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 cpustacks[];
|
||||||
extern vaddr_t cputhreads[];
|
extern vaddr_t cputhreads[];
|
||||||
|
|
||||||
|
|
||||||
#endif /* _MIPS_TRAPFRAME_H_ */
|
#endif /* _MIPS_TRAPFRAME_H_ */
|
||||||
|
|||||||
@@ -30,13 +30,12 @@
|
|||||||
#ifndef _MIPS_VM_H_
|
#ifndef _MIPS_VM_H_
|
||||||
#define _MIPS_VM_H_
|
#define _MIPS_VM_H_
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Machine-dependent VM system definitions.
|
* Machine-dependent VM system definitions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PAGE_SIZE 4096 /* size of VM page */
|
#define PAGE_SIZE 4096 /* size of VM page */
|
||||||
#define PAGE_FRAME 0xfffff000 /* mask for getting page number from addr */
|
#define PAGE_FRAME 0xfffff000 /* mask for getting page number from addr */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MIPS-I hardwired memory layout:
|
* MIPS-I hardwired memory layout:
|
||||||
@@ -48,10 +47,10 @@
|
|||||||
* (mips32 is a little different)
|
* (mips32 is a little different)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MIPS_KUSEG 0x00000000
|
#define MIPS_KUSEG 0x00000000
|
||||||
#define MIPS_KSEG0 0x80000000
|
#define MIPS_KSEG0 0x80000000
|
||||||
#define MIPS_KSEG1 0xa0000000
|
#define MIPS_KSEG1 0xa0000000
|
||||||
#define MIPS_KSEG2 0xc0000000
|
#define MIPS_KSEG2 0xc0000000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The first 512 megs of physical space can be addressed in both kseg0 and
|
* 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*
|
* 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.
|
* 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
|
* The top of user space. (Actually, the address immediately above the
|
||||||
* last valid user address.)
|
* last valid user address.)
|
||||||
*/
|
*/
|
||||||
#define USERSPACETOP MIPS_KSEG0
|
#define USERSPACETOP MIPS_KSEG0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The starting value for the stack pointer at user level. Because
|
* 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
|
* We put the stack at the very top of user virtual memory because it
|
||||||
* grows downwards.
|
* grows downwards.
|
||||||
*/
|
*/
|
||||||
#define USERSTACK USERSPACETOP
|
#define USERSTACK USERSPACETOP
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Interface to the low-level module that looks after the amount of
|
* Interface to the low-level module that looks after the amount of
|
||||||
@@ -117,13 +116,12 @@ paddr_t ram_getfirstfree(void);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct tlbshootdown {
|
struct tlbshootdown {
|
||||||
/*
|
/*
|
||||||
* Change this to what you need for your VM design.
|
* Change this to what you need for your VM design.
|
||||||
*/
|
*/
|
||||||
int ts_placeholder;
|
int ts_placeholder;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TLBSHOOTDOWN_MAX 16
|
#define TLBSHOOTDOWN_MAX 16
|
||||||
|
|
||||||
|
|
||||||
#endif /* _MIPS_VM_H_ */
|
#endif /* _MIPS_VM_H_ */
|
||||||
|
|||||||
@@ -40,81 +40,68 @@
|
|||||||
#include <mainbus.h>
|
#include <mainbus.h>
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
|
|
||||||
|
|
||||||
/* in exception-*.S */
|
/* in exception-*.S */
|
||||||
extern __DEAD void asm_usermode(struct trapframe *tf);
|
extern __DEAD void asm_usermode(struct trapframe *tf);
|
||||||
|
|
||||||
/* called only from assembler, so not declared in a header */
|
/* called only from assembler, so not declared in a header */
|
||||||
void mips_trap(struct trapframe *tf);
|
void mips_trap(struct trapframe *tf);
|
||||||
|
|
||||||
|
|
||||||
/* Names for trap codes */
|
/* Names for trap codes */
|
||||||
#define NTRAPCODES 13
|
#define NTRAPCODES 13
|
||||||
static const char *const trapcodenames[NTRAPCODES] = {
|
static const char *const trapcodenames[NTRAPCODES] = {
|
||||||
"Interrupt",
|
"Interrupt", "TLB modify trap", "TLB miss on load",
|
||||||
"TLB modify trap",
|
"TLB miss on store", "Address error on load", "Address error on store",
|
||||||
"TLB miss on load",
|
"Bus error on code", "Bus error on data", "System call",
|
||||||
"TLB miss on store",
|
"Break instruction", "Illegal instruction", "Coprocessor unusable",
|
||||||
"Address error on load",
|
"Arithmetic overflow",
|
||||||
"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.
|
* Function called when user-level code hits a fatal fault.
|
||||||
*/
|
*/
|
||||||
static
|
static void kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr) {
|
||||||
void
|
int sig = 0;
|
||||||
kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr)
|
|
||||||
{
|
|
||||||
int sig = 0;
|
|
||||||
|
|
||||||
KASSERT(code < NTRAPCODES);
|
KASSERT(code < NTRAPCODES);
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case EX_IRQ:
|
case EX_IRQ:
|
||||||
case EX_IBE:
|
case EX_IBE:
|
||||||
case EX_DBE:
|
case EX_DBE:
|
||||||
case EX_SYS:
|
case EX_SYS:
|
||||||
/* should not be seen */
|
/* should not be seen */
|
||||||
KASSERT(0);
|
KASSERT(0);
|
||||||
sig = SIGABRT;
|
sig = SIGABRT;
|
||||||
break;
|
break;
|
||||||
case EX_MOD:
|
case EX_MOD:
|
||||||
case EX_TLBL:
|
case EX_TLBL:
|
||||||
case EX_TLBS:
|
case EX_TLBS:
|
||||||
sig = SIGSEGV;
|
sig = SIGSEGV;
|
||||||
break;
|
break;
|
||||||
case EX_ADEL:
|
case EX_ADEL:
|
||||||
case EX_ADES:
|
case EX_ADES:
|
||||||
sig = SIGBUS;
|
sig = SIGBUS;
|
||||||
break;
|
break;
|
||||||
case EX_BP:
|
case EX_BP:
|
||||||
sig = SIGTRAP;
|
sig = SIGTRAP;
|
||||||
break;
|
break;
|
||||||
case EX_RI:
|
case EX_RI:
|
||||||
sig = SIGILL;
|
sig = SIGILL;
|
||||||
break;
|
break;
|
||||||
case EX_CPU:
|
case EX_CPU:
|
||||||
sig = SIGSEGV;
|
sig = SIGSEGV;
|
||||||
break;
|
break;
|
||||||
case EX_OVF:
|
case EX_OVF:
|
||||||
sig = SIGFPE;
|
sig = SIGFPE;
|
||||||
break;
|
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",
|
kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n", code,
|
||||||
code, sig, trapcodenames[code], epc, vaddr);
|
sig, trapcodenames[code], epc, vaddr);
|
||||||
panic("I don't know how to handle this\n");
|
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
|
* This is called by the assembly-language exception handler once
|
||||||
* the trapframe has been set up.
|
* the trapframe has been set up.
|
||||||
*/
|
*/
|
||||||
void
|
void mips_trap(struct trapframe *tf) {
|
||||||
mips_trap(struct trapframe *tf)
|
uint32_t code;
|
||||||
{
|
/*bool isutlb; -- not used */
|
||||||
uint32_t code;
|
bool iskern;
|
||||||
/*bool isutlb; -- not used */
|
int spl;
|
||||||
bool iskern;
|
|
||||||
int spl;
|
|
||||||
|
|
||||||
/* The trap frame is supposed to be 35 registers long. */
|
/* The trap frame is supposed to be 35 registers long. */
|
||||||
KASSERT(sizeof(struct trapframe)==(35*4));
|
KASSERT(sizeof(struct trapframe) == (35 * 4));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract the exception code info from the register fields.
|
* Extract the exception code info from the register fields.
|
||||||
*/
|
*/
|
||||||
code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT;
|
code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT;
|
||||||
/*isutlb = (tf->tf_cause & CCA_UTLB) != 0;*/
|
/*isutlb = (tf->tf_cause & CCA_UTLB) != 0;*/
|
||||||
iskern = (tf->tf_status & CST_KUp) == 0;
|
iskern = (tf->tf_status & CST_KUp) == 0;
|
||||||
|
|
||||||
KASSERT(code < NTRAPCODES);
|
KASSERT(code < NTRAPCODES);
|
||||||
|
|
||||||
/* Make sure we haven't run off our stack */
|
/* Make sure we haven't run off our stack */
|
||||||
if (curthread != NULL && curthread->t_stack != NULL) {
|
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);
|
||||||
KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack
|
KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack + STACK_SIZE));
|
||||||
+ STACK_SIZE));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Interrupt? Call the interrupt handler and return. */
|
/* Interrupt? Call the interrupt handler and return. */
|
||||||
if (code == EX_IRQ) {
|
if (code == EX_IRQ) {
|
||||||
int old_in;
|
int old_in;
|
||||||
bool doadjust;
|
bool doadjust;
|
||||||
|
|
||||||
old_in = curthread->t_in_interrupt;
|
old_in = curthread->t_in_interrupt;
|
||||||
curthread->t_in_interrupt = 1;
|
curthread->t_in_interrupt = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The processor has turned interrupts off; if the
|
* The processor has turned interrupts off; if the
|
||||||
* currently recorded interrupt state is interrupts on
|
* currently recorded interrupt state is interrupts on
|
||||||
* (spl of 0), adjust the recorded state to match, and
|
* (spl of 0), adjust the recorded state to match, and
|
||||||
* restore after processing the interrupt.
|
* restore after processing the interrupt.
|
||||||
*
|
*
|
||||||
* How can we get an interrupt if the recorded state
|
* How can we get an interrupt if the recorded state
|
||||||
* is interrupts off? Well, as things currently stand
|
* is interrupts off? Well, as things currently stand
|
||||||
* when the CPU finishes idling it flips interrupts on
|
* when the CPU finishes idling it flips interrupts on
|
||||||
* and off to allow things to happen, but leaves
|
* and off to allow things to happen, but leaves
|
||||||
* curspl high while doing so.
|
* curspl high while doing so.
|
||||||
*
|
*
|
||||||
* While we're here, assert that the interrupt
|
* While we're here, assert that the interrupt
|
||||||
* handling code hasn't leaked a spinlock or an
|
* handling code hasn't leaked a spinlock or an
|
||||||
* splhigh().
|
* splhigh().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (curthread->t_curspl == 0) {
|
if (curthread->t_curspl == 0) {
|
||||||
KASSERT(curthread->t_curspl == 0);
|
KASSERT(curthread->t_curspl == 0);
|
||||||
KASSERT(curthread->t_iplhigh_count == 0);
|
KASSERT(curthread->t_iplhigh_count == 0);
|
||||||
curthread->t_curspl = IPL_HIGH;
|
curthread->t_curspl = IPL_HIGH;
|
||||||
curthread->t_iplhigh_count++;
|
curthread->t_iplhigh_count++;
|
||||||
doadjust = true;
|
doadjust = true;
|
||||||
}
|
} else {
|
||||||
else {
|
doadjust = false;
|
||||||
doadjust = false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
mainbus_interrupt(tf);
|
mainbus_interrupt(tf);
|
||||||
|
|
||||||
if (doadjust) {
|
if (doadjust) {
|
||||||
KASSERT(curthread->t_curspl == IPL_HIGH);
|
KASSERT(curthread->t_curspl == IPL_HIGH);
|
||||||
KASSERT(curthread->t_iplhigh_count == 1);
|
KASSERT(curthread->t_iplhigh_count == 1);
|
||||||
curthread->t_iplhigh_count--;
|
curthread->t_iplhigh_count--;
|
||||||
curthread->t_curspl = 0;
|
curthread->t_curspl = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
curthread->t_in_interrupt = old_in;
|
curthread->t_in_interrupt = old_in;
|
||||||
goto done2;
|
goto done2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The processor turned interrupts off when it took the trap.
|
* The processor turned interrupts off when it took the trap.
|
||||||
*
|
*
|
||||||
* While we're in the kernel, and not actually handling an
|
* While we're in the kernel, and not actually handling an
|
||||||
* interrupt, restore the interrupt state to where it was in
|
* interrupt, restore the interrupt state to where it was in
|
||||||
* the previous context, which may be low (interrupts on).
|
* the previous context, which may be low (interrupts on).
|
||||||
*
|
*
|
||||||
* Do this by forcing splhigh(), which may do a redundant
|
* Do this by forcing splhigh(), which may do a redundant
|
||||||
* cpu_irqoff() but forces the stored MI interrupt state into
|
* cpu_irqoff() but forces the stored MI interrupt state into
|
||||||
* sync, then restoring the previous state.
|
* sync, then restoring the previous state.
|
||||||
*/
|
*/
|
||||||
spl = splhigh();
|
spl = splhigh();
|
||||||
splx(spl);
|
splx(spl);
|
||||||
|
|
||||||
/* Syscall? Call the syscall handler and return. */
|
/* Syscall? Call the syscall handler and return. */
|
||||||
if (code == EX_SYS) {
|
if (code == EX_SYS) {
|
||||||
/* Interrupts should have been on while in user mode. */
|
/* Interrupts should have been on while in user mode. */
|
||||||
KASSERT(curthread->t_curspl == 0);
|
KASSERT(curthread->t_curspl == 0);
|
||||||
KASSERT(curthread->t_iplhigh_count == 0);
|
KASSERT(curthread->t_iplhigh_count == 0);
|
||||||
|
|
||||||
DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n",
|
DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n", tf->tf_v0, tf->tf_a0,
|
||||||
tf->tf_v0, tf->tf_a0, tf->tf_a1, tf->tf_a2, tf->tf_a3);
|
tf->tf_a1, tf->tf_a2, tf->tf_a3);
|
||||||
|
|
||||||
syscall(tf);
|
syscall(tf);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ok, it wasn't any of the really easy cases.
|
* Ok, it wasn't any of the really easy cases.
|
||||||
* Call vm_fault on the TLB exceptions.
|
* Call vm_fault on the TLB exceptions.
|
||||||
* Panic on the bus error exceptions.
|
* Panic on the bus error exceptions.
|
||||||
*/
|
*/
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case EX_MOD:
|
case EX_MOD:
|
||||||
if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr)==0) {
|
if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr) == 0) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EX_TLBL:
|
case EX_TLBL:
|
||||||
if (vm_fault(VM_FAULT_READ, tf->tf_vaddr)==0) {
|
if (vm_fault(VM_FAULT_READ, tf->tf_vaddr) == 0) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EX_TLBS:
|
case EX_TLBS:
|
||||||
if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr)==0) {
|
if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr) == 0) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EX_IBE:
|
case EX_IBE:
|
||||||
case EX_DBE:
|
case EX_DBE:
|
||||||
/*
|
/*
|
||||||
* This means you loaded invalid TLB entries, or
|
* This means you loaded invalid TLB entries, or
|
||||||
* touched invalid parts of the direct-mapped
|
* touched invalid parts of the direct-mapped
|
||||||
* segments. These are serious kernel errors, so
|
* segments. These are serious kernel errors, so
|
||||||
* panic.
|
* panic.
|
||||||
*
|
*
|
||||||
* The MIPS won't even tell you what invalid address
|
* The MIPS won't even tell you what invalid address
|
||||||
* caused the bus error.
|
* caused the bus error.
|
||||||
*/
|
*/
|
||||||
panic("Bus error exception, PC=0x%x\n", tf->tf_epc);
|
panic("Bus error exception, PC=0x%x\n", tf->tf_epc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we get to this point, it's a fatal fault - either it's
|
* If we get to this point, it's a fatal fault - either it's
|
||||||
* one of the other exceptions, like illegal instruction, or
|
* one of the other exceptions, like illegal instruction, or
|
||||||
* it was a page fault we couldn't handle.
|
* it was a page fault we couldn't handle.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!iskern) {
|
if (!iskern) {
|
||||||
/*
|
/*
|
||||||
* Fatal fault in user mode.
|
* Fatal fault in user mode.
|
||||||
* Kill the current user process.
|
* Kill the current user process.
|
||||||
*/
|
*/
|
||||||
kill_curthread(tf->tf_epc, code, tf->tf_vaddr);
|
kill_curthread(tf->tf_epc, code, tf->tf_vaddr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fatal fault in kernel mode.
|
* Fatal fault in kernel mode.
|
||||||
*
|
*
|
||||||
* If pcb_badfaultfunc is set, we do not panic; badfaultfunc is
|
* If pcb_badfaultfunc is set, we do not panic; badfaultfunc is
|
||||||
* set by copyin/copyout and related functions to signify that
|
* set by copyin/copyout and related functions to signify that
|
||||||
* the addresses they're accessing are userlevel-supplied and
|
* the addresses they're accessing are userlevel-supplied and
|
||||||
* not trustable. What we actually want to do is resume
|
* not trustable. What we actually want to do is resume
|
||||||
* execution at the function pointed to by badfaultfunc. That's
|
* execution at the function pointed to by badfaultfunc. That's
|
||||||
* going to be "copyfail" (see copyinout.c), which longjmps
|
* going to be "copyfail" (see copyinout.c), which longjmps
|
||||||
* back to copyin/copyout or wherever and returns EFAULT.
|
* back to copyin/copyout or wherever and returns EFAULT.
|
||||||
*
|
*
|
||||||
* Note that we do not just *call* this function, because that
|
* Note that we do not just *call* this function, because that
|
||||||
* won't necessarily do anything. We want the control flow
|
* won't necessarily do anything. We want the control flow
|
||||||
* that is currently executing in copyin (or whichever), and
|
* that is currently executing in copyin (or whichever), and
|
||||||
* is stopped while we process the exception, to *teleport* to
|
* is stopped while we process the exception, to *teleport* to
|
||||||
* copyfail.
|
* copyfail.
|
||||||
*
|
*
|
||||||
* This is accomplished by changing tf->tf_epc and returning
|
* This is accomplished by changing tf->tf_epc and returning
|
||||||
* from the exception handler.
|
* from the exception handler.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (curthread != NULL &&
|
if (curthread != NULL && curthread->t_machdep.tm_badfaultfunc != NULL) {
|
||||||
curthread->t_machdep.tm_badfaultfunc != NULL) {
|
tf->tf_epc = (vaddr_t)curthread->t_machdep.tm_badfaultfunc;
|
||||||
tf->tf_epc = (vaddr_t) curthread->t_machdep.tm_badfaultfunc;
|
goto done;
|
||||||
goto done;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Really fatal kernel-mode fault.
|
* Really fatal kernel-mode fault.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code,
|
kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code,
|
||||||
trapcodenames[code]);
|
trapcodenames[code]);
|
||||||
kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n",
|
kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n", tf->tf_epc, tf->tf_vaddr);
|
||||||
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:
|
done:
|
||||||
/*
|
/*
|
||||||
* Turn interrupts off on the processor, without affecting the
|
* Turn interrupts off on the processor, without affecting the
|
||||||
* stored interrupt state.
|
* stored interrupt state.
|
||||||
*/
|
*/
|
||||||
cpu_irqoff();
|
cpu_irqoff();
|
||||||
done2:
|
done2:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The boot thread can get here (e.g. on interrupt return) but
|
* 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
|
* since it doesn't go to userlevel, it can't be returning to
|
||||||
* userlevel, so there's no need to set cputhreads[] and
|
* userlevel, so there's no need to set cputhreads[] and
|
||||||
* cpustacks[]. Just return.
|
* cpustacks[]. Just return.
|
||||||
*/
|
*/
|
||||||
if (curthread->t_stack == NULL) {
|
if (curthread->t_stack == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
||||||
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This assertion will fail if either
|
* This assertion will fail if either
|
||||||
* (1) curthread->t_stack is corrupted, or
|
* (1) curthread->t_stack is corrupted, or
|
||||||
* (2) the trap frame is somehow on the wrong kernel stack.
|
* (2) the trap frame is somehow on the wrong kernel stack.
|
||||||
*
|
*
|
||||||
* If cpustacks[] is corrupted, the next trap back to the
|
* If cpustacks[] is corrupted, the next trap back to the
|
||||||
* kernel will (most likely) hang the system, so it's better
|
* kernel will (most likely) hang the system, so it's better
|
||||||
* to find out now.
|
* to find out now.
|
||||||
*/
|
*/
|
||||||
KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
|
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_new_process, for use by exec and equivalent.
|
||||||
* - enter_forked_process, in syscall.c, for use by fork.
|
* - enter_forked_process, in syscall.c, for use by fork.
|
||||||
*/
|
*/
|
||||||
void
|
void mips_usermode(struct trapframe *tf) {
|
||||||
mips_usermode(struct trapframe *tf)
|
|
||||||
{
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Interrupts should be off within the kernel while entering
|
* Interrupts should be off within the kernel while entering
|
||||||
* user mode. However, while in user mode, interrupts should
|
* user mode. However, while in user mode, interrupts should
|
||||||
* be on. To interact properly with the spl-handling logic
|
* be on. To interact properly with the spl-handling logic
|
||||||
* above, we explicitly call spl0() and then call cpu_irqoff().
|
* above, we explicitly call spl0() and then call cpu_irqoff().
|
||||||
*/
|
*/
|
||||||
spl0();
|
spl0();
|
||||||
cpu_irqoff();
|
cpu_irqoff();
|
||||||
|
|
||||||
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
||||||
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This assertion will fail if either
|
* This assertion will fail if either
|
||||||
* (1) cpustacks[] is corrupted, or
|
* (1) cpustacks[] is corrupted, or
|
||||||
* (2) the trap frame is not on our own kernel stack, or
|
* (2) the trap frame is not on our own kernel stack, or
|
||||||
* (3) the boot thread tries to enter user mode.
|
* (3) the boot thread tries to enter user mode.
|
||||||
*
|
*
|
||||||
* If cpustacks[] is corrupted, the next trap back to the
|
* If cpustacks[] is corrupted, the next trap back to the
|
||||||
* kernel will (most likely) hang the system, so it's better
|
* kernel will (most likely) hang the system, so it's better
|
||||||
* to find out now.
|
* to find out now.
|
||||||
*
|
*
|
||||||
* It's necessary for the trap frame used here to be on the
|
* It's necessary for the trap frame used here to be on the
|
||||||
* current thread's own stack. It cannot correctly be on
|
* current thread's own stack. It cannot correctly be on
|
||||||
* either another thread's stack or in the kernel heap.
|
* either another thread's stack or in the kernel heap.
|
||||||
* (Exercise: why?)
|
* (Exercise: why?)
|
||||||
*/
|
*/
|
||||||
KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
|
KASSERT(SAME_STACK(cpustacks[curcpu->c_number] - 1, (vaddr_t)tf));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This actually does it. See exception-*.S.
|
* This actually does it. See exception-*.S.
|
||||||
*/
|
*/
|
||||||
asm_usermode(tf);
|
asm_usermode(tf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -419,20 +398,18 @@ mips_usermode(struct trapframe *tf)
|
|||||||
*
|
*
|
||||||
* Works by creating an ersatz trapframe.
|
* Works by creating an ersatz trapframe.
|
||||||
*/
|
*/
|
||||||
void
|
void enter_new_process(int argc, userptr_t argv, userptr_t env, vaddr_t stack,
|
||||||
enter_new_process(int argc, userptr_t argv, userptr_t env,
|
vaddr_t entry) {
|
||||||
vaddr_t stack, vaddr_t entry)
|
struct trapframe tf;
|
||||||
{
|
|
||||||
struct trapframe tf;
|
|
||||||
|
|
||||||
bzero(&tf, sizeof(tf));
|
bzero(&tf, sizeof(tf));
|
||||||
|
|
||||||
tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp;
|
tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp;
|
||||||
tf.tf_epc = entry;
|
tf.tf_epc = entry;
|
||||||
tf.tf_a0 = argc;
|
tf.tf_a0 = argc;
|
||||||
tf.tf_a1 = (vaddr_t)argv;
|
tf.tf_a1 = (vaddr_t)argv;
|
||||||
tf.tf_a2 = (vaddr_t)env;
|
tf.tf_a2 = (vaddr_t)env;
|
||||||
tf.tf_sp = stack;
|
tf.tf_sp = stack;
|
||||||
|
|
||||||
mips_usermode(&tf);
|
mips_usermode(&tf);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,6 @@
|
|||||||
#include <current.h>
|
#include <current.h>
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* System call dispatcher.
|
* System call dispatcher.
|
||||||
*
|
*
|
||||||
@@ -75,75 +74,70 @@
|
|||||||
* stack, starting at sp+16 to skip over the slots for the
|
* stack, starting at sp+16 to skip over the slots for the
|
||||||
* registerized values, with copyin().
|
* registerized values, with copyin().
|
||||||
*/
|
*/
|
||||||
void
|
void syscall(struct trapframe *tf) {
|
||||||
syscall(struct trapframe *tf)
|
int callno;
|
||||||
{
|
int32_t retval;
|
||||||
int callno;
|
int err;
|
||||||
int32_t retval;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
KASSERT(curthread != NULL);
|
KASSERT(curthread != NULL);
|
||||||
KASSERT(curthread->t_curspl == 0);
|
KASSERT(curthread->t_curspl == 0);
|
||||||
KASSERT(curthread->t_iplhigh_count == 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
|
* Initialize retval to 0. Many of the system calls don't
|
||||||
* really return a value, just 0 for success and -1 on
|
* really return a value, just 0 for success and -1 on
|
||||||
* error. Since retval is the value returned on success,
|
* error. Since retval is the value returned on success,
|
||||||
* initialize it to 0 by default; thus it's not necessary to
|
* initialize it to 0 by default; thus it's not necessary to
|
||||||
* deal with it except for calls that return other values,
|
* deal with it except for calls that return other values,
|
||||||
* like write.
|
* like write.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
||||||
switch (callno) {
|
switch (callno) {
|
||||||
case SYS_reboot:
|
case SYS_reboot:
|
||||||
err = sys_reboot(tf->tf_a0);
|
err = sys_reboot(tf->tf_a0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYS___time:
|
case SYS___time:
|
||||||
err = sys___time((userptr_t)tf->tf_a0,
|
err = sys___time((userptr_t)tf->tf_a0, (userptr_t)tf->tf_a1);
|
||||||
(userptr_t)tf->tf_a1);
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
/* Add stuff here */
|
/* Add stuff here */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
kprintf("Unknown syscall %d\n", callno);
|
kprintf("Unknown syscall %d\n", callno);
|
||||||
err = ENOSYS;
|
err = ENOSYS;
|
||||||
break;
|
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) {
|
/*
|
||||||
/*
|
* Now, advance the program counter, to avoid restarting
|
||||||
* Return the error code. This gets converted at
|
* the syscall over and over again.
|
||||||
* 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 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
tf->tf_epc += 4;
|
||||||
* Now, advance the program counter, to avoid restarting
|
|
||||||
* the syscall over and over again.
|
|
||||||
*/
|
|
||||||
|
|
||||||
tf->tf_epc += 4;
|
/* Make sure the syscall code didn't forget to lower spl */
|
||||||
|
KASSERT(curthread->t_curspl == 0);
|
||||||
/* Make sure the syscall code didn't forget to lower spl */
|
/* ...or leak any spinlocks */
|
||||||
KASSERT(curthread->t_curspl == 0);
|
KASSERT(curthread->t_iplhigh_count == 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.
|
* Thus, you can trash it and do things another way if you prefer.
|
||||||
*/
|
*/
|
||||||
void
|
void enter_forked_process(struct trapframe *tf) { (void)tf; }
|
||||||
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
|
* associated with a new cpu. Note that we're not running on the new
|
||||||
* cpu when this is called.
|
* cpu when this is called.
|
||||||
*/
|
*/
|
||||||
void
|
void cpu_machdep_init(struct cpu *c) {
|
||||||
cpu_machdep_init(struct cpu *c)
|
vaddr_t stackpointer;
|
||||||
{
|
|
||||||
vaddr_t stackpointer;
|
|
||||||
|
|
||||||
KASSERT(c->c_number < MAXCPUS);
|
KASSERT(c->c_number < MAXCPUS);
|
||||||
|
|
||||||
if (c->c_curthread->t_stack == NULL) {
|
if (c->c_curthread->t_stack == NULL) {
|
||||||
/* boot cpu; don't need to do anything here */
|
/* boot cpu; don't need to do anything here */
|
||||||
}
|
} else {
|
||||||
else {
|
/*
|
||||||
/*
|
* Stick the stack in cpustacks[], and thread pointer
|
||||||
* Stick the stack in cpustacks[], and thread pointer
|
* in cputhreads[].
|
||||||
* in cputhreads[].
|
*/
|
||||||
*/
|
|
||||||
|
|
||||||
/* stack base address */
|
/* stack base address */
|
||||||
stackpointer = (vaddr_t) c->c_curthread->t_stack;
|
stackpointer = (vaddr_t)c->c_curthread->t_stack;
|
||||||
/* since stacks grow down, get the top */
|
/* since stacks grow down, get the top */
|
||||||
stackpointer += STACK_SIZE;
|
stackpointer += STACK_SIZE;
|
||||||
|
|
||||||
cpustacks[c->c_number] = stackpointer;
|
cpustacks[c->c_number] = stackpointer;
|
||||||
cputhreads[c->c_number] = (vaddr_t)c->c_curthread;
|
cputhreads[c->c_number] = (vaddr_t)c->c_curthread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@@ -107,73 +104,61 @@ cpu_machdep_init(struct cpu *c)
|
|||||||
* System/161 processor-ID values.
|
* System/161 processor-ID values.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SYS161_PRID_ORIG 0x000003ff
|
#define SYS161_PRID_ORIG 0x000003ff
|
||||||
#define SYS161_PRID_2X 0x000000a1
|
#define SYS161_PRID_2X 0x000000a1
|
||||||
|
|
||||||
static inline
|
static inline uint32_t cpu_getprid(void) {
|
||||||
uint32_t
|
uint32_t prid;
|
||||||
cpu_getprid(void)
|
|
||||||
{
|
|
||||||
uint32_t prid;
|
|
||||||
|
|
||||||
__asm volatile("mfc0 %0,$15" : "=r" (prid));
|
__asm volatile("mfc0 %0,$15" : "=r"(prid));
|
||||||
return prid;
|
return prid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline uint32_t cpu_getfeatures(void) {
|
||||||
uint32_t
|
uint32_t features;
|
||||||
cpu_getfeatures(void)
|
|
||||||
{
|
|
||||||
uint32_t features;
|
|
||||||
|
|
||||||
__asm volatile(".set push;" /* save assembler mode */
|
__asm volatile(".set push;" /* save assembler mode */
|
||||||
".set mips32;" /* allow mips32 instructions */
|
".set mips32;" /* allow mips32 instructions */
|
||||||
"mfc0 %0,$15,1;" /* get cop0 reg 15 sel 1 */
|
"mfc0 %0,$15,1;" /* get cop0 reg 15 sel 1 */
|
||||||
".set pop" /* restore assembler mode */
|
".set pop" /* restore assembler mode */
|
||||||
: "=r" (features));
|
: "=r"(features));
|
||||||
return features;
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline uint32_t cpu_getifeatures(void) {
|
||||||
uint32_t
|
uint32_t features;
|
||||||
cpu_getifeatures(void)
|
|
||||||
{
|
|
||||||
uint32_t features;
|
|
||||||
|
|
||||||
__asm volatile(".set push;" /* save assembler mode */
|
__asm volatile(".set push;" /* save assembler mode */
|
||||||
".set mips32;" /* allow mips32 instructions */
|
".set mips32;" /* allow mips32 instructions */
|
||||||
"mfc0 %0,$15,2;" /* get cop0 reg 15 sel 2 */
|
"mfc0 %0,$15,2;" /* get cop0 reg 15 sel 2 */
|
||||||
".set pop" /* restore assembler mode */
|
".set pop" /* restore assembler mode */
|
||||||
: "=r" (features));
|
: "=r"(features));
|
||||||
return features;
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void cpu_identify(char *buf, size_t max) {
|
||||||
cpu_identify(char *buf, size_t max)
|
uint32_t prid;
|
||||||
{
|
uint32_t features;
|
||||||
uint32_t prid;
|
|
||||||
uint32_t features;
|
|
||||||
|
|
||||||
prid = cpu_getprid();
|
prid = cpu_getprid();
|
||||||
switch (prid) {
|
switch (prid) {
|
||||||
case SYS161_PRID_ORIG:
|
case SYS161_PRID_ORIG:
|
||||||
snprintf(buf, max, "MIPS/161 (System/161 1.x and pre-2.x)");
|
snprintf(buf, max, "MIPS/161 (System/161 1.x and pre-2.x)");
|
||||||
break;
|
break;
|
||||||
case SYS161_PRID_2X:
|
case SYS161_PRID_2X:
|
||||||
features = cpu_getfeatures();
|
features = cpu_getfeatures();
|
||||||
snprintf(buf, max, "MIPS/161 (System/161 2.x) features 0x%x",
|
snprintf(buf, max, "MIPS/161 (System/161 2.x) features 0x%x", features);
|
||||||
features);
|
features = cpu_getifeatures();
|
||||||
features = cpu_getifeatures();
|
if (features != 0) {
|
||||||
if (features != 0) {
|
kprintf("WARNING: unknown CPU incompatible features "
|
||||||
kprintf("WARNING: unknown CPU incompatible features "
|
"0x%x\n",
|
||||||
"0x%x\n", features);
|
features);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
snprintf(buf, max, "32-bit MIPS (unknown type, CPU ID 0x%x)",
|
snprintf(buf, max, "32-bit MIPS (unknown type, CPU ID 0x%x)", prid);
|
||||||
prid);
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@@ -200,50 +185,43 @@ cpu_identify(char *buf, size_t max)
|
|||||||
* These considerations do not (currently) apply to System/161,
|
* These considerations do not (currently) apply to System/161,
|
||||||
* however.
|
* however.
|
||||||
*/
|
*/
|
||||||
#define GET_STATUS(x) __asm volatile("mfc0 %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))
|
#define SET_STATUS(x) __asm volatile("mtc0 %0,$12" ::"r"(x))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Interrupts on.
|
* Interrupts on.
|
||||||
*/
|
*/
|
||||||
void
|
void cpu_irqon(void) {
|
||||||
cpu_irqon(void)
|
uint32_t x;
|
||||||
{
|
|
||||||
uint32_t x;
|
|
||||||
|
|
||||||
GET_STATUS(x);
|
GET_STATUS(x);
|
||||||
x |= CST_IEc;
|
x |= CST_IEc;
|
||||||
SET_STATUS(x);
|
SET_STATUS(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Interrupts off.
|
* Interrupts off.
|
||||||
*/
|
*/
|
||||||
void
|
void cpu_irqoff(void) {
|
||||||
cpu_irqoff(void)
|
uint32_t x;
|
||||||
{
|
|
||||||
uint32_t x;
|
|
||||||
|
|
||||||
GET_STATUS(x);
|
GET_STATUS(x);
|
||||||
x &= ~(uint32_t)CST_IEc;
|
x &= ~(uint32_t)CST_IEc;
|
||||||
SET_STATUS(x);
|
SET_STATUS(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used below.
|
* Used below.
|
||||||
*/
|
*/
|
||||||
static
|
static void cpu_irqonoff(void) {
|
||||||
void
|
uint32_t x, xon, xoff;
|
||||||
cpu_irqonoff(void)
|
|
||||||
{
|
|
||||||
uint32_t x, xon, xoff;
|
|
||||||
|
|
||||||
GET_STATUS(x);
|
GET_STATUS(x);
|
||||||
xon = x | CST_IEc;
|
xon = x | CST_IEc;
|
||||||
xoff = x & ~(uint32_t)CST_IEc;
|
xoff = x & ~(uint32_t)CST_IEc;
|
||||||
SET_STATUS(xon);
|
SET_STATUS(xon);
|
||||||
__asm volatile("nop; nop; nop; nop");
|
__asm volatile("nop; nop; nop; nop");
|
||||||
SET_STATUS(xoff);
|
SET_STATUS(xoff);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@@ -261,49 +239,40 @@ cpu_irqonoff(void)
|
|||||||
* appropriate the mips32 WAIT instruction.
|
* appropriate the mips32 WAIT instruction.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
static inline void wait(void) {
|
||||||
inline
|
/*
|
||||||
void
|
* The WAIT instruction goes into powersave mode until an
|
||||||
wait(void)
|
* interrupt is trying to occur.
|
||||||
{
|
*
|
||||||
/*
|
* Then switch interrupts on and off again, so we actually
|
||||||
* The WAIT instruction goes into powersave mode until an
|
* take the interrupt.
|
||||||
* interrupt is trying to occur.
|
*
|
||||||
*
|
* Note that the precise behavior of this instruction in the
|
||||||
* Then switch interrupts on and off again, so we actually
|
* System/161 simulator is partly guesswork. This code may not
|
||||||
* take the interrupt.
|
* work on a real mips.
|
||||||
*
|
*/
|
||||||
* Note that the precise behavior of this instruction in the
|
__asm volatile(".set push;" /* save assembler mode */
|
||||||
* System/161 simulator is partly guesswork. This code may not
|
".set mips32;" /* allow MIPS32 instructions */
|
||||||
* work on a real mips.
|
".set volatile;" /* avoid unwanted optimization */
|
||||||
*/
|
"wait;" /* suspend until interrupted */
|
||||||
__asm volatile(
|
".set pop" /* restore assembler mode */
|
||||||
".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.
|
* Idle the processor until something happens.
|
||||||
*/
|
*/
|
||||||
void
|
void cpu_idle(void) {
|
||||||
cpu_idle(void)
|
wait();
|
||||||
{
|
cpu_irqonoff();
|
||||||
wait();
|
|
||||||
cpu_irqonoff();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Halt the CPU permanently.
|
* Halt the CPU permanently.
|
||||||
*/
|
*/
|
||||||
void
|
void cpu_halt(void) {
|
||||||
cpu_halt(void)
|
cpu_irqoff();
|
||||||
{
|
while (1) {
|
||||||
cpu_irqoff();
|
wait();
|
||||||
while (1) {
|
}
|
||||||
wait();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
/* in threadstart.S */
|
/* in threadstart.S */
|
||||||
extern void mips_threadstart(/* arguments are in unusual registers */);
|
extern void mips_threadstart(/* arguments are in unusual registers */);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function to initialize the switchframe of a new thread, which is
|
* Function to initialize the switchframe of a new thread, which is
|
||||||
* *not* the one that is currently running.
|
* *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
|
* store the arguments in the s* registers, and use a bit of asm
|
||||||
* (mips_threadstart) to move them and then jump to thread_startup.
|
* (mips_threadstart) to move them and then jump to thread_startup.
|
||||||
*/
|
*/
|
||||||
void
|
void switchframe_init(struct thread *thread,
|
||||||
switchframe_init(struct thread *thread,
|
void (*entrypoint)(void *data1, unsigned long data2),
|
||||||
void (*entrypoint)(void *data1, unsigned long data2),
|
void *data1, unsigned long data2) {
|
||||||
void *data1, unsigned long data2)
|
vaddr_t stacktop;
|
||||||
{
|
struct switchframe *sf;
|
||||||
vaddr_t stacktop;
|
|
||||||
struct switchframe *sf;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MIPS stacks grow down. t_stack is just a hunk of memory, so
|
* 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
|
* get the other end of it. Then set up a switchframe on the
|
||||||
* top of the stack.
|
* top of the stack.
|
||||||
*/
|
*/
|
||||||
stacktop = ((vaddr_t)thread->t_stack) + STACK_SIZE;
|
stacktop = ((vaddr_t)thread->t_stack) + STACK_SIZE;
|
||||||
sf = ((struct switchframe *) stacktop) - 1;
|
sf = ((struct switchframe *)stacktop) - 1;
|
||||||
|
|
||||||
/* Zero out the switchframe. */
|
/* Zero out the switchframe. */
|
||||||
bzero(sf, sizeof(*sf));
|
bzero(sf, sizeof(*sf));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now set the important parts: pass through the three arguments,
|
* Now set the important parts: pass through the three arguments,
|
||||||
* and set the return address register to the place we want
|
* and set the return address register to the place we want
|
||||||
* execution to begin.
|
* execution to begin.
|
||||||
*
|
*
|
||||||
* Thus, when switchframe_switch does its "j ra", it will
|
* Thus, when switchframe_switch does its "j ra", it will
|
||||||
* actually jump to mips_threadstart, which will move the
|
* actually jump to mips_threadstart, which will move the
|
||||||
* arguments into the right register and jump to
|
* arguments into the right register and jump to
|
||||||
* thread_startup().
|
* thread_startup().
|
||||||
*
|
*
|
||||||
* Note that this means that when we call switchframe_switch()
|
* Note that this means that when we call switchframe_switch()
|
||||||
* in thread_switch(), we may not come back out the same way
|
* in thread_switch(), we may not come back out the same way
|
||||||
* in the next thread. (Though we will come back out the same
|
* in the next thread. (Though we will come back out the same
|
||||||
* way when we later come back to the same thread again.)
|
* way when we later come back to the same thread again.)
|
||||||
*
|
*
|
||||||
* This has implications for code at the bottom of
|
* This has implications for code at the bottom of
|
||||||
* thread_switch, described in thread.c.
|
* thread_switch, described in thread.c.
|
||||||
*/
|
*/
|
||||||
sf->sf_s0 = (uint32_t)entrypoint;
|
sf->sf_s0 = (uint32_t)entrypoint;
|
||||||
sf->sf_s1 = (uint32_t)data1;
|
sf->sf_s1 = (uint32_t)data1;
|
||||||
sf->sf_s2 = (uint32_t)data2;
|
sf->sf_s2 = (uint32_t)data2;
|
||||||
sf->sf_ra = (uint32_t)mips_threadstart;
|
sf->sf_ra = (uint32_t)mips_threadstart;
|
||||||
|
|
||||||
/* Set ->t_context, and we're done. */
|
/* Set ->t_context, and we're done. */
|
||||||
thread->t_context = sf;
|
thread->t_context = sf;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,16 +37,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct switchframe {
|
struct switchframe {
|
||||||
uint32_t sf_s0;
|
uint32_t sf_s0;
|
||||||
uint32_t sf_s1;
|
uint32_t sf_s1;
|
||||||
uint32_t sf_s2;
|
uint32_t sf_s2;
|
||||||
uint32_t sf_s3;
|
uint32_t sf_s3;
|
||||||
uint32_t sf_s4;
|
uint32_t sf_s4;
|
||||||
uint32_t sf_s5;
|
uint32_t sf_s5;
|
||||||
uint32_t sf_s6;
|
uint32_t sf_s6;
|
||||||
uint32_t sf_s8;
|
uint32_t sf_s8;
|
||||||
uint32_t sf_gp;
|
uint32_t sf_gp;
|
||||||
uint32_t sf_ra;
|
uint32_t sf_ra;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _MIPS_SWITCHFRAME_H_ */
|
#endif /* _MIPS_SWITCHFRAME_H_ */
|
||||||
|
|||||||
@@ -36,14 +36,10 @@
|
|||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <threadprivate.h>
|
#include <threadprivate.h>
|
||||||
|
|
||||||
void
|
void thread_machdep_init(struct thread_machdep *tm) {
|
||||||
thread_machdep_init(struct thread_machdep *tm)
|
tm->tm_badfaultfunc = NULL;
|
||||||
{
|
|
||||||
tm->tm_badfaultfunc = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void thread_machdep_cleanup(struct thread_machdep *tm) {
|
||||||
thread_machdep_cleanup(struct thread_machdep *tm)
|
KASSERT(tm->tm_badfaultfunc == NULL);
|
||||||
{
|
|
||||||
KASSERT(tm->tm_badfaultfunc == NULL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,18 +57,14 @@
|
|||||||
|
|
||||||
/* under dumbvm, always have 72k of user stack */
|
/* under dumbvm, always have 72k of user stack */
|
||||||
/* (this must be > 64K so argument blocks of size ARG_MAX will fit) */
|
/* (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.
|
* Wrap ram_stealmem in a spinlock.
|
||||||
*/
|
*/
|
||||||
static struct spinlock stealmem_lock = SPINLOCK_INITIALIZER;
|
static struct spinlock stealmem_lock = SPINLOCK_INITIALIZER;
|
||||||
|
|
||||||
void
|
void vm_bootstrap(void) { /* Do nothing. */ }
|
||||||
vm_bootstrap(void)
|
|
||||||
{
|
|
||||||
/* Do nothing. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if we're in a context that can sleep. While most of the
|
* 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
|
* avoid the situation where syscall-layer code that works ok with
|
||||||
* dumbvm starts blowing up during the VM assignment.
|
* dumbvm starts blowing up during the VM assignment.
|
||||||
*/
|
*/
|
||||||
static
|
static void dumbvm_can_sleep(void) {
|
||||||
void
|
if (CURCPU_EXISTS()) {
|
||||||
dumbvm_can_sleep(void)
|
/* must not hold spinlocks */
|
||||||
{
|
KASSERT(curcpu->c_spinlocks == 0);
|
||||||
if (CURCPU_EXISTS()) {
|
|
||||||
/* must not hold spinlocks */
|
|
||||||
KASSERT(curcpu->c_spinlocks == 0);
|
|
||||||
|
|
||||||
/* must not be in an interrupt handler */
|
/* must not be in an interrupt handler */
|
||||||
KASSERT(curthread->t_in_interrupt == 0);
|
KASSERT(curthread->t_in_interrupt == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static paddr_t getppages(unsigned long npages) {
|
||||||
paddr_t
|
paddr_t addr;
|
||||||
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);
|
spinlock_release(&stealmem_lock);
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate/free some kernel-space virtual pages */
|
/* Allocate/free some kernel-space virtual pages */
|
||||||
vaddr_t
|
vaddr_t alloc_kpages(unsigned npages) {
|
||||||
alloc_kpages(unsigned npages)
|
paddr_t pa;
|
||||||
{
|
|
||||||
paddr_t pa;
|
|
||||||
|
|
||||||
dumbvm_can_sleep();
|
dumbvm_can_sleep();
|
||||||
pa = getppages(npages);
|
pa = getppages(npages);
|
||||||
if (pa==0) {
|
if (pa == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return PADDR_TO_KVADDR(pa);
|
return PADDR_TO_KVADDR(pa);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void free_kpages(vaddr_t addr) {
|
||||||
free_kpages(vaddr_t addr)
|
/* nothing - leak the memory. */
|
||||||
{
|
|
||||||
/* nothing - leak the memory. */
|
|
||||||
|
|
||||||
(void)addr;
|
(void)addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void vm_tlbshootdown(const struct tlbshootdown *ts) {
|
||||||
vm_tlbshootdown(const struct tlbshootdown *ts)
|
(void)ts;
|
||||||
{
|
panic("dumbvm tried to do tlb shootdown?!\n");
|
||||||
(void)ts;
|
|
||||||
panic("dumbvm tried to do tlb shootdown?!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int vm_fault(int faulttype, vaddr_t faultaddress) {
|
||||||
vm_fault(int faulttype, vaddr_t faultaddress)
|
vaddr_t vbase1, vtop1, vbase2, vtop2, stackbase, stacktop;
|
||||||
{
|
paddr_t paddr;
|
||||||
vaddr_t vbase1, vtop1, vbase2, vtop2, stackbase, stacktop;
|
int i;
|
||||||
paddr_t paddr;
|
uint32_t ehi, elo;
|
||||||
int i;
|
struct addrspace *as;
|
||||||
uint32_t ehi, elo;
|
int spl;
|
||||||
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) {
|
switch (faulttype) {
|
||||||
case VM_FAULT_READONLY:
|
case VM_FAULT_READONLY:
|
||||||
/* We always create pages read-write, so we can't get this */
|
/* We always create pages read-write, so we can't get this */
|
||||||
panic("dumbvm: got VM_FAULT_READONLY\n");
|
panic("dumbvm: got VM_FAULT_READONLY\n");
|
||||||
case VM_FAULT_READ:
|
case VM_FAULT_READ:
|
||||||
case VM_FAULT_WRITE:
|
case VM_FAULT_WRITE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curproc == NULL) {
|
if (curproc == NULL) {
|
||||||
/*
|
/*
|
||||||
* No process. This is probably a kernel fault early
|
* No process. This is probably a kernel fault early
|
||||||
* in boot. Return EFAULT so as to panic instead of
|
* in boot. Return EFAULT so as to panic instead of
|
||||||
* getting into an infinite faulting loop.
|
* getting into an infinite faulting loop.
|
||||||
*/
|
*/
|
||||||
return EFAULT;
|
return EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
as = proc_getas();
|
as = proc_getas();
|
||||||
if (as == NULL) {
|
if (as == NULL) {
|
||||||
/*
|
/*
|
||||||
* No address space set up. This is probably also a
|
* No address space set up. This is probably also a
|
||||||
* kernel fault early in boot.
|
* kernel fault early in boot.
|
||||||
*/
|
*/
|
||||||
return EFAULT;
|
return EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assert that the address space has been set up properly. */
|
/* Assert that the address space has been set up properly. */
|
||||||
KASSERT(as->as_vbase1 != 0);
|
KASSERT(as->as_vbase1 != 0);
|
||||||
KASSERT(as->as_pbase1 != 0);
|
KASSERT(as->as_pbase1 != 0);
|
||||||
KASSERT(as->as_npages1 != 0);
|
KASSERT(as->as_npages1 != 0);
|
||||||
KASSERT(as->as_vbase2 != 0);
|
KASSERT(as->as_vbase2 != 0);
|
||||||
KASSERT(as->as_pbase2 != 0);
|
KASSERT(as->as_pbase2 != 0);
|
||||||
KASSERT(as->as_npages2 != 0);
|
KASSERT(as->as_npages2 != 0);
|
||||||
KASSERT(as->as_stackpbase != 0);
|
KASSERT(as->as_stackpbase != 0);
|
||||||
KASSERT((as->as_vbase1 & PAGE_FRAME) == as->as_vbase1);
|
KASSERT((as->as_vbase1 & PAGE_FRAME) == as->as_vbase1);
|
||||||
KASSERT((as->as_pbase1 & PAGE_FRAME) == as->as_pbase1);
|
KASSERT((as->as_pbase1 & PAGE_FRAME) == as->as_pbase1);
|
||||||
KASSERT((as->as_vbase2 & PAGE_FRAME) == as->as_vbase2);
|
KASSERT((as->as_vbase2 & PAGE_FRAME) == as->as_vbase2);
|
||||||
KASSERT((as->as_pbase2 & PAGE_FRAME) == as->as_pbase2);
|
KASSERT((as->as_pbase2 & PAGE_FRAME) == as->as_pbase2);
|
||||||
KASSERT((as->as_stackpbase & PAGE_FRAME) == as->as_stackpbase);
|
KASSERT((as->as_stackpbase & PAGE_FRAME) == as->as_stackpbase);
|
||||||
|
|
||||||
vbase1 = as->as_vbase1;
|
vbase1 = as->as_vbase1;
|
||||||
vtop1 = vbase1 + as->as_npages1 * PAGE_SIZE;
|
vtop1 = vbase1 + as->as_npages1 * PAGE_SIZE;
|
||||||
vbase2 = as->as_vbase2;
|
vbase2 = as->as_vbase2;
|
||||||
vtop2 = vbase2 + as->as_npages2 * PAGE_SIZE;
|
vtop2 = vbase2 + as->as_npages2 * PAGE_SIZE;
|
||||||
stackbase = USERSTACK - DUMBVM_STACKPAGES * PAGE_SIZE;
|
stackbase = USERSTACK - DUMBVM_STACKPAGES * PAGE_SIZE;
|
||||||
stacktop = USERSTACK;
|
stacktop = USERSTACK;
|
||||||
|
|
||||||
if (faultaddress >= vbase1 && faultaddress < vtop1) {
|
if (faultaddress >= vbase1 && faultaddress < vtop1) {
|
||||||
paddr = (faultaddress - vbase1) + as->as_pbase1;
|
paddr = (faultaddress - vbase1) + as->as_pbase1;
|
||||||
}
|
} else if (faultaddress >= vbase2 && faultaddress < vtop2) {
|
||||||
else if (faultaddress >= vbase2 && faultaddress < vtop2) {
|
paddr = (faultaddress - vbase2) + as->as_pbase2;
|
||||||
paddr = (faultaddress - vbase2) + as->as_pbase2;
|
} else if (faultaddress >= stackbase && faultaddress < stacktop) {
|
||||||
}
|
paddr = (faultaddress - stackbase) + as->as_stackpbase;
|
||||||
else if (faultaddress >= stackbase && faultaddress < stacktop) {
|
} else {
|
||||||
paddr = (faultaddress - stackbase) + as->as_stackpbase;
|
return EFAULT;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make sure it's page-aligned */
|
/* make sure it's page-aligned */
|
||||||
KASSERT((paddr & PAGE_FRAME) == paddr);
|
KASSERT((paddr & PAGE_FRAME) == paddr);
|
||||||
|
|
||||||
/* Disable interrupts on this CPU while frobbing the TLB. */
|
/* Disable interrupts on this CPU while frobbing the TLB. */
|
||||||
spl = splhigh();
|
spl = splhigh();
|
||||||
|
|
||||||
for (i=0; i<NUM_TLB; i++) {
|
for (i = 0; i < NUM_TLB; i++) {
|
||||||
tlb_read(&ehi, &elo, i);
|
tlb_read(&ehi, &elo, i);
|
||||||
if (elo & TLBLO_VALID) {
|
if (elo & TLBLO_VALID) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ehi = faultaddress;
|
ehi = faultaddress;
|
||||||
elo = paddr | TLBLO_DIRTY | TLBLO_VALID;
|
elo = paddr | TLBLO_DIRTY | TLBLO_VALID;
|
||||||
DEBUG(DB_VM, "dumbvm: 0x%x -> 0x%x\n", faultaddress, paddr);
|
DEBUG(DB_VM, "dumbvm: 0x%x -> 0x%x\n", faultaddress, paddr);
|
||||||
tlb_write(ehi, elo, i);
|
tlb_write(ehi, elo, i);
|
||||||
splx(spl);
|
splx(spl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf("dumbvm: Ran out of TLB entries - cannot handle page fault\n");
|
kprintf("dumbvm: Ran out of TLB entries - cannot handle page fault\n");
|
||||||
splx(spl);
|
splx(spl);
|
||||||
return EFAULT;
|
return EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct addrspace *
|
struct addrspace *as_create(void) {
|
||||||
as_create(void)
|
struct addrspace *as = kmalloc(sizeof(struct addrspace));
|
||||||
{
|
if (as == NULL) {
|
||||||
struct addrspace *as = kmalloc(sizeof(struct addrspace));
|
return NULL;
|
||||||
if (as==NULL) {
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
as->as_vbase1 = 0;
|
as->as_vbase1 = 0;
|
||||||
as->as_pbase1 = 0;
|
as->as_pbase1 = 0;
|
||||||
as->as_npages1 = 0;
|
as->as_npages1 = 0;
|
||||||
as->as_vbase2 = 0;
|
as->as_vbase2 = 0;
|
||||||
as->as_pbase2 = 0;
|
as->as_pbase2 = 0;
|
||||||
as->as_npages2 = 0;
|
as->as_npages2 = 0;
|
||||||
as->as_stackpbase = 0;
|
as->as_stackpbase = 0;
|
||||||
|
|
||||||
return as;
|
return as;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void as_destroy(struct addrspace *as) {
|
||||||
as_destroy(struct addrspace *as)
|
dumbvm_can_sleep();
|
||||||
{
|
kfree(as);
|
||||||
dumbvm_can_sleep();
|
|
||||||
kfree(as);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void as_activate(void) {
|
||||||
as_activate(void)
|
int i, spl;
|
||||||
{
|
struct addrspace *as;
|
||||||
int i, spl;
|
|
||||||
struct addrspace *as;
|
|
||||||
|
|
||||||
as = proc_getas();
|
as = proc_getas();
|
||||||
if (as == NULL) {
|
if (as == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable interrupts on this CPU while frobbing the TLB. */
|
/* Disable interrupts on this CPU while frobbing the TLB. */
|
||||||
spl = splhigh();
|
spl = splhigh();
|
||||||
|
|
||||||
for (i=0; i<NUM_TLB; i++) {
|
for (i = 0; i < NUM_TLB; i++) {
|
||||||
tlb_write(TLBHI_INVALID(i), TLBLO_INVALID(), i);
|
tlb_write(TLBHI_INVALID(i), TLBLO_INVALID(), i);
|
||||||
}
|
}
|
||||||
|
|
||||||
splx(spl);
|
splx(spl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void as_deactivate(void) { /* nothing */ }
|
||||||
as_deactivate(void)
|
|
||||||
{
|
int as_define_region(struct addrspace *as, vaddr_t vaddr, size_t sz,
|
||||||
/* nothing */
|
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
|
static void as_zero_region(paddr_t paddr, unsigned npages) {
|
||||||
as_define_region(struct addrspace *as, vaddr_t vaddr, size_t sz,
|
bzero((void *)PADDR_TO_KVADDR(paddr), npages * PAGE_SIZE);
|
||||||
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
|
int as_prepare_load(struct addrspace *as) {
|
||||||
void
|
KASSERT(as->as_pbase1 == 0);
|
||||||
as_zero_region(paddr_t paddr, unsigned npages)
|
KASSERT(as->as_pbase2 == 0);
|
||||||
{
|
KASSERT(as->as_stackpbase == 0);
|
||||||
bzero((void *)PADDR_TO_KVADDR(paddr), npages * PAGE_SIZE);
|
|
||||||
|
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
|
int as_complete_load(struct addrspace *as) {
|
||||||
as_prepare_load(struct addrspace *as)
|
dumbvm_can_sleep();
|
||||||
{
|
(void)as;
|
||||||
KASSERT(as->as_pbase1 == 0);
|
return 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
|
int as_define_stack(struct addrspace *as, vaddr_t *stackptr) {
|
||||||
as_complete_load(struct addrspace *as)
|
KASSERT(as->as_stackpbase != 0);
|
||||||
{
|
|
||||||
dumbvm_can_sleep();
|
*stackptr = USERSTACK;
|
||||||
(void)as;
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int as_copy(struct addrspace *old, struct addrspace **ret) {
|
||||||
as_define_stack(struct addrspace *as, vaddr_t *stackptr)
|
struct addrspace *new;
|
||||||
{
|
|
||||||
KASSERT(as->as_stackpbase != 0);
|
|
||||||
|
|
||||||
*stackptr = USERSTACK;
|
dumbvm_can_sleep();
|
||||||
return 0;
|
|
||||||
}
|
new = as_create();
|
||||||
|
if (new == NULL) {
|
||||||
int
|
return ENOMEM;
|
||||||
as_copy(struct addrspace *old, struct addrspace **ret)
|
}
|
||||||
{
|
|
||||||
struct addrspace *new;
|
new->as_vbase1 = old->as_vbase1;
|
||||||
|
new->as_npages1 = old->as_npages1;
|
||||||
dumbvm_can_sleep();
|
new->as_vbase2 = old->as_vbase2;
|
||||||
|
new->as_npages2 = old->as_npages2;
|
||||||
new = as_create();
|
|
||||||
if (new==NULL) {
|
/* (Mis)use as_prepare_load to allocate some physical memory. */
|
||||||
return ENOMEM;
|
if (as_prepare_load(new)) {
|
||||||
}
|
as_destroy(new);
|
||||||
|
return ENOMEM;
|
||||||
new->as_vbase1 = old->as_vbase1;
|
}
|
||||||
new->as_npages1 = old->as_npages1;
|
|
||||||
new->as_vbase2 = old->as_vbase2;
|
KASSERT(new->as_pbase1 != 0);
|
||||||
new->as_npages2 = old->as_npages2;
|
KASSERT(new->as_pbase2 != 0);
|
||||||
|
KASSERT(new->as_stackpbase != 0);
|
||||||
/* (Mis)use as_prepare_load to allocate some physical memory. */
|
|
||||||
if (as_prepare_load(new)) {
|
memmove((void *)PADDR_TO_KVADDR(new->as_pbase1),
|
||||||
as_destroy(new);
|
(const void *)PADDR_TO_KVADDR(old->as_pbase1),
|
||||||
return ENOMEM;
|
old->as_npages1 * PAGE_SIZE);
|
||||||
}
|
|
||||||
|
memmove((void *)PADDR_TO_KVADDR(new->as_pbase2),
|
||||||
KASSERT(new->as_pbase1 != 0);
|
(const void *)PADDR_TO_KVADDR(old->as_pbase2),
|
||||||
KASSERT(new->as_pbase2 != 0);
|
old->as_npages2 * PAGE_SIZE);
|
||||||
KASSERT(new->as_stackpbase != 0);
|
|
||||||
|
memmove((void *)PADDR_TO_KVADDR(new->as_stackpbase),
|
||||||
memmove((void *)PADDR_TO_KVADDR(new->as_pbase1),
|
(const void *)PADDR_TO_KVADDR(old->as_stackpbase),
|
||||||
(const void *)PADDR_TO_KVADDR(old->as_pbase1),
|
DUMBVM_STACKPAGES * PAGE_SIZE);
|
||||||
old->as_npages1*PAGE_SIZE);
|
|
||||||
|
*ret = new;
|
||||||
memmove((void *)PADDR_TO_KVADDR(new->as_pbase2),
|
return 0;
|
||||||
(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 <vm.h>
|
||||||
#include <mainbus.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
|
* Called very early in system boot to figure out how much physical
|
||||||
* RAM is available.
|
* RAM is available.
|
||||||
*/
|
*/
|
||||||
void
|
void ram_bootstrap(void) {
|
||||||
ram_bootstrap(void)
|
size_t ramsize;
|
||||||
{
|
|
||||||
size_t ramsize;
|
|
||||||
|
|
||||||
/* Get size of RAM. */
|
/* Get size of RAM. */
|
||||||
ramsize = mainbus_ramsize();
|
ramsize = mainbus_ramsize();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the same as the last physical address, as long as
|
* 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 have less than 512 megabytes of memory. If we had more,
|
||||||
* we wouldn't be able to access it all through kseg0 and
|
* we wouldn't be able to access it all through kseg0 and
|
||||||
* everything would get a lot more complicated. This is not a
|
* everything would get a lot more complicated. This is not a
|
||||||
* case we are going to worry about.
|
* case we are going to worry about.
|
||||||
*/
|
*/
|
||||||
if (ramsize > 512*1024*1024) {
|
if (ramsize > 512 * 1024 * 1024) {
|
||||||
ramsize = 512*1024*1024;
|
ramsize = 512 * 1024 * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastpaddr = ramsize;
|
lastpaddr = ramsize;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get first free virtual address from where start.S saved it.
|
* Get first free virtual address from where start.S saved it.
|
||||||
* Convert to physical address.
|
* Convert to physical address.
|
||||||
*/
|
*/
|
||||||
firstpaddr = firstfree - MIPS_KSEG0;
|
firstpaddr = firstfree - MIPS_KSEG0;
|
||||||
|
|
||||||
kprintf("%uk physical memory available\n",
|
kprintf("%uk physical memory available\n", (lastpaddr - firstpaddr) / 1024);
|
||||||
(lastpaddr-firstpaddr)/1024);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -91,22 +87,20 @@ ram_bootstrap(void)
|
|||||||
* This function should not be called once the VM system is initialized,
|
* This function should not be called once the VM system is initialized,
|
||||||
* so it is not synchronized.
|
* so it is not synchronized.
|
||||||
*/
|
*/
|
||||||
paddr_t
|
paddr_t ram_stealmem(unsigned long npages) {
|
||||||
ram_stealmem(unsigned long npages)
|
size_t size;
|
||||||
{
|
paddr_t paddr;
|
||||||
size_t size;
|
|
||||||
paddr_t paddr;
|
|
||||||
|
|
||||||
size = npages * PAGE_SIZE;
|
size = npages * PAGE_SIZE;
|
||||||
|
|
||||||
if (firstpaddr + size > lastpaddr) {
|
if (firstpaddr + size > lastpaddr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
paddr = firstpaddr;
|
paddr = firstpaddr;
|
||||||
firstpaddr += size;
|
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
|
* initialize the VM system, after which the VM system should take
|
||||||
* charge of knowing what memory exists.
|
* charge of knowing what memory exists.
|
||||||
*/
|
*/
|
||||||
paddr_t
|
paddr_t ram_getsize(void) { return lastpaddr; }
|
||||||
ram_getsize(void)
|
|
||||||
{
|
|
||||||
return lastpaddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is intended to be called by the VM system when it
|
* 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,
|
* This function should not be called once the VM system is initialized,
|
||||||
* so it is not synchronized.
|
* so it is not synchronized.
|
||||||
*/
|
*/
|
||||||
paddr_t
|
paddr_t ram_getfirstfree(void) {
|
||||||
ram_getfirstfree(void)
|
paddr_t ret;
|
||||||
{
|
|
||||||
paddr_t ret;
|
|
||||||
|
|
||||||
ret = firstpaddr;
|
ret = firstpaddr;
|
||||||
firstpaddr = lastpaddr = 0;
|
firstpaddr = lastpaddr = 0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,20 +60,16 @@
|
|||||||
* matches the c0_compare register, the timer interrupt line is
|
* matches the c0_compare register, the timer interrupt line is
|
||||||
* asserted. Writing to c0_compare again clears the interrupt.
|
* asserted. Writing to c0_compare again clears the interrupt.
|
||||||
*/
|
*/
|
||||||
static
|
static void mips_timer_set(uint32_t count) {
|
||||||
void
|
/*
|
||||||
mips_timer_set(uint32_t count)
|
* $11 == c0_compare; we can't use the symbolic name inside
|
||||||
{
|
* the asm string.
|
||||||
/*
|
*/
|
||||||
* $11 == c0_compare; we can't use the symbolic name inside
|
__asm volatile(".set push;" /* save assembler mode */
|
||||||
* the asm string.
|
".set mips32;" /* allow MIPS32 registers */
|
||||||
*/
|
"mtc0 %0, $11;" /* do it */
|
||||||
__asm volatile(
|
".set pop" /* restore assembler mode */
|
||||||
".set push;" /* save assembler mode */
|
::"r"(count));
|
||||||
".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;
|
static struct lamebus_softc *lamebus;
|
||||||
|
|
||||||
void
|
void mainbus_bootstrap(void) {
|
||||||
mainbus_bootstrap(void)
|
/* Interrupts should be off (and have been off since startup) */
|
||||||
{
|
KASSERT(curthread->t_curspl > 0);
|
||||||
/* Interrupts should be off (and have been off since startup) */
|
|
||||||
KASSERT(curthread->t_curspl > 0);
|
|
||||||
|
|
||||||
/* Initialize the system LAMEbus data */
|
/* Initialize the system LAMEbus data */
|
||||||
lamebus = lamebus_init();
|
lamebus = lamebus_init();
|
||||||
|
|
||||||
/* Probe CPUs (should these be done as device attachments instead?) */
|
/* Probe CPUs (should these be done as device attachments instead?) */
|
||||||
lamebus_find_cpus(lamebus);
|
lamebus_find_cpus(lamebus);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print the device name for the main bus.
|
* Print the device name for the main bus.
|
||||||
*/
|
*/
|
||||||
kprintf("lamebus0 (system main bus)\n");
|
kprintf("lamebus0 (system main bus)\n");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we can take interrupts without croaking, so turn them on.
|
* Now we can take interrupts without croaking, so turn them on.
|
||||||
* Some device probes might require being able to get interrupts.
|
* Some device probes might require being able to get interrupts.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
spl0();
|
spl0();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now probe all the devices attached to the bus.
|
* Now probe all the devices attached to the bus.
|
||||||
* (This amounts to all devices.)
|
* (This amounts to all devices.)
|
||||||
*/
|
*/
|
||||||
autoconf_lamebus(lamebus, 0);
|
autoconf_lamebus(lamebus, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure the MIPS on-chip timer to interrupt HZ times a second.
|
* Configure the MIPS on-chip timer to interrupt HZ times a second.
|
||||||
*/
|
*/
|
||||||
mips_timer_set(CPU_FREQUENCY / HZ);
|
mips_timer_set(CPU_FREQUENCY / HZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start all secondary CPUs.
|
* Start all secondary CPUs.
|
||||||
*/
|
*/
|
||||||
void
|
void mainbus_start_cpus(void) { lamebus_start_cpus(lamebus); }
|
||||||
mainbus_start_cpus(void)
|
|
||||||
{
|
|
||||||
lamebus_start_cpus(lamebus);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function to generate the memory address (in the uncached segment)
|
* Function to generate the memory address (in the uncached segment)
|
||||||
* for the specified offset into the specified slot's region of the
|
* for the specified offset into the specified slot's region of the
|
||||||
* LAMEbus.
|
* LAMEbus.
|
||||||
*/
|
*/
|
||||||
void *
|
void *lamebus_map_area(struct lamebus_softc *bus, int slot, uint32_t offset) {
|
||||||
lamebus_map_area(struct lamebus_softc *bus, int slot, uint32_t offset)
|
uint32_t address;
|
||||||
{
|
|
||||||
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;
|
address = LB_BASEADDR + slot * LB_SLOT_SIZE + offset;
|
||||||
return (void *)address;
|
return (void *)address;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a 32-bit register from a LAMEbus device.
|
* Read a 32-bit register from a LAMEbus device.
|
||||||
*/
|
*/
|
||||||
uint32_t
|
uint32_t lamebus_read_register(struct lamebus_softc *bus, int slot,
|
||||||
lamebus_read_register(struct lamebus_softc *bus, int slot, uint32_t offset)
|
uint32_t offset) {
|
||||||
{
|
uint32_t *ptr;
|
||||||
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
|
* Make sure the load happens after anything the device has
|
||||||
* been doing.
|
* been doing.
|
||||||
*/
|
*/
|
||||||
membar_load_load();
|
membar_load_load();
|
||||||
|
|
||||||
return *ptr;
|
return *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write a 32-bit register of a LAMEbus device.
|
* Write a 32-bit register of a LAMEbus device.
|
||||||
*/
|
*/
|
||||||
void
|
void lamebus_write_register(struct lamebus_softc *bus, int slot,
|
||||||
lamebus_write_register(struct lamebus_softc *bus, int slot,
|
uint32_t offset, uint32_t val) {
|
||||||
uint32_t offset, uint32_t val)
|
uint32_t *ptr;
|
||||||
{
|
|
||||||
uint32_t *ptr;
|
|
||||||
|
|
||||||
ptr = lamebus_map_area(bus, slot, offset);
|
ptr = lamebus_map_area(bus, slot, offset);
|
||||||
*ptr = val;
|
*ptr = val;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure the store happens before we do anything else to
|
* Make sure the store happens before we do anything else to
|
||||||
* the device.
|
* the device.
|
||||||
*/
|
*/
|
||||||
membar_store_store();
|
membar_store_store();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power off the system.
|
* Power off the system.
|
||||||
*/
|
*/
|
||||||
void
|
void mainbus_poweroff(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
|
||||||
* Note that lamebus_write_register() doesn't actually access
|
* before the bus is initialized.
|
||||||
* the bus argument, so this will still work if we get here
|
*/
|
||||||
* before the bus is initialized.
|
lamebus_poweroff(lamebus);
|
||||||
*/
|
|
||||||
lamebus_poweroff(lamebus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reboot the system.
|
* Reboot the system.
|
||||||
*/
|
*/
|
||||||
void
|
void mainbus_reboot(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
|
||||||
* The MIPS doesn't appear to have any on-chip reset.
|
* power off instead of rebooting. This would not be
|
||||||
* LAMEbus doesn't have a reset control, so we just
|
* so great in a real system, but it's fine for what
|
||||||
* power off instead of rebooting. This would not be
|
* we're doing.
|
||||||
* 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();
|
||||||
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
|
* On some systems, this would return to the boot monitor. But we don't
|
||||||
* have one.
|
* have one.
|
||||||
*/
|
*/
|
||||||
void
|
void mainbus_halt(void) { cpu_halt(); }
|
||||||
mainbus_halt(void)
|
|
||||||
{
|
|
||||||
cpu_halt();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to reset the system from panic().
|
* 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.
|
* as to panic recursively if we do much of anything. So just power off.
|
||||||
* (We'd reboot, but System/161 doesn't do that.)
|
* (We'd reboot, but System/161 doesn't do that.)
|
||||||
*/
|
*/
|
||||||
void
|
void mainbus_panic(void) { mainbus_poweroff(); }
|
||||||
mainbus_panic(void)
|
|
||||||
{
|
|
||||||
mainbus_poweroff();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function to get the size of installed physical RAM from the LAMEbus
|
* Function to get the size of installed physical RAM from the LAMEbus
|
||||||
* controller.
|
* controller.
|
||||||
*/
|
*/
|
||||||
uint32_t
|
uint32_t mainbus_ramsize(void) {
|
||||||
mainbus_ramsize(void)
|
uint32_t ramsize;
|
||||||
{
|
|
||||||
uint32_t ramsize;
|
|
||||||
|
|
||||||
ramsize = lamebus_ramsize();
|
ramsize = lamebus_ramsize();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the same as the last physical address, as long as
|
* This is the same as the last physical address, as long as
|
||||||
* we have less than 508 megabytes of memory. The LAMEbus I/O
|
* we have less than 508 megabytes of memory. The LAMEbus I/O
|
||||||
* area occupies the space between 508 megabytes and 512
|
* area occupies the space between 508 megabytes and 512
|
||||||
* megabytes, so if we had more RAM than this it would have to
|
* 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
|
* be discontiguous. This is not a case we are going to worry
|
||||||
* about.
|
* about.
|
||||||
*/
|
*/
|
||||||
if (ramsize > 508*1024*1024) {
|
if (ramsize > 508 * 1024 * 1024) {
|
||||||
ramsize = 508*1024*1024;
|
ramsize = 508 * 1024 * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ramsize;
|
return ramsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send IPI.
|
* Send IPI.
|
||||||
*/
|
*/
|
||||||
void
|
void mainbus_send_ipi(struct cpu *target) {
|
||||||
mainbus_send_ipi(struct cpu *target)
|
lamebus_assert_ipi(lamebus, target);
|
||||||
{
|
|
||||||
lamebus_assert_ipi(lamebus, target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Trigger the debugger.
|
* Trigger the debugger.
|
||||||
*/
|
*/
|
||||||
void
|
void mainbus_debugger(void) { ltrace_stop(0); }
|
||||||
mainbus_debugger(void)
|
|
||||||
{
|
|
||||||
ltrace_stop(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Interrupt dispatcher.
|
* Interrupt dispatcher.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Wiring of LAMEbus interrupts to bits in the cause register */
|
/* Wiring of LAMEbus interrupts to bits in the cause register */
|
||||||
#define LAMEBUS_IRQ_BIT 0x00000400 /* all system bus slots */
|
#define LAMEBUS_IRQ_BIT 0x00000400 /* all system bus slots */
|
||||||
#define LAMEBUS_IPI_BIT 0x00000800 /* inter-processor interrupt */
|
#define LAMEBUS_IPI_BIT 0x00000800 /* inter-processor interrupt */
|
||||||
#define MIPS_TIMER_BIT 0x00008000 /* on-chip timer */
|
#define MIPS_TIMER_BIT 0x00008000 /* on-chip timer */
|
||||||
|
|
||||||
void
|
void mainbus_interrupt(struct trapframe *tf) {
|
||||||
mainbus_interrupt(struct trapframe *tf)
|
uint32_t cause;
|
||||||
{
|
bool seen = false;
|
||||||
uint32_t cause;
|
|
||||||
bool seen = false;
|
|
||||||
|
|
||||||
/* interrupts should be off */
|
/* interrupts should be off */
|
||||||
KASSERT(curthread->t_curspl > 0);
|
KASSERT(curthread->t_curspl > 0);
|
||||||
|
|
||||||
cause = tf->tf_cause;
|
cause = tf->tf_cause;
|
||||||
if (cause & LAMEBUS_IRQ_BIT) {
|
if (cause & LAMEBUS_IRQ_BIT) {
|
||||||
lamebus_interrupt(lamebus);
|
lamebus_interrupt(lamebus);
|
||||||
seen = true;
|
seen = true;
|
||||||
}
|
}
|
||||||
if (cause & LAMEBUS_IPI_BIT) {
|
if (cause & LAMEBUS_IPI_BIT) {
|
||||||
interprocessor_interrupt();
|
interprocessor_interrupt();
|
||||||
lamebus_clear_ipi(lamebus, curcpu);
|
lamebus_clear_ipi(lamebus, curcpu);
|
||||||
seen = true;
|
seen = true;
|
||||||
}
|
}
|
||||||
if (cause & MIPS_TIMER_BIT) {
|
if (cause & MIPS_TIMER_BIT) {
|
||||||
/* Reset the timer (this clears the interrupt) */
|
/* Reset the timer (this clears the interrupt) */
|
||||||
mips_timer_set(CPU_FREQUENCY / HZ);
|
mips_timer_set(CPU_FREQUENCY / HZ);
|
||||||
/* and call hardclock */
|
/* and call hardclock */
|
||||||
hardclock();
|
hardclock();
|
||||||
seen = true;
|
seen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!seen) {
|
if (!seen) {
|
||||||
if ((cause & CCA_IRQS) == 0) {
|
if ((cause & CCA_IRQS) == 0) {
|
||||||
/*
|
/*
|
||||||
* Don't panic here; this can happen if an
|
* Don't panic here; this can happen if an
|
||||||
* interrupt line asserts (very) briefly and
|
* interrupt line asserts (very) briefly and
|
||||||
* turns off again before we get as far as
|
* turns off again before we get as far as
|
||||||
* reading the cause register. This was
|
* reading the cause register. This was
|
||||||
* actually seen... once.
|
* actually seen... once.
|
||||||
*/
|
*/
|
||||||
}
|
} else {
|
||||||
else {
|
/*
|
||||||
/*
|
* But if we get an interrupt on an interrupt
|
||||||
* But if we get an interrupt on an interrupt
|
* line that's not supposed to be wired up,
|
||||||
* line that's not supposed to be wired up,
|
* complain.
|
||||||
* complain.
|
*/
|
||||||
*/
|
panic("Unknown interrupt; cause register is %08x\n", cause);
|
||||||
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.
|
* This would need to be a bit more complicated if that weren't the case.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <machine/vm.h> /* for MIPS_KSEG1 */
|
#include <machine/vm.h> /* for MIPS_KSEG1 */
|
||||||
#include <lamebus/lamebus.h> /* for LAMEbus definitions */
|
#include <lamebus/lamebus.h> /* for LAMEbus definitions */
|
||||||
|
|
||||||
#define bus_write_register(bus, slot, offset, val) \
|
#define bus_write_register(bus, slot, offset, val) \
|
||||||
lamebus_write_register(bus, slot, offset, val)
|
lamebus_write_register(bus, slot, offset, val)
|
||||||
|
|
||||||
#define bus_read_register(bus, slot, offset) \
|
#define bus_read_register(bus, slot, offset) \
|
||||||
lamebus_read_register(bus, slot, offset)
|
lamebus_read_register(bus, slot, offset)
|
||||||
|
|
||||||
#define bus_map_area(bus, slot, offset) \
|
#define bus_map_area(bus, slot, offset) lamebus_map_area(bus, slot, offset)
|
||||||
lamebus_map_area(bus, slot, offset)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Machine-dependent LAMEbus definitions
|
* Machine-dependent LAMEbus definitions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Base address of the LAMEbus mapping area */
|
/* Base address of the LAMEbus mapping area */
|
||||||
#define LB_BASEADDR (MIPS_KSEG1 + 0x1fe00000)
|
#define LB_BASEADDR (MIPS_KSEG1 + 0x1fe00000)
|
||||||
|
|
||||||
|
|
||||||
#endif /* _SYS161_BUS_H_ */
|
#endif /* _SYS161_BUS_H_ */
|
||||||
|
|||||||
@@ -46,26 +46,21 @@
|
|||||||
|
|
||||||
static struct beep_softc *the_beep = NULL;
|
static struct beep_softc *the_beep = NULL;
|
||||||
|
|
||||||
int
|
int config_beep(struct beep_softc *bs, int unit) {
|
||||||
config_beep(struct beep_softc *bs, int unit)
|
/* We use only the first beep device. */
|
||||||
{
|
if (unit != 0) {
|
||||||
/* We use only the first beep device. */
|
return ENODEV;
|
||||||
if (unit!=0) {
|
}
|
||||||
return ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
KASSERT(the_beep==NULL);
|
KASSERT(the_beep == NULL);
|
||||||
the_beep = bs;
|
the_beep = bs;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void beep(void) {
|
||||||
beep(void)
|
if (the_beep != NULL) {
|
||||||
{
|
the_beep->bs_beep(the_beep->bs_devdata);
|
||||||
if (the_beep!=NULL) {
|
} else {
|
||||||
the_beep->bs_beep(the_beep->bs_devdata);
|
kprintf("beep: Warning: no beep device\n");
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
kprintf("beep: Warning: no beep device\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,8 +36,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct beep_softc {
|
struct beep_softc {
|
||||||
void *bs_devdata;
|
void *bs_devdata;
|
||||||
void (*bs_beep)(void *devdata);
|
void (*bs_beep)(void *devdata);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _GENERIC_BEEP_H_ */
|
#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
|
* console is set up. Upon console setup they are dumped
|
||||||
* to the actual console; thenceforth this space is unused.
|
* to the actual console; thenceforth this space is unused.
|
||||||
*/
|
*/
|
||||||
#define DELAYBUFSIZE 1024
|
#define DELAYBUFSIZE 1024
|
||||||
static char delayed_outbuf[DELAYBUFSIZE];
|
static char delayed_outbuf[DELAYBUFSIZE];
|
||||||
static size_t delayed_outbuf_pos=0;
|
static size_t delayed_outbuf_pos = 0;
|
||||||
|
|
||||||
static
|
static void putch_delayed(int ch) {
|
||||||
void
|
/*
|
||||||
putch_delayed(int ch)
|
* No synchronization needed: called only during system startup
|
||||||
{
|
* by main thread.
|
||||||
/*
|
*/
|
||||||
* No synchronization needed: called only during system startup
|
|
||||||
* by main thread.
|
|
||||||
*/
|
|
||||||
|
|
||||||
KASSERT(delayed_outbuf_pos < sizeof(delayed_outbuf));
|
KASSERT(delayed_outbuf_pos < sizeof(delayed_outbuf));
|
||||||
delayed_outbuf[delayed_outbuf_pos++] = ch;
|
delayed_outbuf[delayed_outbuf_pos++] = ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void flush_delay_buf(void) {
|
||||||
void
|
size_t i;
|
||||||
flush_delay_buf(void)
|
for (i = 0; i < delayed_outbuf_pos; i++) {
|
||||||
{
|
putch(delayed_outbuf[i]);
|
||||||
size_t i;
|
}
|
||||||
for (i=0; i<delayed_outbuf_pos; i++) {
|
delayed_outbuf_pos = 0;
|
||||||
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
|
* Print a character, using polling instead of interrupts to wait for
|
||||||
* I/O completion.
|
* I/O completion.
|
||||||
*/
|
*/
|
||||||
static
|
static void putch_polled(struct con_softc *cs, int ch) {
|
||||||
void
|
cs->cs_sendpolled(cs->cs_devdata, ch);
|
||||||
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.
|
* Print a character, using interrupts to wait for I/O completion.
|
||||||
*/
|
*/
|
||||||
static
|
static void putch_intr(struct con_softc *cs, int ch) {
|
||||||
void
|
P(cs->cs_wsem);
|
||||||
putch_intr(struct con_softc *cs, int ch)
|
cs->cs_send(cs->cs_devdata, ch);
|
||||||
{
|
|
||||||
P(cs->cs_wsem);
|
|
||||||
cs->cs_send(cs->cs_devdata, ch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a character, using interrupts to wait for I/O completion.
|
* Read a character, using interrupts to wait for I/O completion.
|
||||||
*/
|
*/
|
||||||
static
|
static int getch_intr(struct con_softc *cs) {
|
||||||
int
|
unsigned char ret;
|
||||||
getch_intr(struct con_softc *cs)
|
|
||||||
{
|
|
||||||
unsigned char ret;
|
|
||||||
|
|
||||||
P(cs->cs_rsem);
|
P(cs->cs_rsem);
|
||||||
ret = cs->cs_gotchars[cs->cs_gotchars_tail];
|
ret = cs->cs_gotchars[cs->cs_gotchars_tail];
|
||||||
cs->cs_gotchars_tail =
|
cs->cs_gotchars_tail = (cs->cs_gotchars_tail + 1) % CONSOLE_INPUT_BUFFER_SIZE;
|
||||||
(cs->cs_gotchars_tail + 1) % CONSOLE_INPUT_BUFFER_SIZE;
|
return ret;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -158,33 +142,29 @@ getch_intr(struct con_softc *cs)
|
|||||||
* too) would be with a second semaphore used with a nonblocking P,
|
* too) would be with a second semaphore used with a nonblocking P,
|
||||||
* but we don't have that in OS/161.
|
* but we don't have that in OS/161.
|
||||||
*/
|
*/
|
||||||
void
|
void con_input(void *vcs, int ch) {
|
||||||
con_input(void *vcs, int ch)
|
struct con_softc *cs = vcs;
|
||||||
{
|
unsigned nexthead;
|
||||||
struct con_softc *cs = vcs;
|
|
||||||
unsigned nexthead;
|
|
||||||
|
|
||||||
nexthead = (cs->cs_gotchars_head + 1) % CONSOLE_INPUT_BUFFER_SIZE;
|
nexthead = (cs->cs_gotchars_head + 1) % CONSOLE_INPUT_BUFFER_SIZE;
|
||||||
if (nexthead == cs->cs_gotchars_tail) {
|
if (nexthead == cs->cs_gotchars_tail) {
|
||||||
/* overflow; drop character */
|
/* overflow; drop character */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cs->cs_gotchars[cs->cs_gotchars_head] = ch;
|
cs->cs_gotchars[cs->cs_gotchars_head] = ch;
|
||||||
cs->cs_gotchars_head = nexthead;
|
cs->cs_gotchars_head = nexthead;
|
||||||
|
|
||||||
V(cs->cs_rsem);
|
V(cs->cs_rsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called from underlying device when a write-done interrupt occurs.
|
* Called from underlying device when a write-done interrupt occurs.
|
||||||
*/
|
*/
|
||||||
void
|
void con_start(void *vcs) {
|
||||||
con_start(void *vcs)
|
struct con_softc *cs = 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.
|
* not, and does not.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void putch(int ch) {
|
||||||
putch(int ch)
|
struct con_softc *cs = the_console;
|
||||||
{
|
|
||||||
struct con_softc *cs = the_console;
|
|
||||||
|
|
||||||
if (cs==NULL) {
|
if (cs == NULL) {
|
||||||
putch_delayed(ch);
|
putch_delayed(ch);
|
||||||
}
|
} else if (curthread->t_in_interrupt || curthread->t_curspl > 0 ||
|
||||||
else if (curthread->t_in_interrupt ||
|
curcpu->c_spinlocks > 0) {
|
||||||
curthread->t_curspl > 0 ||
|
putch_polled(cs, ch);
|
||||||
curcpu->c_spinlocks > 0) {
|
} else {
|
||||||
putch_polled(cs, ch);
|
putch_intr(cs, ch);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
putch_intr(cs, ch);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int getch(void) {
|
||||||
getch(void)
|
struct con_softc *cs = the_console;
|
||||||
{
|
KASSERT(cs != NULL);
|
||||||
struct con_softc *cs = the_console;
|
KASSERT(!curthread->t_in_interrupt && curthread->t_iplhigh_count == 0);
|
||||||
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
|
* VFS interface functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
static int con_eachopen(struct device *dev, int openflags) {
|
||||||
int
|
(void)dev;
|
||||||
con_eachopen(struct device *dev, int openflags)
|
(void)openflags;
|
||||||
{
|
return 0;
|
||||||
(void)dev;
|
|
||||||
(void)openflags;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static int con_io(struct device *dev, struct uio *uio) {
|
||||||
int
|
int result;
|
||||||
con_io(struct device *dev, struct uio *uio)
|
char ch;
|
||||||
{
|
struct lock *lk;
|
||||||
int result;
|
|
||||||
char ch;
|
|
||||||
struct lock *lk;
|
|
||||||
|
|
||||||
(void)dev; // unused
|
(void)dev; // unused
|
||||||
|
|
||||||
if (uio->uio_rw==UIO_READ) {
|
if (uio->uio_rw == UIO_READ) {
|
||||||
lk = con_userlock_read;
|
lk = con_userlock_read;
|
||||||
}
|
} else {
|
||||||
else {
|
lk = con_userlock_write;
|
||||||
lk = con_userlock_write;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
KASSERT(lk != NULL);
|
KASSERT(lk != NULL);
|
||||||
lock_acquire(lk);
|
lock_acquire(lk);
|
||||||
|
|
||||||
while (uio->uio_resid > 0) {
|
while (uio->uio_resid > 0) {
|
||||||
if (uio->uio_rw==UIO_READ) {
|
if (uio->uio_rw == UIO_READ) {
|
||||||
ch = getch();
|
ch = getch();
|
||||||
if (ch=='\r') {
|
if (ch == '\r') {
|
||||||
ch = '\n';
|
ch = '\n';
|
||||||
}
|
}
|
||||||
result = uiomove(&ch, 1, uio);
|
result = uiomove(&ch, 1, uio);
|
||||||
if (result) {
|
if (result) {
|
||||||
lock_release(lk);
|
lock_release(lk);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (ch=='\n') {
|
if (ch == '\n') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
result = uiomove(&ch, 1, uio);
|
||||||
result = uiomove(&ch, 1, uio);
|
if (result) {
|
||||||
if (result) {
|
lock_release(lk);
|
||||||
lock_release(lk);
|
return result;
|
||||||
return result;
|
}
|
||||||
}
|
if (ch == '\n') {
|
||||||
if (ch=='\n') {
|
putch('\r');
|
||||||
putch('\r');
|
}
|
||||||
}
|
putch(ch);
|
||||||
putch(ch);
|
}
|
||||||
}
|
}
|
||||||
}
|
lock_release(lk);
|
||||||
lock_release(lk);
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static int con_ioctl(struct device *dev, int op, userptr_t data) {
|
||||||
int
|
/* No ioctls. */
|
||||||
con_ioctl(struct device *dev, int op, userptr_t data)
|
(void)dev;
|
||||||
{
|
(void)op;
|
||||||
/* No ioctls. */
|
(void)data;
|
||||||
(void)dev;
|
return EINVAL;
|
||||||
(void)op;
|
|
||||||
(void)data;
|
|
||||||
return EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct device_ops console_devops = {
|
static const struct device_ops console_devops = {
|
||||||
.devop_eachopen = con_eachopen,
|
.devop_eachopen = con_eachopen,
|
||||||
.devop_io = con_io,
|
.devop_io = con_io,
|
||||||
.devop_ioctl = con_ioctl,
|
.devop_ioctl = con_ioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
static
|
static int attach_console_to_vfs(struct con_softc *cs) {
|
||||||
int
|
struct device *dev;
|
||||||
attach_console_to_vfs(struct con_softc *cs)
|
int result;
|
||||||
{
|
|
||||||
struct device *dev;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
dev = kmalloc(sizeof(*dev));
|
dev = kmalloc(sizeof(*dev));
|
||||||
if (dev==NULL) {
|
if (dev == NULL) {
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->d_ops = &console_devops;
|
dev->d_ops = &console_devops;
|
||||||
dev->d_blocks = 0;
|
dev->d_blocks = 0;
|
||||||
dev->d_blocksize = 1;
|
dev->d_blocksize = 1;
|
||||||
dev->d_data = cs;
|
dev->d_data = cs;
|
||||||
|
|
||||||
result = vfs_adddev("con", dev, 0);
|
result = vfs_adddev("con", dev, 0);
|
||||||
if (result) {
|
if (result) {
|
||||||
kfree(dev);
|
kfree(dev);
|
||||||
return result;
|
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.
|
* Config routine called by autoconf.c after we are attached to something.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int config_con(struct con_softc *cs, int unit) {
|
||||||
config_con(struct con_softc *cs, int unit)
|
struct semaphore *rsem, *wsem;
|
||||||
{
|
struct lock *rlk, *wlk;
|
||||||
struct semaphore *rsem, *wsem;
|
|
||||||
struct lock *rlk, *wlk;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only allow one system console.
|
* Only allow one system console.
|
||||||
* Further devices that could be the system console are ignored.
|
* Further devices that could be the system console are ignored.
|
||||||
*
|
*
|
||||||
* Do not hardwire the console to be "con1" instead of "con0",
|
* Do not hardwire the console to be "con1" instead of "con0",
|
||||||
* or these asserts will go off.
|
* or these asserts will go off.
|
||||||
*/
|
*/
|
||||||
if (unit>0) {
|
if (unit > 0) {
|
||||||
KASSERT(the_console!=NULL);
|
KASSERT(the_console != NULL);
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
}
|
}
|
||||||
KASSERT(the_console==NULL);
|
KASSERT(the_console == NULL);
|
||||||
|
|
||||||
rsem = sem_create("console read", 0);
|
rsem = sem_create("console read", 0);
|
||||||
if (rsem == NULL) {
|
if (rsem == NULL) {
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
wsem = sem_create("console write", 1);
|
wsem = sem_create("console write", 1);
|
||||||
if (wsem == NULL) {
|
if (wsem == NULL) {
|
||||||
sem_destroy(rsem);
|
sem_destroy(rsem);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
rlk = lock_create("console-lock-read");
|
rlk = lock_create("console-lock-read");
|
||||||
if (rlk == NULL) {
|
if (rlk == NULL) {
|
||||||
sem_destroy(rsem);
|
sem_destroy(rsem);
|
||||||
sem_destroy(wsem);
|
sem_destroy(wsem);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
wlk = lock_create("console-lock-write");
|
wlk = lock_create("console-lock-write");
|
||||||
if (wlk == NULL) {
|
if (wlk == NULL) {
|
||||||
lock_destroy(rlk);
|
lock_destroy(rlk);
|
||||||
sem_destroy(rsem);
|
sem_destroy(rsem);
|
||||||
sem_destroy(wsem);
|
sem_destroy(wsem);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
cs->cs_rsem = rsem;
|
cs->cs_rsem = rsem;
|
||||||
cs->cs_wsem = wsem;
|
cs->cs_wsem = wsem;
|
||||||
cs->cs_gotchars_head = 0;
|
cs->cs_gotchars_head = 0;
|
||||||
cs->cs_gotchars_tail = 0;
|
cs->cs_gotchars_tail = 0;
|
||||||
|
|
||||||
the_console = cs;
|
the_console = cs;
|
||||||
con_userlock_read = rlk;
|
con_userlock_read = rlk;
|
||||||
con_userlock_write = wlk;
|
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
|
#define CONSOLE_INPUT_BUFFER_SIZE 32
|
||||||
|
|
||||||
struct con_softc {
|
struct con_softc {
|
||||||
/* initialized by attach routine */
|
/* initialized by attach routine */
|
||||||
void *cs_devdata;
|
void *cs_devdata;
|
||||||
void (*cs_send)(void *devdata, int ch);
|
void (*cs_send)(void *devdata, int ch);
|
||||||
void (*cs_sendpolled)(void *devdata, int ch);
|
void (*cs_sendpolled)(void *devdata, int ch);
|
||||||
|
|
||||||
/* initialized by config routine */
|
/* initialized by config routine */
|
||||||
struct semaphore *cs_rsem;
|
struct semaphore *cs_rsem;
|
||||||
struct semaphore *cs_wsem;
|
struct semaphore *cs_wsem;
|
||||||
unsigned char cs_gotchars[CONSOLE_INPUT_BUFFER_SIZE];
|
unsigned char cs_gotchars[CONSOLE_INPUT_BUFFER_SIZE];
|
||||||
unsigned cs_gotchars_head; /* next slot to put a char in */
|
unsigned cs_gotchars_head; /* next slot to put a char in */
|
||||||
unsigned cs_gotchars_tail; /* next slot to take a char out */
|
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.
|
* VFS device functions.
|
||||||
* open: allow reading only.
|
* open: allow reading only.
|
||||||
*/
|
*/
|
||||||
static
|
static int randeachopen(struct device *dev, int openflags) {
|
||||||
int
|
(void)dev;
|
||||||
randeachopen(struct device *dev, int openflags)
|
|
||||||
{
|
|
||||||
(void)dev;
|
|
||||||
|
|
||||||
if (openflags != O_RDONLY) {
|
if (openflags != O_RDONLY) {
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VFS I/O function. Hand off to implementation.
|
* VFS I/O function. Hand off to implementation.
|
||||||
*/
|
*/
|
||||||
static
|
static int randio(struct device *dev, struct uio *uio) {
|
||||||
int
|
struct random_softc *rs = dev->d_data;
|
||||||
randio(struct device *dev, struct uio *uio)
|
|
||||||
{
|
|
||||||
struct random_softc *rs = dev->d_data;
|
|
||||||
|
|
||||||
if (uio->uio_rw != UIO_READ) {
|
if (uio->uio_rw != UIO_READ) {
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rs->rs_read(rs->rs_devdata, uio);
|
return rs->rs_read(rs->rs_devdata, uio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VFS ioctl function.
|
* VFS ioctl function.
|
||||||
*/
|
*/
|
||||||
static
|
static int randioctl(struct device *dev, int op, userptr_t data) {
|
||||||
int
|
/*
|
||||||
randioctl(struct device *dev, int op, userptr_t data)
|
* We don't support any ioctls.
|
||||||
{
|
*/
|
||||||
/*
|
(void)dev;
|
||||||
* We don't support any ioctls.
|
(void)op;
|
||||||
*/
|
(void)data;
|
||||||
(void)dev;
|
return EIOCTL;
|
||||||
(void)op;
|
|
||||||
(void)data;
|
|
||||||
return EIOCTL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct device_ops random_devops = {
|
static const struct device_ops random_devops = {
|
||||||
.devop_eachopen = randeachopen,
|
.devop_eachopen = randeachopen,
|
||||||
.devop_io = randio,
|
.devop_io = randio,
|
||||||
.devop_ioctl = randioctl,
|
.devop_ioctl = randioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Config function.
|
* Config function.
|
||||||
*/
|
*/
|
||||||
int
|
int config_random(struct random_softc *rs, int unit) {
|
||||||
config_random(struct random_softc *rs, int unit)
|
int result;
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
/* We use only the first random device. */
|
/* We use only the first random device. */
|
||||||
if (unit!=0) {
|
if (unit != 0) {
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
KASSERT(the_random==NULL);
|
KASSERT(the_random == NULL);
|
||||||
the_random = rs;
|
the_random = rs;
|
||||||
|
|
||||||
rs->rs_dev.d_ops = &random_devops;
|
rs->rs_dev.d_ops = &random_devops;
|
||||||
rs->rs_dev.d_blocks = 0;
|
rs->rs_dev.d_blocks = 0;
|
||||||
rs->rs_dev.d_blocksize = 1;
|
rs->rs_dev.d_blocksize = 1;
|
||||||
rs->rs_dev.d_data = rs;
|
rs->rs_dev.d_data = rs;
|
||||||
|
|
||||||
/* Add the VFS device structure to the VFS device list. */
|
/* Add the VFS device structure to the VFS device list. */
|
||||||
result = vfs_adddev("random", &rs->rs_dev, 0);
|
result = vfs_adddev("random", &rs->rs_dev, 0);
|
||||||
if (result) {
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Random number functions exported to the rest of the kernel.
|
* Random number functions exported to the rest of the kernel.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint32_t
|
uint32_t random(void) {
|
||||||
random(void)
|
if (the_random == NULL) {
|
||||||
{
|
panic("No random device\n");
|
||||||
if (the_random==NULL) {
|
}
|
||||||
panic("No random device\n");
|
return the_random->rs_random(the_random->rs_devdata);
|
||||||
}
|
|
||||||
return the_random->rs_random(the_random->rs_devdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t randmax(void) {
|
||||||
randmax(void)
|
if (the_random == NULL) {
|
||||||
{
|
panic("No random device\n");
|
||||||
if (the_random==NULL) {
|
}
|
||||||
panic("No random device\n");
|
return the_random->rs_randmax(the_random->rs_devdata);
|
||||||
}
|
|
||||||
return the_random->rs_randmax(the_random->rs_devdata);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,13 +34,13 @@
|
|||||||
struct uio;
|
struct uio;
|
||||||
|
|
||||||
struct random_softc {
|
struct random_softc {
|
||||||
/* Initialized by lower-level attach routine */
|
/* Initialized by lower-level attach routine */
|
||||||
void *rs_devdata;
|
void *rs_devdata;
|
||||||
uint32_t (*rs_random)(void *devdata);
|
uint32_t (*rs_random)(void *devdata);
|
||||||
uint32_t (*rs_randmax)(void *devdata);
|
uint32_t (*rs_randmax)(void *devdata);
|
||||||
int (*rs_read)(void *devdata, struct uio *uio);
|
int (*rs_read)(void *devdata, struct uio *uio);
|
||||||
|
|
||||||
struct device rs_dev;
|
struct device rs_dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _GENERIC_RANDOM_H_ */
|
#endif /* _GENERIC_RANDOM_H_ */
|
||||||
|
|||||||
@@ -49,22 +49,18 @@
|
|||||||
|
|
||||||
static struct rtclock_softc *the_clock = NULL;
|
static struct rtclock_softc *the_clock = NULL;
|
||||||
|
|
||||||
int
|
int config_rtclock(struct rtclock_softc *rtc, int unit) {
|
||||||
config_rtclock(struct rtclock_softc *rtc, int unit)
|
/* We use only the first clock device. */
|
||||||
{
|
if (unit != 0) {
|
||||||
/* We use only the first clock device. */
|
return ENODEV;
|
||||||
if (unit!=0) {
|
}
|
||||||
return ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
KASSERT(the_clock==NULL);
|
KASSERT(the_clock == NULL);
|
||||||
the_clock = rtc;
|
the_clock = rtc;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void gettime(struct timespec *ts) {
|
||||||
gettime(struct timespec *ts)
|
KASSERT(the_clock != NULL);
|
||||||
{
|
the_clock->rtc_gettime(the_clock->rtc_devdata, ts);
|
||||||
KASSERT(the_clock!=NULL);
|
|
||||||
the_clock->rtc_gettime(the_clock->rtc_devdata, ts);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,8 +38,8 @@
|
|||||||
struct timespec;
|
struct timespec;
|
||||||
|
|
||||||
struct rtclock_softc {
|
struct rtclock_softc {
|
||||||
void *rtc_devdata;
|
void *rtc_devdata;
|
||||||
void (*rtc_gettime)(void *devdata, struct timespec *);
|
void (*rtc_gettime)(void *devdata, struct timespec *);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _GENERIC_RTCLOCK_H_ */
|
#endif /* _GENERIC_RTCLOCK_H_ */
|
||||||
|
|||||||
@@ -38,18 +38,16 @@
|
|||||||
#include <lamebus/ltimer.h>
|
#include <lamebus/ltimer.h>
|
||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
struct beep_softc *
|
struct beep_softc *attach_beep_to_ltimer(int beepno, struct ltimer_softc *ls) {
|
||||||
attach_beep_to_ltimer(int beepno, struct ltimer_softc *ls)
|
struct beep_softc *bs = kmalloc(sizeof(struct beep_softc));
|
||||||
{
|
if (bs == NULL) {
|
||||||
struct beep_softc *bs = kmalloc(sizeof(struct beep_softc));
|
return NULL;
|
||||||
if (bs==NULL) {
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)beepno; // unused
|
(void)beepno; // unused
|
||||||
|
|
||||||
bs->bs_devdata = ls;
|
bs->bs_devdata = ls;
|
||||||
bs->bs_beep = ltimer_beep;
|
bs->bs_beep = ltimer_beep;
|
||||||
|
|
||||||
return bs;
|
return bs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,22 +38,19 @@
|
|||||||
#include <lamebus/lscreen.h>
|
#include <lamebus/lscreen.h>
|
||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
struct con_softc *
|
struct con_softc *attach_con_to_lscreen(int consno, struct lscreen_softc *ls) {
|
||||||
attach_con_to_lscreen(int consno, struct lscreen_softc *ls)
|
struct con_softc *cs = kmalloc(sizeof(struct con_softc));
|
||||||
{
|
if (cs == NULL) {
|
||||||
struct con_softc *cs = kmalloc(sizeof(struct con_softc));
|
return NULL;
|
||||||
if (cs==NULL) {
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cs->cs_devdata = ls;
|
cs->cs_devdata = ls;
|
||||||
cs->cs_send = lscreen_write;
|
cs->cs_send = lscreen_write;
|
||||||
cs->cs_sendpolled = lscreen_write;
|
cs->cs_sendpolled = lscreen_write;
|
||||||
|
|
||||||
ls->ls_devdata = cs;
|
ls->ls_devdata = cs;
|
||||||
ls->ls_start = con_start;
|
ls->ls_start = con_start;
|
||||||
ls->ls_input = con_input;
|
ls->ls_input = con_input;
|
||||||
|
|
||||||
return cs;
|
return cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,24 +38,21 @@
|
|||||||
#include <lamebus/lser.h>
|
#include <lamebus/lser.h>
|
||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
struct con_softc *
|
struct con_softc *attach_con_to_lser(int consno, struct lser_softc *ls) {
|
||||||
attach_con_to_lser(int consno, struct lser_softc *ls)
|
struct con_softc *cs = kmalloc(sizeof(struct con_softc));
|
||||||
{
|
if (cs == NULL) {
|
||||||
struct con_softc *cs = kmalloc(sizeof(struct con_softc));
|
return NULL;
|
||||||
if (cs==NULL) {
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)consno; // unused
|
(void)consno; // unused
|
||||||
|
|
||||||
cs->cs_devdata = ls;
|
cs->cs_devdata = ls;
|
||||||
cs->cs_send = lser_write;
|
cs->cs_send = lser_write;
|
||||||
cs->cs_sendpolled = lser_writepolled;
|
cs->cs_sendpolled = lser_writepolled;
|
||||||
|
|
||||||
ls->ls_devdata = cs;
|
ls->ls_devdata = cs;
|
||||||
ls->ls_start = con_start;
|
ls->ls_start = con_start;
|
||||||
ls->ls_input = con_input;
|
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_
|
#ifndef _LAMEBUS_EMU_H_
|
||||||
#define _LAMEBUS_EMU_H_
|
#define _LAMEBUS_EMU_H_
|
||||||
|
|
||||||
|
#define EMU_MAXIO 16384
|
||||||
#define EMU_MAXIO 16384
|
#define EMU_ROOTHANDLE 0
|
||||||
#define EMU_ROOTHANDLE 0
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The per-device data used by the emufs device driver.
|
* The per-device data used by the emufs device driver.
|
||||||
@@ -41,22 +40,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct emu_softc {
|
struct emu_softc {
|
||||||
/* Initialized by lower-level attach code */
|
/* Initialized by lower-level attach code */
|
||||||
void *e_busdata;
|
void *e_busdata;
|
||||||
uint32_t e_buspos;
|
uint32_t e_buspos;
|
||||||
int e_unit;
|
int e_unit;
|
||||||
|
|
||||||
/* Initialized by config_emu() */
|
/* Initialized by config_emu() */
|
||||||
struct lock *e_lock;
|
struct lock *e_lock;
|
||||||
struct semaphore *e_sem;
|
struct semaphore *e_sem;
|
||||||
void *e_iobuf;
|
void *e_iobuf;
|
||||||
|
|
||||||
/* Written by the interrupt handler */
|
/* Written by the interrupt handler */
|
||||||
uint32_t e_result;
|
uint32_t e_result;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Functions called by lower-level drivers */
|
/* Functions called by lower-level drivers */
|
||||||
void emu_irq(/*struct emu_softc*/ void *);
|
void emu_irq(/*struct emu_softc*/ void *);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _LAMEBUS_EMU_H_ */
|
#endif /* _LAMEBUS_EMU_H_ */
|
||||||
|
|||||||
@@ -38,29 +38,27 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Lowest revision we support */
|
/* Lowest revision we support */
|
||||||
#define LOW_VERSION 1
|
#define LOW_VERSION 1
|
||||||
|
|
||||||
struct emu_softc *
|
struct emu_softc *attach_emu_to_lamebus(int emuno, struct lamebus_softc *sc) {
|
||||||
attach_emu_to_lamebus(int emuno, struct lamebus_softc *sc)
|
struct emu_softc *es;
|
||||||
{
|
int slot =
|
||||||
struct emu_softc *es;
|
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_EMUFS, LOW_VERSION, NULL);
|
||||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_EMUFS,
|
if (slot < 0) {
|
||||||
LOW_VERSION, NULL);
|
return NULL;
|
||||||
if (slot < 0) {
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
es = kmalloc(sizeof(struct emu_softc));
|
es = kmalloc(sizeof(struct emu_softc));
|
||||||
if (es==NULL) {
|
if (es == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
es->e_busdata = sc;
|
es->e_busdata = sc;
|
||||||
es->e_buspos = slot;
|
es->e_buspos = slot;
|
||||||
es->e_unit = emuno;
|
es->e_unit = emuno;
|
||||||
|
|
||||||
lamebus_mark(sc, slot);
|
lamebus_mark(sc, slot);
|
||||||
lamebus_attach_interrupt(sc, slot, es, emu_irq);
|
lamebus_attach_interrupt(sc, slot, es, emu_irq);
|
||||||
|
|
||||||
return es;
|
return es;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,147 +40,124 @@
|
|||||||
#include <lamebus/lamebus.h>
|
#include <lamebus/lamebus.h>
|
||||||
|
|
||||||
/* Register offsets within each config region */
|
/* Register offsets within each config region */
|
||||||
#define CFGREG_VID 0 /* Vendor ID */
|
#define CFGREG_VID 0 /* Vendor ID */
|
||||||
#define CFGREG_DID 4 /* Device ID */
|
#define CFGREG_DID 4 /* Device ID */
|
||||||
#define CFGREG_DRL 8 /* Device Revision Level */
|
#define CFGREG_DRL 8 /* Device Revision Level */
|
||||||
|
|
||||||
/* LAMEbus controller private registers (offsets within its config region) */
|
/* LAMEbus controller private registers (offsets within its config region) */
|
||||||
#define CTLREG_RAMSZ 0x200
|
#define CTLREG_RAMSZ 0x200
|
||||||
#define CTLREG_IRQS 0x204
|
#define CTLREG_IRQS 0x204
|
||||||
#define CTLREG_PWR 0x208
|
#define CTLREG_PWR 0x208
|
||||||
#define CTLREG_IRQE 0x20c
|
#define CTLREG_IRQE 0x20c
|
||||||
#define CTLREG_CPUS 0x210
|
#define CTLREG_CPUS 0x210
|
||||||
#define CTLREG_CPUE 0x214
|
#define CTLREG_CPUE 0x214
|
||||||
#define CTLREG_SELF 0x218
|
#define CTLREG_SELF 0x218
|
||||||
|
|
||||||
/* LAMEbus CPU control registers (offsets within each per-cpu region) */
|
/* LAMEbus CPU control registers (offsets within each per-cpu region) */
|
||||||
#define CTLCPU_CIRQE 0x000
|
#define CTLCPU_CIRQE 0x000
|
||||||
#define CTLCPU_CIPI 0x004
|
#define CTLCPU_CIPI 0x004
|
||||||
#define CTLCPU_CRAM 0x300
|
#define CTLCPU_CRAM 0x300
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a config register for the given slot.
|
* Read a config register for the given slot.
|
||||||
*/
|
*/
|
||||||
static
|
static inline uint32_t read_cfg_register(struct lamebus_softc *lb, int slot,
|
||||||
inline
|
uint32_t offset) {
|
||||||
uint32_t
|
/* Note that lb might be NULL on some platforms in some contexts. */
|
||||||
read_cfg_register(struct lamebus_softc *lb, int slot, uint32_t offset)
|
offset += LB_CONFIG_SIZE * slot;
|
||||||
{
|
return lamebus_read_register(lb, LB_CONTROLLER_SLOT, 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.
|
* Write a config register for a given slot.
|
||||||
*/
|
*/
|
||||||
static
|
static inline void write_cfg_register(struct lamebus_softc *lb, int slot,
|
||||||
inline
|
uint32_t offset, uint32_t val) {
|
||||||
void
|
offset += LB_CONFIG_SIZE * slot;
|
||||||
write_cfg_register(struct lamebus_softc *lb, int slot, uint32_t offset,
|
lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val);
|
||||||
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.
|
* Read one of the bus controller's registers.
|
||||||
*/
|
*/
|
||||||
static
|
static inline uint32_t read_ctl_register(struct lamebus_softc *lb,
|
||||||
inline
|
uint32_t offset) {
|
||||||
uint32_t
|
/* Note that lb might be NULL on some platforms in some contexts. */
|
||||||
read_ctl_register(struct lamebus_softc *lb, uint32_t offset)
|
return read_cfg_register(lb, LB_CONTROLLER_SLOT, 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.
|
* Write one of the bus controller's registers.
|
||||||
*/
|
*/
|
||||||
static
|
static inline void write_ctl_register(struct lamebus_softc *lb, uint32_t offset,
|
||||||
inline
|
uint32_t val) {
|
||||||
void
|
write_cfg_register(lb, LB_CONTROLLER_SLOT, offset, val);
|
||||||
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.
|
* Write one of the bus controller's CPU control registers.
|
||||||
*/
|
*/
|
||||||
static
|
static inline void write_ctlcpu_register(struct lamebus_softc *lb,
|
||||||
inline
|
unsigned hw_cpunum, uint32_t offset,
|
||||||
void
|
uint32_t val) {
|
||||||
write_ctlcpu_register(struct lamebus_softc *lb, unsigned hw_cpunum,
|
offset += LB_CTLCPU_OFFSET + hw_cpunum * LB_CTLCPU_SIZE;
|
||||||
uint32_t offset, uint32_t val)
|
lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val);
|
||||||
{
|
|
||||||
offset += LB_CTLCPU_OFFSET + hw_cpunum * LB_CTLCPU_SIZE;
|
|
||||||
lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find and create secondary CPUs.
|
* Find and create secondary CPUs.
|
||||||
*/
|
*/
|
||||||
void
|
void lamebus_find_cpus(struct lamebus_softc *lamebus) {
|
||||||
lamebus_find_cpus(struct lamebus_softc *lamebus)
|
uint32_t mainboard_vid, mainboard_did;
|
||||||
{
|
uint32_t cpumask, self, bit, val;
|
||||||
uint32_t mainboard_vid, mainboard_did;
|
unsigned i, numcpus, bootcpu;
|
||||||
uint32_t cpumask, self, bit, val;
|
unsigned hwnum[32];
|
||||||
unsigned i, numcpus, bootcpu;
|
|
||||||
unsigned hwnum[32];
|
|
||||||
|
|
||||||
mainboard_vid = read_cfg_register(lamebus, LB_CONTROLLER_SLOT,
|
mainboard_vid = read_cfg_register(lamebus, LB_CONTROLLER_SLOT, CFGREG_VID);
|
||||||
CFGREG_VID);
|
mainboard_did = read_cfg_register(lamebus, LB_CONTROLLER_SLOT, CFGREG_DID);
|
||||||
mainboard_did = read_cfg_register(lamebus, LB_CONTROLLER_SLOT,
|
if (mainboard_vid == LB_VENDOR_CS161 && mainboard_did == LBCS161_UPBUSCTL) {
|
||||||
CFGREG_DID);
|
/* Old uniprocessor mainboard; no cpu registers. */
|
||||||
if (mainboard_vid == LB_VENDOR_CS161 &&
|
lamebus->ls_uniprocessor = 1;
|
||||||
mainboard_did == LBCS161_UPBUSCTL) {
|
return;
|
||||||
/* Old uniprocessor mainboard; no cpu registers. */
|
}
|
||||||
lamebus->ls_uniprocessor = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
|
cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
|
||||||
self = read_ctl_register(lamebus, CTLREG_SELF);
|
self = read_ctl_register(lamebus, CTLREG_SELF);
|
||||||
|
|
||||||
numcpus = 0;
|
numcpus = 0;
|
||||||
bootcpu = 0;
|
bootcpu = 0;
|
||||||
for (i=0; i<32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
bit = (uint32_t)1 << i;
|
bit = (uint32_t)1 << i;
|
||||||
if ((cpumask & bit) != 0) {
|
if ((cpumask & bit) != 0) {
|
||||||
if (self & bit) {
|
if (self & bit) {
|
||||||
bootcpu = numcpus;
|
bootcpu = numcpus;
|
||||||
curcpu->c_hardware_number = i;
|
curcpu->c_hardware_number = i;
|
||||||
}
|
}
|
||||||
hwnum[numcpus] = i;
|
hwnum[numcpus] = i;
|
||||||
numcpus++;
|
numcpus++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<numcpus; i++) {
|
for (i = 0; i < numcpus; i++) {
|
||||||
if (i != bootcpu) {
|
if (i != bootcpu) {
|
||||||
cpu_create(hwnum[i]);
|
cpu_create(hwnum[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* By default, route all interrupts only to the boot cpu. We
|
* By default, route all interrupts only to the boot cpu. We
|
||||||
* could be arbitrarily more elaborate, up to things like
|
* could be arbitrarily more elaborate, up to things like
|
||||||
* dynamic load balancing.
|
* dynamic load balancing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (i=0; i<numcpus; i++) {
|
for (i = 0; i < numcpus; i++) {
|
||||||
if (i != bootcpu) {
|
if (i != bootcpu) {
|
||||||
val = 0;
|
val = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
val = 0xffffffff;
|
||||||
val = 0xffffffff;
|
}
|
||||||
}
|
write_ctlcpu_register(lamebus, hwnum[i], CTLCPU_CIRQE, val);
|
||||||
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
|
* LAMEbus; if in some environment there are other CPUs about as well
|
||||||
* this logic will have to be made more complex.
|
* this logic will have to be made more complex.
|
||||||
*/
|
*/
|
||||||
void
|
void lamebus_start_cpus(struct lamebus_softc *lamebus) {
|
||||||
lamebus_start_cpus(struct lamebus_softc *lamebus)
|
uint32_t cpumask, self, bit;
|
||||||
{
|
uint32_t ctlcpuoffset;
|
||||||
uint32_t cpumask, self, bit;
|
uint32_t *cram;
|
||||||
uint32_t ctlcpuoffset;
|
unsigned i;
|
||||||
uint32_t *cram;
|
unsigned cpunum;
|
||||||
unsigned i;
|
|
||||||
unsigned cpunum;
|
|
||||||
|
|
||||||
if (lamebus->ls_uniprocessor) {
|
if (lamebus->ls_uniprocessor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
|
cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
|
||||||
self = read_ctl_register(lamebus, CTLREG_SELF);
|
self = read_ctl_register(lamebus, CTLREG_SELF);
|
||||||
|
|
||||||
/* Poke in the startup address. */
|
/* Poke in the startup address. */
|
||||||
cpunum = 1;
|
cpunum = 1;
|
||||||
for (i=0; i<32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
bit = (uint32_t)1 << i;
|
bit = (uint32_t)1 << i;
|
||||||
if ((cpumask & bit) != 0) {
|
if ((cpumask & bit) != 0) {
|
||||||
if (self & bit) {
|
if (self & bit) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ctlcpuoffset = LB_CTLCPU_OFFSET + i * LB_CTLCPU_SIZE;
|
ctlcpuoffset = LB_CTLCPU_OFFSET + i * LB_CTLCPU_SIZE;
|
||||||
cram = lamebus_map_area(lamebus,
|
cram = lamebus_map_area(lamebus, LB_CONTROLLER_SLOT,
|
||||||
LB_CONTROLLER_SLOT,
|
ctlcpuoffset + CTLCPU_CRAM);
|
||||||
ctlcpuoffset + CTLCPU_CRAM);
|
cram[0] = (uint32_t)cpu_start_secondary;
|
||||||
cram[0] = (uint32_t)cpu_start_secondary;
|
cram[1] = cpunum++;
|
||||||
cram[1] = cpunum++;
|
}
|
||||||
}
|
}
|
||||||
}
|
/* Ensure all the above writes get flushed. */
|
||||||
/* Ensure all the above writes get flushed. */
|
membar_store_store();
|
||||||
membar_store_store();
|
|
||||||
|
|
||||||
/* Now, enable them all. */
|
/* Now, enable them all. */
|
||||||
write_ctl_register(lamebus, CTLREG_CPUE, cpumask);
|
write_ctl_register(lamebus, CTLREG_CPUE, cpumask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -247,58 +221,55 @@ lamebus_start_cpus(struct lamebus_softc *lamebus)
|
|||||||
* more specific checks.
|
* more specific checks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int lamebus_probe(struct lamebus_softc *sc, uint32_t vendorid,
|
||||||
lamebus_probe(struct lamebus_softc *sc,
|
uint32_t deviceid, uint32_t lowver, uint32_t *version_ret) {
|
||||||
uint32_t vendorid, uint32_t deviceid,
|
int slot;
|
||||||
uint32_t lowver, uint32_t *version_ret)
|
uint32_t val;
|
||||||
{
|
|
||||||
int slot;
|
|
||||||
uint32_t val;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Because the slot information in sc is used when dispatching
|
* Because the slot information in sc is used when dispatching
|
||||||
* interrupts, disable interrupts while working with it.
|
* interrupts, disable interrupts while working with it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
spinlock_acquire(&sc->ls_lock);
|
spinlock_acquire(&sc->ls_lock);
|
||||||
|
|
||||||
for (slot=0; slot<LB_NSLOTS; slot++) {
|
for (slot = 0; slot < LB_NSLOTS; slot++) {
|
||||||
if (sc->ls_slotsinuse & (1<<slot)) {
|
if (sc->ls_slotsinuse & (1 << slot)) {
|
||||||
/* Slot already in use; skip */
|
/* Slot already in use; skip */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
val = read_cfg_register(sc, slot, CFGREG_VID);
|
val = read_cfg_register(sc, slot, CFGREG_VID);
|
||||||
if (val!=vendorid) {
|
if (val != vendorid) {
|
||||||
/* Wrong vendor id */
|
/* Wrong vendor id */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
val = read_cfg_register(sc, slot, CFGREG_DID);
|
val = read_cfg_register(sc, slot, CFGREG_DID);
|
||||||
if (val != deviceid) {
|
if (val != deviceid) {
|
||||||
/* Wrong device id */
|
/* Wrong device id */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
val = read_cfg_register(sc, slot, CFGREG_DRL);
|
val = read_cfg_register(sc, slot, CFGREG_DRL);
|
||||||
if (val < lowver) {
|
if (val < lowver) {
|
||||||
/* Unsupported device revision */
|
/* Unsupported device revision */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (version_ret != NULL) {
|
if (version_ret != NULL) {
|
||||||
*version_ret = val;
|
*version_ret = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Found something */
|
/* Found something */
|
||||||
|
|
||||||
spinlock_release(&sc->ls_lock);
|
spinlock_release(&sc->ls_lock);
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Found nothing */
|
/* Found nothing */
|
||||||
|
|
||||||
spinlock_release(&sc->ls_lock);
|
spinlock_release(&sc->ls_lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -306,360 +277,328 @@ lamebus_probe(struct lamebus_softc *sc,
|
|||||||
* This prevents the probe routine from returning the same device over
|
* This prevents the probe routine from returning the same device over
|
||||||
* and over again.
|
* and over again.
|
||||||
*/
|
*/
|
||||||
void
|
void lamebus_mark(struct lamebus_softc *sc, int slot) {
|
||||||
lamebus_mark(struct lamebus_softc *sc, int slot)
|
uint32_t mask = ((uint32_t)1) << slot;
|
||||||
{
|
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||||
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) {
|
if ((sc->ls_slotsinuse & mask) != 0) {
|
||||||
panic("lamebus_mark: slot %d already in use\n", slot);
|
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.
|
* Mark that a slot is no longer in use.
|
||||||
*/
|
*/
|
||||||
void
|
void lamebus_unmark(struct lamebus_softc *sc, int slot) {
|
||||||
lamebus_unmark(struct lamebus_softc *sc, int slot)
|
uint32_t mask = ((uint32_t)1) << slot;
|
||||||
{
|
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||||
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) {
|
if ((sc->ls_slotsinuse & mask) == 0) {
|
||||||
panic("lamebus_mark: slot %d not marked in use\n", slot);
|
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
|
* Register a function (and a device context pointer) to be called
|
||||||
* when a particular slot signals an interrupt.
|
* when a particular slot signals an interrupt.
|
||||||
*/
|
*/
|
||||||
void
|
void lamebus_attach_interrupt(struct lamebus_softc *sc, int slot, void *devdata,
|
||||||
lamebus_attach_interrupt(struct lamebus_softc *sc, int slot,
|
void (*irqfunc)(void *devdata)) {
|
||||||
void *devdata,
|
uint32_t mask = ((uint32_t)1) << slot;
|
||||||
void (*irqfunc)(void *devdata))
|
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||||
{
|
|
||||||
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) {
|
if ((sc->ls_slotsinuse & mask) == 0) {
|
||||||
panic("lamebus_attach_interrupt: slot %d not marked in use\n",
|
panic("lamebus_attach_interrupt: slot %d not marked in use\n", slot);
|
||||||
slot);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
KASSERT(sc->ls_devdata[slot]==NULL);
|
KASSERT(sc->ls_devdata[slot] == NULL);
|
||||||
KASSERT(sc->ls_irqfuncs[slot]==NULL);
|
KASSERT(sc->ls_irqfuncs[slot] == NULL);
|
||||||
|
|
||||||
sc->ls_devdata[slot] = devdata;
|
sc->ls_devdata[slot] = devdata;
|
||||||
sc->ls_irqfuncs[slot] = irqfunc;
|
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
|
* Unregister a function that was being called when a particular slot
|
||||||
* signaled an interrupt.
|
* signaled an interrupt.
|
||||||
*/
|
*/
|
||||||
void
|
void lamebus_detach_interrupt(struct lamebus_softc *sc, int slot) {
|
||||||
lamebus_detach_interrupt(struct lamebus_softc *sc, int slot)
|
uint32_t mask = ((uint32_t)1) << slot;
|
||||||
{
|
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||||
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) {
|
if ((sc->ls_slotsinuse & mask) == 0) {
|
||||||
panic("lamebus_detach_interrupt: slot %d not marked in use\n",
|
panic("lamebus_detach_interrupt: slot %d not marked in use\n", slot);
|
||||||
slot);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
KASSERT(sc->ls_irqfuncs[slot]!=NULL);
|
KASSERT(sc->ls_irqfuncs[slot] != NULL);
|
||||||
|
|
||||||
sc->ls_devdata[slot] = NULL;
|
sc->ls_devdata[slot] = NULL;
|
||||||
sc->ls_irqfuncs[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.
|
* Mask/unmask an interrupt using the global IRQE register.
|
||||||
*/
|
*/
|
||||||
void
|
void lamebus_mask_interrupt(struct lamebus_softc *lamebus, int slot) {
|
||||||
lamebus_mask_interrupt(struct lamebus_softc *lamebus, int slot)
|
uint32_t bits, mask = ((uint32_t)1) << slot;
|
||||||
{
|
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||||
uint32_t bits, mask = ((uint32_t)1) << slot;
|
|
||||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
|
||||||
|
|
||||||
spinlock_acquire(&lamebus->ls_lock);
|
spinlock_acquire(&lamebus->ls_lock);
|
||||||
bits = read_ctl_register(lamebus, CTLREG_IRQE);
|
bits = read_ctl_register(lamebus, CTLREG_IRQE);
|
||||||
bits &= ~mask;
|
bits &= ~mask;
|
||||||
write_ctl_register(lamebus, CTLREG_IRQE, bits);
|
write_ctl_register(lamebus, CTLREG_IRQE, bits);
|
||||||
spinlock_release(&lamebus->ls_lock);
|
spinlock_release(&lamebus->ls_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void lamebus_unmask_interrupt(struct lamebus_softc *lamebus, int slot) {
|
||||||
lamebus_unmask_interrupt(struct lamebus_softc *lamebus, int slot)
|
uint32_t bits, mask = ((uint32_t)1) << slot;
|
||||||
{
|
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||||
uint32_t bits, mask = ((uint32_t)1) << slot;
|
|
||||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
|
||||||
|
|
||||||
spinlock_acquire(&lamebus->ls_lock);
|
spinlock_acquire(&lamebus->ls_lock);
|
||||||
bits = read_ctl_register(lamebus, CTLREG_IRQE);
|
bits = read_ctl_register(lamebus, CTLREG_IRQE);
|
||||||
bits |= mask;
|
bits |= mask;
|
||||||
write_ctl_register(lamebus, CTLREG_IRQE, bits);
|
write_ctl_register(lamebus, CTLREG_IRQE, bits);
|
||||||
spinlock_release(&lamebus->ls_lock);
|
spinlock_release(&lamebus->ls_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LAMEbus interrupt handling function. (Machine-independent!)
|
* LAMEbus interrupt handling function. (Machine-independent!)
|
||||||
*/
|
*/
|
||||||
void
|
void lamebus_interrupt(struct lamebus_softc *lamebus) {
|
||||||
lamebus_interrupt(struct lamebus_softc *lamebus)
|
/*
|
||||||
{
|
* Note that despite the fact that "spl" stands for "set
|
||||||
/*
|
* priority level", we don't actually support interrupt
|
||||||
* Note that despite the fact that "spl" stands for "set
|
* priorities. When an interrupt happens, we look through the
|
||||||
* priority level", we don't actually support interrupt
|
* slots to find the first interrupting device and call its
|
||||||
* priorities. When an interrupt happens, we look through the
|
* interrupt routine, no matter what that device is.
|
||||||
* 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.
|
||||||
* 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;
|
int slot;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
uint32_t irqs;
|
uint32_t irqs;
|
||||||
void (*handler)(void *);
|
void (*handler)(void *);
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
/* For keeping track of how many bogus things happen in a row. */
|
/* For keeping track of how many bogus things happen in a row. */
|
||||||
static int duds = 0;
|
static int duds = 0;
|
||||||
int duds_this_time = 0;
|
int duds_this_time = 0;
|
||||||
|
|
||||||
/* and we better have a valid bus instance. */
|
/* and we better have a valid bus instance. */
|
||||||
KASSERT(lamebus != NULL);
|
KASSERT(lamebus != NULL);
|
||||||
|
|
||||||
/* Lock the softc */
|
/* Lock the softc */
|
||||||
spinlock_acquire(&lamebus->ls_lock);
|
spinlock_acquire(&lamebus->ls_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the LAMEbus controller register that tells us which
|
* Read the LAMEbus controller register that tells us which
|
||||||
* slots are asserting an interrupt condition.
|
* slots are asserting an interrupt condition.
|
||||||
*/
|
*/
|
||||||
irqs = read_ctl_register(lamebus, CTLREG_IRQS);
|
irqs = read_ctl_register(lamebus, CTLREG_IRQS);
|
||||||
|
|
||||||
if (irqs == 0) {
|
if (irqs == 0) {
|
||||||
/*
|
/*
|
||||||
* Huh? None of them? Must be a glitch.
|
* Huh? None of them? Must be a glitch.
|
||||||
*/
|
*/
|
||||||
kprintf("lamebus: stray interrupt on cpu %u\n",
|
kprintf("lamebus: stray interrupt on cpu %u\n", curcpu->c_number);
|
||||||
curcpu->c_number);
|
duds++;
|
||||||
duds++;
|
duds_this_time++;
|
||||||
duds_this_time++;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We could just return now, but instead we'll
|
* We could just return now, but instead we'll
|
||||||
* continue ahead. Because irqs == 0, nothing in the
|
* continue ahead. Because irqs == 0, nothing in the
|
||||||
* loop will execute, and passing through it gets us
|
* loop will execute, and passing through it gets us
|
||||||
* to the code that checks how many duds we've
|
* to the code that checks how many duds we've
|
||||||
* seen. This is important, because we just might get
|
* seen. This is important, because we just might get
|
||||||
* a stray interrupt that latches itself on. If that
|
* a stray interrupt that latches itself on. If that
|
||||||
* happens, we're pretty much toast, but it's better
|
* happens, we're pretty much toast, but it's better
|
||||||
* to panic and hopefully reset the system than to
|
* to panic and hopefully reset the system than to
|
||||||
* loop forever printing "stray interrupt".
|
* loop forever printing "stray interrupt".
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Go through the bits in the value we got back to see which
|
* Go through the bits in the value we got back to see which
|
||||||
* ones are set.
|
* ones are set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (mask=1, slot=0; slot<LB_NSLOTS; mask<<=1, slot++) {
|
for (mask = 1, slot = 0; slot < LB_NSLOTS; mask <<= 1, slot++) {
|
||||||
if ((irqs & mask) == 0) {
|
if ((irqs & mask) == 0) {
|
||||||
/* Nope. */
|
/* Nope. */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This slot is signalling an interrupt.
|
* This slot is signalling an interrupt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((lamebus->ls_slotsinuse & mask)==0) {
|
if ((lamebus->ls_slotsinuse & mask) == 0) {
|
||||||
/*
|
/*
|
||||||
* No device driver is using this slot.
|
* No device driver is using this slot.
|
||||||
*/
|
*/
|
||||||
duds++;
|
duds++;
|
||||||
duds_this_time++;
|
duds_this_time++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lamebus->ls_irqfuncs[slot]==NULL) {
|
if (lamebus->ls_irqfuncs[slot] == NULL) {
|
||||||
/*
|
/*
|
||||||
* The device driver hasn't installed an interrupt
|
* The device driver hasn't installed an interrupt
|
||||||
* handler.
|
* handler.
|
||||||
*/
|
*/
|
||||||
duds++;
|
duds++;
|
||||||
duds_this_time++;
|
duds_this_time++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call the interrupt handler. Release the spinlock
|
* Call the interrupt handler. Release the spinlock
|
||||||
* while we do so, in case other CPUs are handling
|
* while we do so, in case other CPUs are handling
|
||||||
* interrupts on other devices.
|
* interrupts on other devices.
|
||||||
*/
|
*/
|
||||||
handler = lamebus->ls_irqfuncs[slot];
|
handler = lamebus->ls_irqfuncs[slot];
|
||||||
data = lamebus->ls_devdata[slot];
|
data = lamebus->ls_devdata[slot];
|
||||||
spinlock_release(&lamebus->ls_lock);
|
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
|
* Reload the mask of pending IRQs - if we just called
|
||||||
* hardclock, we might not have come back to this
|
* hardclock, we might not have come back to this
|
||||||
* context for some time, and it might have changed.
|
* 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 (duds_this_time == 0 && duds > 0) {
|
||||||
* If we get interrupts for a slot with no driver or no
|
kprintf("lamebus: %d dud interrupts\n", duds);
|
||||||
* interrupt handler, it's fairly serious. Because LAMEbus
|
duds = 0;
|
||||||
* 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) {
|
if (duds > 10000) {
|
||||||
kprintf("lamebus: %d dud interrupts\n", duds);
|
panic("lamebus: too many (%d) dud interrupts\n", duds);
|
||||||
duds = 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (duds > 10000) {
|
/* Unlock the softc */
|
||||||
panic("lamebus: too many (%d) dud interrupts\n", duds);
|
spinlock_release(&lamebus->ls_lock);
|
||||||
}
|
|
||||||
|
|
||||||
/* Unlock the softc */
|
|
||||||
spinlock_release(&lamebus->ls_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Have the bus controller power the system off.
|
* Have the bus controller power the system off.
|
||||||
*/
|
*/
|
||||||
void
|
void lamebus_poweroff(struct lamebus_softc *lamebus) {
|
||||||
lamebus_poweroff(struct lamebus_softc *lamebus)
|
/*
|
||||||
{
|
* Write 0 to the power register to shut the system off.
|
||||||
/*
|
*/
|
||||||
* Write 0 to the power register to shut the system off.
|
|
||||||
*/
|
|
||||||
|
|
||||||
cpu_irqoff();
|
cpu_irqoff();
|
||||||
write_ctl_register(lamebus, CTLREG_PWR, 0);
|
write_ctl_register(lamebus, CTLREG_PWR, 0);
|
||||||
|
|
||||||
/* The power doesn't go off instantly... so halt the cpu. */
|
/* The power doesn't go off instantly... so halt the cpu. */
|
||||||
cpu_halt();
|
cpu_halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ask the bus controller how much memory we have.
|
* Ask the bus controller how much memory we have.
|
||||||
*/
|
*/
|
||||||
uint32_t
|
uint32_t lamebus_ramsize(void) {
|
||||||
lamebus_ramsize(void)
|
/*
|
||||||
{
|
* Note that this has to work before bus initialization.
|
||||||
/*
|
* On machines where lamebus_read_register doesn't work
|
||||||
* Note that this has to work before bus initialization.
|
* before bus initialization, this function can't be used
|
||||||
* On machines where lamebus_read_register doesn't work
|
* for initial RAM size lookup.
|
||||||
* 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.
|
* Turn on or off the interprocessor interrupt line for a given CPU.
|
||||||
*/
|
*/
|
||||||
void
|
void lamebus_assert_ipi(struct lamebus_softc *lamebus, struct cpu *target) {
|
||||||
lamebus_assert_ipi(struct lamebus_softc *lamebus, struct cpu *target)
|
if (lamebus->ls_uniprocessor) {
|
||||||
{
|
return;
|
||||||
if (lamebus->ls_uniprocessor) {
|
}
|
||||||
return;
|
write_ctlcpu_register(lamebus, target->c_hardware_number, CTLCPU_CIPI, 1);
|
||||||
}
|
|
||||||
write_ctlcpu_register(lamebus, target->c_hardware_number,
|
|
||||||
CTLCPU_CIPI, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void lamebus_clear_ipi(struct lamebus_softc *lamebus, struct cpu *target) {
|
||||||
lamebus_clear_ipi(struct lamebus_softc *lamebus, struct cpu *target)
|
if (lamebus->ls_uniprocessor) {
|
||||||
{
|
return;
|
||||||
if (lamebus->ls_uniprocessor) {
|
}
|
||||||
return;
|
write_ctlcpu_register(lamebus, target->c_hardware_number, CTLCPU_CIPI, 0);
|
||||||
}
|
|
||||||
write_ctlcpu_register(lamebus, target->c_hardware_number,
|
|
||||||
CTLCPU_CIPI, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initial setup.
|
* Initial setup.
|
||||||
* Should be called from mainbus_bootstrap().
|
* Should be called from mainbus_bootstrap().
|
||||||
*/
|
*/
|
||||||
struct lamebus_softc *
|
struct lamebus_softc *lamebus_init(void) {
|
||||||
lamebus_init(void)
|
struct lamebus_softc *lamebus;
|
||||||
{
|
int i;
|
||||||
struct lamebus_softc *lamebus;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Allocate space for lamebus data */
|
/* Allocate space for lamebus data */
|
||||||
lamebus = kmalloc(sizeof(struct lamebus_softc));
|
lamebus = kmalloc(sizeof(struct lamebus_softc));
|
||||||
if (lamebus==NULL) {
|
if (lamebus == NULL) {
|
||||||
panic("lamebus_init: Out of memory\n");
|
panic("lamebus_init: Out of memory\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
spinlock_init(&lamebus->ls_lock);
|
spinlock_init(&lamebus->ls_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the LAMEbus data structure.
|
* Initialize the LAMEbus data structure.
|
||||||
*/
|
*/
|
||||||
lamebus->ls_slotsinuse = 1 << LB_CONTROLLER_SLOT;
|
lamebus->ls_slotsinuse = 1 << LB_CONTROLLER_SLOT;
|
||||||
|
|
||||||
for (i=0; i<LB_NSLOTS; i++) {
|
for (i = 0; i < LB_NSLOTS; i++) {
|
||||||
lamebus->ls_devdata[i] = NULL;
|
lamebus->ls_devdata[i] = NULL;
|
||||||
lamebus->ls_irqfuncs[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.
|
* Machine-independent definitions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Vendors */
|
/* Vendors */
|
||||||
#define LB_VENDOR_CS161 1
|
#define LB_VENDOR_CS161 1
|
||||||
|
|
||||||
/* CS161 devices */
|
/* CS161 devices */
|
||||||
#define LBCS161_UPBUSCTL 1
|
#define LBCS161_UPBUSCTL 1
|
||||||
#define LBCS161_TIMER 2
|
#define LBCS161_TIMER 2
|
||||||
#define LBCS161_DISK 3
|
#define LBCS161_DISK 3
|
||||||
#define LBCS161_SERIAL 4
|
#define LBCS161_SERIAL 4
|
||||||
#define LBCS161_SCREEN 5
|
#define LBCS161_SCREEN 5
|
||||||
#define LBCS161_NET 6
|
#define LBCS161_NET 6
|
||||||
#define LBCS161_EMUFS 7
|
#define LBCS161_EMUFS 7
|
||||||
#define LBCS161_TRACE 8
|
#define LBCS161_TRACE 8
|
||||||
#define LBCS161_RANDOM 9
|
#define LBCS161_RANDOM 9
|
||||||
#define LBCS161_MPBUSCTL 10
|
#define LBCS161_MPBUSCTL 10
|
||||||
|
|
||||||
/* LAMEbus controller always goes in slot 31 */
|
/* LAMEbus controller always goes in slot 31 */
|
||||||
#define LB_CONTROLLER_SLOT 31
|
#define LB_CONTROLLER_SLOT 31
|
||||||
|
|
||||||
/* Number of slots */
|
/* Number of slots */
|
||||||
#define LB_NSLOTS 32
|
#define LB_NSLOTS 32
|
||||||
|
|
||||||
/* LAMEbus controller per-slot config space */
|
/* LAMEbus controller per-slot config space */
|
||||||
#define LB_CONFIG_SIZE 1024
|
#define LB_CONFIG_SIZE 1024
|
||||||
|
|
||||||
/* LAMEbus controller per-cpu control space */
|
/* 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 */
|
/* LAMEbus controller slot offset to per-cpu control space */
|
||||||
#define LB_CTLCPU_OFFSET 32768
|
#define LB_CTLCPU_OFFSET 32768
|
||||||
|
|
||||||
/* LAMEbus mapping size per slot */
|
/* LAMEbus mapping size per slot */
|
||||||
#define LB_SLOT_SIZE 65536
|
#define LB_SLOT_SIZE 65536
|
||||||
|
|
||||||
/* Pointer to kind of function called on interrupt */
|
/* Pointer to kind of function called on interrupt */
|
||||||
typedef void (*lb_irqfunc)(void *devdata);
|
typedef void (*lb_irqfunc)(void *devdata);
|
||||||
@@ -80,15 +79,15 @@ typedef void (*lb_irqfunc)(void *devdata);
|
|||||||
* Driver data
|
* Driver data
|
||||||
*/
|
*/
|
||||||
struct lamebus_softc {
|
struct lamebus_softc {
|
||||||
struct spinlock ls_lock;
|
struct spinlock ls_lock;
|
||||||
|
|
||||||
/* Accessed from interrupts; synchronized with ls_lock */
|
/* Accessed from interrupts; synchronized with ls_lock */
|
||||||
uint32_t ls_slotsinuse;
|
uint32_t ls_slotsinuse;
|
||||||
void *ls_devdata[LB_NSLOTS];
|
void *ls_devdata[LB_NSLOTS];
|
||||||
lb_irqfunc ls_irqfuncs[LB_NSLOTS];
|
lb_irqfunc ls_irqfuncs[LB_NSLOTS];
|
||||||
|
|
||||||
/* Read-only once set early in boot */
|
/* Read-only once set early in boot */
|
||||||
unsigned ls_uniprocessor;
|
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.
|
* Returns a slot number (0-31) or -1 if no such device is found.
|
||||||
*/
|
*/
|
||||||
int lamebus_probe(struct lamebus_softc *,
|
int lamebus_probe(struct lamebus_softc *, uint32_t vendorid, uint32_t deviceid,
|
||||||
uint32_t vendorid, uint32_t deviceid,
|
uint32_t lowver, uint32_t *version_ret);
|
||||||
uint32_t lowver, uint32_t *version_ret);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark a slot in-use (that is, has a device driver attached to it),
|
* 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.
|
* Attach to an interrupt.
|
||||||
*/
|
*/
|
||||||
void lamebus_attach_interrupt(struct lamebus_softc *, int slot,
|
void lamebus_attach_interrupt(struct lamebus_softc *, int slot, void *devdata,
|
||||||
void *devdata,
|
void (*irqfunc)(void *devdata));
|
||||||
void (*irqfunc)(void *devdata));
|
|
||||||
/*
|
/*
|
||||||
* Detach from interrupt.
|
* Detach from interrupt.
|
||||||
*/
|
*/
|
||||||
@@ -168,15 +165,13 @@ void lamebus_clear_ipi(struct lamebus_softc *, struct cpu *targetcpu);
|
|||||||
* (Machine dependent.)
|
* (Machine dependent.)
|
||||||
*/
|
*/
|
||||||
uint32_t lamebus_read_register(struct lamebus_softc *, int slot,
|
uint32_t lamebus_read_register(struct lamebus_softc *, int slot,
|
||||||
uint32_t offset);
|
uint32_t offset);
|
||||||
void lamebus_write_register(struct lamebus_softc *, int slot,
|
void lamebus_write_register(struct lamebus_softc *, int slot, uint32_t offset,
|
||||||
uint32_t offset, uint32_t val);
|
uint32_t val);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Map a buffer that starts at offset OFFSET within slot SLOT.
|
* Map a buffer that starts at offset OFFSET within slot SLOT.
|
||||||
*/
|
*/
|
||||||
void *lamebus_map_area(struct lamebus_softc *, int slot,
|
void *lamebus_map_area(struct lamebus_softc *, int slot, uint32_t offset);
|
||||||
uint32_t offset);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _LAMEBUS_H_ */
|
#endif /* _LAMEBUS_H_ */
|
||||||
|
|||||||
@@ -43,68 +43,60 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Registers (offsets within slot) */
|
/* Registers (offsets within slot) */
|
||||||
#define LHD_REG_NSECT 0 /* Number of sectors */
|
#define LHD_REG_NSECT 0 /* Number of sectors */
|
||||||
#define LHD_REG_STAT 4 /* Status */
|
#define LHD_REG_STAT 4 /* Status */
|
||||||
#define LHD_REG_SECT 8 /* Sector for I/O */
|
#define LHD_REG_SECT 8 /* Sector for I/O */
|
||||||
#define LHD_REG_RPM 12 /* Disk rotation speed (revs per minute) */
|
#define LHD_REG_RPM 12 /* Disk rotation speed (revs per minute) */
|
||||||
|
|
||||||
/* Status codes */
|
/* Status codes */
|
||||||
#define LHD_IDLE 0 /* Device idle */
|
#define LHD_IDLE 0 /* Device idle */
|
||||||
#define LHD_WORKING 1 /* Operation in progress */
|
#define LHD_WORKING 1 /* Operation in progress */
|
||||||
#define LHD_OK 4 /* Operation succeeded */
|
#define LHD_OK 4 /* Operation succeeded */
|
||||||
#define LHD_INVSECT 12 /* Invalid sector requested */
|
#define LHD_INVSECT 12 /* Invalid sector requested */
|
||||||
#define LHD_MEDIA 20 /* Media error */
|
#define LHD_MEDIA 20 /* Media error */
|
||||||
#define LHD_ISWRITE 2 /* OR with above: I/O is a write */
|
#define LHD_ISWRITE 2 /* OR with above: I/O is a write */
|
||||||
#define LHD_STATEMASK 0x1d /* mask for masking out LHD_ISWRITE */
|
#define LHD_STATEMASK 0x1d /* mask for masking out LHD_ISWRITE */
|
||||||
|
|
||||||
/* Buffer (offset within slot) */
|
/* Buffer (offset within slot) */
|
||||||
#define LHD_BUFFER 32768
|
#define LHD_BUFFER 32768
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shortcut for reading a register.
|
* Shortcut for reading a register.
|
||||||
*/
|
*/
|
||||||
static
|
static inline uint32_t lhd_rdreg(struct lhd_softc *lh, uint32_t reg) {
|
||||||
inline
|
return bus_read_register(lh->lh_busdata, lh->lh_buspos, reg);
|
||||||
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.
|
* Shortcut for writing a register.
|
||||||
*/
|
*/
|
||||||
static
|
static inline void lhd_wreg(struct lhd_softc *lh, uint32_t reg, uint32_t val) {
|
||||||
inline
|
bus_write_register(lh->lh_busdata, lh->lh_buspos, reg, val);
|
||||||
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.
|
* Convert a result code from the hardware to an errno value.
|
||||||
*/
|
*/
|
||||||
static
|
static int lhd_code_to_errno(struct lhd_softc *lh, int code) {
|
||||||
int lhd_code_to_errno(struct lhd_softc *lh, int code)
|
switch (code & LHD_STATEMASK) {
|
||||||
{
|
case LHD_OK:
|
||||||
switch (code & LHD_STATEMASK) {
|
return 0;
|
||||||
case LHD_OK: return 0;
|
case LHD_INVSECT:
|
||||||
case LHD_INVSECT: return EINVAL;
|
return EINVAL;
|
||||||
case LHD_MEDIA: return EIO;
|
case LHD_MEDIA:
|
||||||
}
|
return EIO;
|
||||||
kprintf("lhd%d: Unknown result code %d\n", lh->lh_unit, code);
|
}
|
||||||
return EAGAIN;
|
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
|
* Record that an I/O has completed: save the result and poke the
|
||||||
* completion semaphore.
|
* completion semaphore.
|
||||||
*/
|
*/
|
||||||
static
|
static void lhd_iodone(struct lhd_softc *lh, int err) {
|
||||||
void
|
lh->lh_result = err;
|
||||||
lhd_iodone(struct lhd_softc *lh, int err)
|
V(lh->lh_done);
|
||||||
{
|
|
||||||
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
|
* Read the status register; if an operation finished, clear the status
|
||||||
* register and report completion.
|
* register and report completion.
|
||||||
*/
|
*/
|
||||||
void
|
void lhd_irq(void *vlh) {
|
||||||
lhd_irq(void *vlh)
|
struct lhd_softc *lh = vlh;
|
||||||
{
|
uint32_t val;
|
||||||
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) {
|
switch (val & LHD_STATEMASK) {
|
||||||
case LHD_IDLE:
|
case LHD_IDLE:
|
||||||
case LHD_WORKING:
|
case LHD_WORKING:
|
||||||
break;
|
break;
|
||||||
case LHD_OK:
|
case LHD_OK:
|
||||||
case LHD_INVSECT:
|
case LHD_INVSECT:
|
||||||
case LHD_MEDIA:
|
case LHD_MEDIA:
|
||||||
lhd_wreg(lh, LHD_REG_STAT, 0);
|
lhd_wreg(lh, LHD_REG_STAT, 0);
|
||||||
lhd_iodone(lh, lhd_code_to_errno(lh, val));
|
lhd_iodone(lh, lhd_code_to_errno(lh, val));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function called when we are open()'d.
|
* Function called when we are open()'d.
|
||||||
*/
|
*/
|
||||||
static
|
static int lhd_eachopen(struct device *d, int openflags) {
|
||||||
int
|
/*
|
||||||
lhd_eachopen(struct device *d, int openflags)
|
* Don't need to do anything.
|
||||||
{
|
*/
|
||||||
/*
|
(void)d;
|
||||||
* Don't need to do anything.
|
(void)openflags;
|
||||||
*/
|
|
||||||
(void)d;
|
|
||||||
(void)openflags;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function for handling ioctls.
|
* Function for handling ioctls.
|
||||||
*/
|
*/
|
||||||
static
|
static int lhd_ioctl(struct device *d, int op, userptr_t data) {
|
||||||
int
|
/*
|
||||||
lhd_ioctl(struct device *d, int op, userptr_t data)
|
* We don't support any ioctls.
|
||||||
{
|
*/
|
||||||
/*
|
(void)d;
|
||||||
* We don't support any ioctls.
|
(void)op;
|
||||||
*/
|
(void)data;
|
||||||
(void)d;
|
return EIOCTL;
|
||||||
(void)op;
|
|
||||||
(void)data;
|
|
||||||
return EIOCTL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@@ -182,127 +166,122 @@ lhd_reset(struct lhd_softc *lh)
|
|||||||
/*
|
/*
|
||||||
* I/O function (for both reads and writes)
|
* I/O function (for both reads and writes)
|
||||||
*/
|
*/
|
||||||
static
|
static int lhd_io(struct device *d, struct uio *uio) {
|
||||||
int
|
struct lhd_softc *lh = d->d_data;
|
||||||
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 sector = uio->uio_offset / LHD_SECTSIZE;
|
||||||
uint32_t sectoff = uio->uio_offset % LHD_SECTSIZE;
|
uint32_t sectoff = uio->uio_offset % LHD_SECTSIZE;
|
||||||
uint32_t len = uio->uio_resid / LHD_SECTSIZE;
|
uint32_t len = uio->uio_resid / LHD_SECTSIZE;
|
||||||
uint32_t lenoff = uio->uio_resid % LHD_SECTSIZE;
|
uint32_t lenoff = uio->uio_resid % LHD_SECTSIZE;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint32_t statval = LHD_WORKING;
|
uint32_t statval = LHD_WORKING;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
/* Don't allow I/O that isn't sector-aligned. */
|
/* Don't allow I/O that isn't sector-aligned. */
|
||||||
if (sectoff != 0 || lenoff != 0) {
|
if (sectoff != 0 || lenoff != 0) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't allow I/O past the end of the disk. */
|
/* Don't allow I/O past the end of the disk. */
|
||||||
/* XXX this check can overflow */
|
/* XXX this check can overflow */
|
||||||
if (sector+len > lh->lh_dev.d_blocks) {
|
if (sector + len > lh->lh_dev.d_blocks) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up the value to write into the status register. */
|
/* Set up the value to write into the status register. */
|
||||||
if (uio->uio_rw==UIO_WRITE) {
|
if (uio->uio_rw == UIO_WRITE) {
|
||||||
statval |= LHD_ISWRITE;
|
statval |= LHD_ISWRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop over all the sectors we were asked to do. */
|
/* Loop over all the sectors we were asked to do. */
|
||||||
for (i=0; i<len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
|
|
||||||
/* Wait until nobody else is using the device. */
|
/* Wait until nobody else is using the device. */
|
||||||
P(lh->lh_clear);
|
P(lh->lh_clear);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Are we writing? If so, transfer the data to the
|
* Are we writing? If so, transfer the data to the
|
||||||
* on-card buffer.
|
* on-card buffer.
|
||||||
*/
|
*/
|
||||||
if (uio->uio_rw == UIO_WRITE) {
|
if (uio->uio_rw == UIO_WRITE) {
|
||||||
result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio);
|
result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio);
|
||||||
membar_store_store();
|
membar_store_store();
|
||||||
if (result) {
|
if (result) {
|
||||||
V(lh->lh_clear);
|
V(lh->lh_clear);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tell it what sector we want... */
|
/* Tell it what sector we want... */
|
||||||
lhd_wreg(lh, LHD_REG_SECT, sector+i);
|
lhd_wreg(lh, LHD_REG_SECT, sector + i);
|
||||||
|
|
||||||
/* and start the operation. */
|
/* and start the operation. */
|
||||||
lhd_wreg(lh, LHD_REG_STAT, statval);
|
lhd_wreg(lh, LHD_REG_STAT, statval);
|
||||||
|
|
||||||
/* Now wait until the interrupt handler tells us we're done. */
|
/* Now wait until the interrupt handler tells us we're done. */
|
||||||
P(lh->lh_done);
|
P(lh->lh_done);
|
||||||
|
|
||||||
/* Get the result value saved by the interrupt handler. */
|
/* Get the result value saved by the interrupt handler. */
|
||||||
result = lh->lh_result;
|
result = lh->lh_result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Are we reading? If so, and if we succeeded,
|
* Are we reading? If so, and if we succeeded,
|
||||||
* transfer the data out of the on-card buffer.
|
* transfer the data out of the on-card buffer.
|
||||||
*/
|
*/
|
||||||
if (result==0 && uio->uio_rw==UIO_READ) {
|
if (result == 0 && uio->uio_rw == UIO_READ) {
|
||||||
membar_load_load();
|
membar_load_load();
|
||||||
result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio);
|
result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tell another thread it's cleared to go ahead. */
|
/* Tell another thread it's cleared to go ahead. */
|
||||||
V(lh->lh_clear);
|
V(lh->lh_clear);
|
||||||
|
|
||||||
/* If we failed, return the error. */
|
/* If we failed, return the error. */
|
||||||
if (result) {
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct device_ops lhd_devops = {
|
static const struct device_ops lhd_devops = {
|
||||||
.devop_eachopen = lhd_eachopen,
|
.devop_eachopen = lhd_eachopen,
|
||||||
.devop_io = lhd_io,
|
.devop_io = lhd_io,
|
||||||
.devop_ioctl = lhd_ioctl,
|
.devop_ioctl = lhd_ioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup routine called by autoconf.c when an lhd is found.
|
* Setup routine called by autoconf.c when an lhd is found.
|
||||||
*/
|
*/
|
||||||
int
|
int config_lhd(struct lhd_softc *lh, int lhdno) {
|
||||||
config_lhd(struct lhd_softc *lh, int lhdno)
|
char name[32];
|
||||||
{
|
|
||||||
char name[32];
|
|
||||||
|
|
||||||
/* Figure out what our name is. */
|
/* Figure out what our name is. */
|
||||||
snprintf(name, sizeof(name), "lhd%d", lhdno);
|
snprintf(name, sizeof(name), "lhd%d", lhdno);
|
||||||
|
|
||||||
/* Get a pointer to the on-chip buffer. */
|
/* Get a pointer to the on-chip buffer. */
|
||||||
lh->lh_buf = bus_map_area(lh->lh_busdata, lh->lh_buspos, LHD_BUFFER);
|
lh->lh_buf = bus_map_area(lh->lh_busdata, lh->lh_buspos, LHD_BUFFER);
|
||||||
|
|
||||||
/* Create the semaphores. */
|
/* Create the semaphores. */
|
||||||
lh->lh_clear = sem_create("lhd-clear", 1);
|
lh->lh_clear = sem_create("lhd-clear", 1);
|
||||||
if (lh->lh_clear == NULL) {
|
if (lh->lh_clear == NULL) {
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
lh->lh_done = sem_create("lhd-done", 0);
|
lh->lh_done = sem_create("lhd-done", 0);
|
||||||
if (lh->lh_done == NULL) {
|
if (lh->lh_done == NULL) {
|
||||||
sem_destroy(lh->lh_clear);
|
sem_destroy(lh->lh_clear);
|
||||||
lh->lh_clear = NULL;
|
lh->lh_clear = NULL;
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up the VFS device structure. */
|
/* Set up the VFS device structure. */
|
||||||
lh->lh_dev.d_ops = &lhd_devops;
|
lh->lh_dev.d_ops = &lhd_devops;
|
||||||
lh->lh_dev.d_blocks = bus_read_register(lh->lh_busdata, lh->lh_buspos,
|
lh->lh_dev.d_blocks =
|
||||||
LHD_REG_NSECT);
|
bus_read_register(lh->lh_busdata, lh->lh_buspos, LHD_REG_NSECT);
|
||||||
lh->lh_dev.d_blocksize = LHD_SECTSIZE;
|
lh->lh_dev.d_blocksize = LHD_SECTSIZE;
|
||||||
lh->lh_dev.d_data = lh;
|
lh->lh_dev.d_data = lh;
|
||||||
|
|
||||||
/* Add the VFS device structure to the VFS device list. */
|
/* Add the VFS device structure to the VFS device list. */
|
||||||
return vfs_adddev(name, &lh->lh_dev, 1);
|
return vfs_adddev(name, &lh->lh_dev, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,30 +35,30 @@
|
|||||||
/*
|
/*
|
||||||
* Our sector size
|
* Our sector size
|
||||||
*/
|
*/
|
||||||
#define LHD_SECTSIZE 512
|
#define LHD_SECTSIZE 512
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hardware device data associated with lhd (LAMEbus hard disk)
|
* Hardware device data associated with lhd (LAMEbus hard disk)
|
||||||
*/
|
*/
|
||||||
struct lhd_softc {
|
struct lhd_softc {
|
||||||
/* Initialized by lower-level attach code */
|
/* Initialized by lower-level attach code */
|
||||||
void *lh_busdata; /* The bus we're on */
|
void *lh_busdata; /* The bus we're on */
|
||||||
uint32_t lh_buspos; /* Our slot on that bus */
|
uint32_t lh_buspos; /* Our slot on that bus */
|
||||||
int lh_unit; /* What number lhd we are */
|
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 */
|
void *lh_buf; /* Pointer to on-card I/O buffer */
|
||||||
int lh_result; /* Result from I/O operation */
|
int lh_result; /* Result from I/O operation */
|
||||||
struct semaphore *lh_clear; /* Synchronization */
|
struct semaphore *lh_clear; /* Synchronization */
|
||||||
struct semaphore *lh_done;
|
struct semaphore *lh_done;
|
||||||
|
|
||||||
struct device lh_dev; /* VFS device structure */
|
struct device lh_dev; /* VFS device structure */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Functions called by lower-level drivers */
|
/* 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_ */
|
#endif /* _LAMEBUS_LHD_H_ */
|
||||||
|
|||||||
@@ -37,33 +37,31 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Lowest revision we support */
|
/* Lowest revision we support */
|
||||||
#define LOW_VERSION 2
|
#define LOW_VERSION 2
|
||||||
|
|
||||||
struct lhd_softc *
|
struct lhd_softc *attach_lhd_to_lamebus(int lhdno, struct lamebus_softc *sc) {
|
||||||
attach_lhd_to_lamebus(int lhdno, struct lamebus_softc *sc)
|
struct lhd_softc *lh;
|
||||||
{
|
int slot =
|
||||||
struct lhd_softc *lh;
|
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_DISK, LOW_VERSION, NULL);
|
||||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_DISK,
|
if (slot < 0) {
|
||||||
LOW_VERSION, NULL);
|
/* None found */
|
||||||
if (slot < 0) {
|
return NULL;
|
||||||
/* None found */
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
lh = kmalloc(sizeof(struct lhd_softc));
|
lh = kmalloc(sizeof(struct lhd_softc));
|
||||||
if (lh==NULL) {
|
if (lh == NULL) {
|
||||||
/* Out of memory */
|
/* Out of memory */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record what the lhd is attached to */
|
/* Record what the lhd is attached to */
|
||||||
lh->lh_busdata = sc;
|
lh->lh_busdata = sc;
|
||||||
lh->lh_buspos = slot;
|
lh->lh_buspos = slot;
|
||||||
lh->lh_unit = lhdno;
|
lh->lh_unit = lhdno;
|
||||||
|
|
||||||
/* Mark the slot in use and collect interrupts */
|
/* Mark the slot in use and collect interrupts */
|
||||||
lamebus_mark(sc, slot);
|
lamebus_mark(sc, slot);
|
||||||
lamebus_attach_interrupt(sc, slot, lh, lhd_irq);
|
lamebus_attach_interrupt(sc, slot, lh, lhd_irq);
|
||||||
|
|
||||||
return lh;
|
return lh;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,14 +33,10 @@
|
|||||||
/*#include <lamebus/lnet.h>*/ /* not yet */
|
/*#include <lamebus/lnet.h>*/ /* not yet */
|
||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
int
|
int config_lnet(struct lnet_softc *sc, int lnetno) {
|
||||||
config_lnet(struct lnet_softc *sc, int lnetno)
|
(void)sc;
|
||||||
{
|
|
||||||
(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"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Lowest revision we support */
|
/* Lowest revision we support */
|
||||||
#define LOW_VERSION 1
|
#define LOW_VERSION 1
|
||||||
/* Highest revision we support */
|
/* Highest revision we support */
|
||||||
#define HIGH_VERSION 1
|
#define HIGH_VERSION 1
|
||||||
|
|
||||||
struct lnet_softc *
|
struct lnet_softc *attach_lnet_to_lamebus(int lnetno,
|
||||||
attach_lnet_to_lamebus(int lnetno, struct lamebus_softc *sc)
|
struct lamebus_softc *sc) {
|
||||||
{
|
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_NET, LOW_VERSION,
|
||||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_NET,
|
HIGH_VERSION);
|
||||||
LOW_VERSION, HIGH_VERSION);
|
if (slot < 0) {
|
||||||
if (slot < 0) {
|
return NULL;
|
||||||
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"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Registers (offsets within slot) */
|
/* Registers (offsets within slot) */
|
||||||
#define LR_REG_RAND 0 /* random register */
|
#define LR_REG_RAND 0 /* random register */
|
||||||
|
|
||||||
/* Constants */
|
/* Constants */
|
||||||
#define LR_RANDMAX 0xffffffff
|
#define LR_RANDMAX 0xffffffff
|
||||||
|
|
||||||
int
|
int config_lrandom(struct lrandom_softc *lr, int lrandomno) {
|
||||||
config_lrandom(struct lrandom_softc *lr, int lrandomno)
|
(void)lrandomno;
|
||||||
{
|
(void)lr;
|
||||||
(void)lrandomno;
|
return 0;
|
||||||
(void)lr;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t lrandom_random(void *devdata) {
|
||||||
lrandom_random(void *devdata)
|
struct lrandom_softc *lr = devdata;
|
||||||
{
|
return bus_read_register(lr->lr_bus, lr->lr_buspos, LR_REG_RAND);
|
||||||
struct lrandom_softc *lr = devdata;
|
|
||||||
return bus_read_register(lr->lr_bus, lr->lr_buspos, LR_REG_RAND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t lrandom_randmax(void *devdata) {
|
||||||
lrandom_randmax(void *devdata)
|
(void)devdata;
|
||||||
{
|
return LR_RANDMAX;
|
||||||
(void)devdata;
|
|
||||||
return LR_RANDMAX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int lrandom_read(void *devdata, struct uio *uio) {
|
||||||
lrandom_read(void *devdata, struct uio *uio)
|
struct lrandom_softc *lr = devdata;
|
||||||
{
|
uint32_t val;
|
||||||
struct lrandom_softc *lr = devdata;
|
int result;
|
||||||
uint32_t val;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
while (uio->uio_resid > 0) {
|
while (uio->uio_resid > 0) {
|
||||||
val = bus_read_register(lr->lr_bus, lr->lr_buspos,
|
val = bus_read_register(lr->lr_bus, lr->lr_buspos, LR_REG_RAND);
|
||||||
LR_REG_RAND);
|
result = uiomove(&val, sizeof(val), uio);
|
||||||
result = uiomove(&val, sizeof(val), uio);
|
if (result) {
|
||||||
if (result) {
|
return result;
|
||||||
return result;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,9 @@
|
|||||||
struct uio;
|
struct uio;
|
||||||
|
|
||||||
struct lrandom_softc {
|
struct lrandom_softc {
|
||||||
/* Initialized by lower-level attach routine */
|
/* Initialized by lower-level attach routine */
|
||||||
void *lr_bus;
|
void *lr_bus;
|
||||||
uint32_t lr_buspos;
|
uint32_t lr_buspos;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Functions called by higher-level drivers */
|
/* Functions called by higher-level drivers */
|
||||||
|
|||||||
@@ -34,29 +34,28 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Lowest revision we support */
|
/* Lowest revision we support */
|
||||||
#define LOW_VERSION 1
|
#define LOW_VERSION 1
|
||||||
|
|
||||||
struct lrandom_softc *
|
struct lrandom_softc *attach_lrandom_to_lamebus(int lrandomno,
|
||||||
attach_lrandom_to_lamebus(int lrandomno, struct lamebus_softc *sc)
|
struct lamebus_softc *sc) {
|
||||||
{
|
struct lrandom_softc *lr;
|
||||||
struct lrandom_softc *lr;
|
int slot =
|
||||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_RANDOM,
|
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_RANDOM, LOW_VERSION, NULL);
|
||||||
LOW_VERSION, NULL);
|
if (slot < 0) {
|
||||||
if (slot < 0) {
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
lr = kmalloc(sizeof(struct lrandom_softc));
|
lr = kmalloc(sizeof(struct lrandom_softc));
|
||||||
if (lr==NULL) {
|
if (lr == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)lrandomno; // unused
|
(void)lrandomno; // unused
|
||||||
|
|
||||||
lr->lr_bus = sc;
|
lr->lr_bus = sc;
|
||||||
lr->lr_buspos = slot;
|
lr->lr_buspos = slot;
|
||||||
|
|
||||||
lamebus_mark(sc, slot);
|
lamebus_mark(sc, slot);
|
||||||
|
|
||||||
return lr;
|
return lr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,37 +41,29 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Registers (offsets within slot) */
|
/* Registers (offsets within slot) */
|
||||||
#define LSCR_REG_POSN 0 /* Cursor position */
|
#define LSCR_REG_POSN 0 /* Cursor position */
|
||||||
#define LSCR_REG_SIZE 4 /* Display size */
|
#define LSCR_REG_SIZE 4 /* Display size */
|
||||||
#define LSCR_REG_CHAR 8 /* Character in */
|
#define LSCR_REG_CHAR 8 /* Character in */
|
||||||
#define LSCR_REG_RIRQ 12 /* Read interrupt status */
|
#define LSCR_REG_RIRQ 12 /* Read interrupt status */
|
||||||
|
|
||||||
/* Bits in the IRQ registers */
|
/* Bits in the IRQ registers */
|
||||||
#define LSCR_IRQ_ENABLE 1
|
#define LSCR_IRQ_ENABLE 1
|
||||||
#define LSCR_IRQ_ACTIVE 2
|
#define LSCR_IRQ_ACTIVE 2
|
||||||
|
|
||||||
/* Offset within slot of screen buffer */
|
/* 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. */
|
/* Convert a 32-bit X/Y pair to X and Y coordinates. */
|
||||||
static
|
static inline void splitxy(uint32_t xy, unsigned *x, unsigned *y) {
|
||||||
inline
|
*x = xy >> 16;
|
||||||
void
|
*y = xy & 0xffff;
|
||||||
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. */
|
/* Convert X and Y coordinates to a single 32-bit value. */
|
||||||
static
|
static inline uint32_t mergexy(unsigned x, unsigned y) {
|
||||||
inline
|
uint32_t val = x;
|
||||||
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.
|
* Interrupt handler.
|
||||||
*/
|
*/
|
||||||
void
|
void lscreen_irq(void *vsc) {
|
||||||
lscreen_irq(void *vsc)
|
struct lscreen_softc *sc = vsc;
|
||||||
{
|
uint32_t ch, x;
|
||||||
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);
|
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_RIRQ);
|
||||||
if (x & LSCR_IRQ_ACTIVE) {
|
if (x & LSCR_IRQ_ACTIVE) {
|
||||||
ch = bus_read_register(sc->ls_busdata, sc->ls_buspos,
|
ch = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_CHAR);
|
||||||
LSCR_REG_CHAR);
|
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_RIRQ,
|
||||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
LSCR_IRQ_ENABLE);
|
||||||
LSCR_REG_RIRQ, LSCR_IRQ_ENABLE);
|
|
||||||
|
|
||||||
spinlock_release(&sc->ls_lock);
|
spinlock_release(&sc->ls_lock);
|
||||||
if (sc->ls_input) {
|
if (sc->ls_input) {
|
||||||
sc->ls_input(sc->ls_devdata, ch);
|
sc->ls_input(sc->ls_devdata, ch);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
spinlock_release(&sc->ls_lock);
|
||||||
spinlock_release(&sc->ls_lock);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@@ -109,74 +97,68 @@ lscreen_irq(void *vsc)
|
|||||||
/*
|
/*
|
||||||
* Handle a newline on the screen.
|
* Handle a newline on the screen.
|
||||||
*/
|
*/
|
||||||
static
|
static void lscreen_newline(struct lscreen_softc *sc) {
|
||||||
void
|
if (sc->ls_cy >= sc->ls_height - 1) {
|
||||||
lscreen_newline(struct lscreen_softc *sc)
|
/*
|
||||||
{
|
* Scroll
|
||||||
if (sc->ls_cy >= sc->ls_height-1) {
|
*/
|
||||||
/*
|
|
||||||
* Scroll
|
|
||||||
*/
|
|
||||||
|
|
||||||
memmove(sc->ls_screen, sc->ls_screen + sc->ls_width,
|
memmove(sc->ls_screen, sc->ls_screen + sc->ls_width,
|
||||||
sc->ls_width * (sc->ls_height-1));
|
sc->ls_width * (sc->ls_height - 1));
|
||||||
bzero(sc->ls_screen + sc->ls_width * (sc->ls_height-1),
|
bzero(sc->ls_screen + sc->ls_width * (sc->ls_height - 1), sc->ls_width);
|
||||||
sc->ls_width);
|
} else {
|
||||||
}
|
sc->ls_cy++;
|
||||||
else {
|
}
|
||||||
sc->ls_cy++;
|
sc->ls_cx = 0;
|
||||||
}
|
|
||||||
sc->ls_cx=0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle a printable character being written to the screen.
|
* Handle a printable character being written to the screen.
|
||||||
*/
|
*/
|
||||||
static
|
static void lscreen_char(struct lscreen_softc *sc, int ch) {
|
||||||
void
|
if (sc->ls_cx >= sc->ls_width) {
|
||||||
lscreen_char(struct lscreen_softc *sc, int ch)
|
lscreen_newline(sc);
|
||||||
{
|
}
|
||||||
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_screen[sc->ls_cy * sc->ls_width + sc->ls_cx] = ch;
|
||||||
sc->ls_cx++;
|
sc->ls_cx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send a character to the screen.
|
* Send a character to the screen.
|
||||||
* This should probably know about backspace and tab.
|
* This should probably know about backspace and tab.
|
||||||
*/
|
*/
|
||||||
void
|
void lscreen_write(void *vsc, int ch) {
|
||||||
lscreen_write(void *vsc, int ch)
|
struct lscreen_softc *sc = vsc;
|
||||||
{
|
int ccx, ccy;
|
||||||
struct lscreen_softc *sc = vsc;
|
|
||||||
int ccx, ccy;
|
|
||||||
|
|
||||||
spinlock_acquire(&sc->ls_lock);
|
spinlock_acquire(&sc->ls_lock);
|
||||||
|
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case '\n': lscreen_newline(sc); break;
|
case '\n':
|
||||||
default: lscreen_char(sc, ch); break;
|
lscreen_newline(sc);
|
||||||
}
|
break;
|
||||||
|
default:
|
||||||
|
lscreen_char(sc, ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ccx/ccy = corrected cursor position
|
* ccx/ccy = corrected cursor position
|
||||||
* (The cursor marks the next space text will appear in. But
|
* (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.)
|
* at the very end of the line, it should not move off the edge.)
|
||||||
*/
|
*/
|
||||||
ccx = sc->ls_cx;
|
ccx = sc->ls_cx;
|
||||||
ccy = sc->ls_cy;
|
ccy = sc->ls_cy;
|
||||||
if (ccx==sc->ls_width) {
|
if (ccx == sc->ls_width) {
|
||||||
ccx--;
|
ccx--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the cursor position */
|
/* Set the cursor position */
|
||||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_POSN,
|
||||||
LSCR_REG_POSN, mergexy(ccx, ccy));
|
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.
|
* Setup routine called by autoconf.c when an lscreen is found.
|
||||||
*/
|
*/
|
||||||
int
|
int config_lscreen(struct lscreen_softc *sc, int lscreenno) {
|
||||||
config_lscreen(struct lscreen_softc *sc, int lscreenno)
|
uint32_t val;
|
||||||
{
|
|
||||||
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,
|
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_RIRQ,
|
||||||
LSCR_REG_RIRQ, LSCR_IRQ_ENABLE);
|
LSCR_IRQ_ENABLE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get screen size.
|
* Get screen size.
|
||||||
*/
|
*/
|
||||||
val = bus_read_register(sc->ls_busdata, sc->ls_buspos,
|
val = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_SIZE);
|
||||||
LSCR_REG_SIZE);
|
splitxy(val, &sc->ls_width, &sc->ls_height);
|
||||||
splitxy(val, &sc->ls_width, &sc->ls_height);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get cursor position.
|
* Get cursor position.
|
||||||
*/
|
*/
|
||||||
val = bus_read_register(sc->ls_busdata, sc->ls_buspos,
|
val = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_POSN);
|
||||||
LSCR_REG_POSN);
|
splitxy(val, &sc->ls_cx, &sc->ls_cy);
|
||||||
splitxy(val, &sc->ls_cx, &sc->ls_cy);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a pointer to the memory-mapped screen area.
|
* Get a pointer to the memory-mapped screen area.
|
||||||
*/
|
*/
|
||||||
sc->ls_screen = bus_map_area(sc->ls_busdata, sc->ls_buspos,
|
sc->ls_screen = bus_map_area(sc->ls_busdata, sc->ls_buspos, LSCR_SCREEN);
|
||||||
LSCR_SCREEN);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,24 +34,24 @@
|
|||||||
* Hardware device data for memory-mapped fullscreen text console.
|
* Hardware device data for memory-mapped fullscreen text console.
|
||||||
*/
|
*/
|
||||||
struct lscreen_softc {
|
struct lscreen_softc {
|
||||||
/* Initialized by config function */
|
/* Initialized by config function */
|
||||||
struct spinlock ls_lock; // protects data and device regs
|
struct spinlock ls_lock; // protects data and device regs
|
||||||
unsigned ls_width, ls_height; // screen size
|
unsigned ls_width, ls_height; // screen size
|
||||||
unsigned ls_cx, ls_cy; // cursor position
|
unsigned ls_cx, ls_cy; // cursor position
|
||||||
char *ls_screen; // memory-mapped screen buffer
|
char *ls_screen; // memory-mapped screen buffer
|
||||||
|
|
||||||
/* Initialized by lower-level attachment function */
|
/* Initialized by lower-level attachment function */
|
||||||
void *ls_busdata; // bus we're on
|
void *ls_busdata; // bus we're on
|
||||||
uint32_t ls_buspos; // position on that bus
|
uint32_t ls_buspos; // position on that bus
|
||||||
|
|
||||||
/* Initialized by higher-level attachment function */
|
/* Initialized by higher-level attachment function */
|
||||||
void *ls_devdata; // data and functions for
|
void *ls_devdata; // data and functions for
|
||||||
void (*ls_start)(void *devdata); // upper device (perhaps
|
void (*ls_start)(void *devdata); // upper device (perhaps
|
||||||
void (*ls_input)(void *devdata, int ch); // console)
|
void (*ls_input)(void *devdata, int ch); // console)
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Functions called by lower-level drivers */
|
/* 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 */
|
/* Functions called by higher-level drivers */
|
||||||
void lscreen_write(/*struct lser_softc*/ void *sc, int ch); // output function
|
void lscreen_write(/*struct lser_softc*/ void *sc, int ch); // output function
|
||||||
|
|||||||
@@ -37,34 +37,33 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Lowest revision we support */
|
/* Lowest revision we support */
|
||||||
#define LOW_VERSION 1
|
#define LOW_VERSION 1
|
||||||
/* Highest revision we support */
|
/* Highest revision we support */
|
||||||
#define HIGH_VERSION 1
|
#define HIGH_VERSION 1
|
||||||
|
|
||||||
struct lscreen_softc *
|
struct lscreen_softc *attach_lscreen_to_lamebus(int lscreenno,
|
||||||
attach_lscreen_to_lamebus(int lscreenno, struct lamebus_softc *sc)
|
struct lamebus_softc *sc) {
|
||||||
{
|
struct lscreen_softc *ls;
|
||||||
struct lscreen_softc *ls;
|
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SCREEN, LOW_VERSION,
|
||||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SCREEN,
|
HIGH_VERSION);
|
||||||
LOW_VERSION, HIGH_VERSION);
|
if (slot < 0) {
|
||||||
if (slot < 0) {
|
/* Not found */
|
||||||
/* Not found */
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ls = kmalloc(sizeof(struct lscreen_softc));
|
ls = kmalloc(sizeof(struct lscreen_softc));
|
||||||
if (ls==NULL) {
|
if (ls == NULL) {
|
||||||
/* Out of memory */
|
/* Out of memory */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record what it's attached to */
|
/* Record what it's attached to */
|
||||||
ls->ls_busdata = sc;
|
ls->ls_busdata = sc;
|
||||||
ls->ls_buspos = slot;
|
ls->ls_buspos = slot;
|
||||||
|
|
||||||
/* Mark the slot in use and hook the interrupt */
|
/* Mark the slot in use and hook the interrupt */
|
||||||
lamebus_mark(sc, slot);
|
lamebus_mark(sc, slot);
|
||||||
lamebus_attach_interrupt(sc, slot, ls, lscreen_irq);
|
lamebus_attach_interrupt(sc, slot, ls, lscreen_irq);
|
||||||
|
|
||||||
return ls;
|
return ls;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,158 +35,139 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Registers (offsets within slot) */
|
/* Registers (offsets within slot) */
|
||||||
#define LSER_REG_CHAR 0 /* Character in/out */
|
#define LSER_REG_CHAR 0 /* Character in/out */
|
||||||
#define LSER_REG_WIRQ 4 /* Write interrupt status */
|
#define LSER_REG_WIRQ 4 /* Write interrupt status */
|
||||||
#define LSER_REG_RIRQ 8 /* Read interrupt status */
|
#define LSER_REG_RIRQ 8 /* Read interrupt status */
|
||||||
|
|
||||||
/* Bits in the IRQ registers */
|
/* Bits in the IRQ registers */
|
||||||
#define LSER_IRQ_ENABLE 1
|
#define LSER_IRQ_ENABLE 1
|
||||||
#define LSER_IRQ_ACTIVE 2
|
#define LSER_IRQ_ACTIVE 2
|
||||||
#define LSER_IRQ_FORCE 4
|
#define LSER_IRQ_FORCE 4
|
||||||
|
|
||||||
void
|
void lser_irq(void *vsc) {
|
||||||
lser_irq(void *vsc)
|
struct lser_softc *sc = vsc;
|
||||||
{
|
uint32_t x;
|
||||||
struct lser_softc *sc = vsc;
|
bool clear_to_write = false;
|
||||||
uint32_t x;
|
bool got_a_read = false;
|
||||||
bool clear_to_write = false;
|
uint32_t ch = 0;
|
||||||
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);
|
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ);
|
||||||
if (x & LSER_IRQ_ACTIVE) {
|
if (x & LSER_IRQ_ACTIVE) {
|
||||||
x = LSER_IRQ_ENABLE;
|
x = LSER_IRQ_ENABLE;
|
||||||
sc->ls_wbusy = 0;
|
sc->ls_wbusy = 0;
|
||||||
clear_to_write = true;
|
clear_to_write = true;
|
||||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ, x);
|
||||||
LSER_REG_WIRQ, x);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_RIRQ);
|
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_RIRQ);
|
||||||
if (x & LSER_IRQ_ACTIVE) {
|
if (x & LSER_IRQ_ACTIVE) {
|
||||||
x = LSER_IRQ_ENABLE;
|
x = LSER_IRQ_ENABLE;
|
||||||
ch = bus_read_register(sc->ls_busdata, sc->ls_buspos,
|
ch = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_CHAR);
|
||||||
LSER_REG_CHAR);
|
got_a_read = true;
|
||||||
got_a_read = true;
|
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_RIRQ, x);
|
||||||
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) {
|
if (clear_to_write && sc->ls_start != NULL) {
|
||||||
sc->ls_start(sc->ls_devdata);
|
sc->ls_start(sc->ls_devdata);
|
||||||
}
|
}
|
||||||
if (got_a_read && sc->ls_input != NULL) {
|
if (got_a_read && sc->ls_input != NULL) {
|
||||||
sc->ls_input(sc->ls_devdata, ch);
|
sc->ls_input(sc->ls_devdata, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void lser_write(void *vls, int ch) {
|
||||||
lser_write(void *vls, int ch)
|
struct lser_softc *ls = vls;
|
||||||
{
|
|
||||||
struct lser_softc *ls = vls;
|
|
||||||
|
|
||||||
spinlock_acquire(&ls->ls_lock);
|
spinlock_acquire(&ls->ls_lock);
|
||||||
|
|
||||||
if (ls->ls_wbusy) {
|
if (ls->ls_wbusy) {
|
||||||
/*
|
/*
|
||||||
* We're not clear to write.
|
* We're not clear to write.
|
||||||
*
|
*
|
||||||
* This should not happen. It's the job of the driver
|
* This should not happen. It's the job of the driver
|
||||||
* attached to us to not write until we call
|
* attached to us to not write until we call
|
||||||
* ls->ls_start.
|
* ls->ls_start.
|
||||||
*
|
*
|
||||||
* (Note: if we're the console, the panic will go to
|
* (Note: if we're the console, the panic will go to
|
||||||
* lser_writepolled for printing, because we hold a
|
* lser_writepolled for printing, because we hold a
|
||||||
* spinlock and interrupts are off; it won't recurse.)
|
* spinlock and interrupts are off; it won't recurse.)
|
||||||
*/
|
*/
|
||||||
panic("lser: Not clear to write\n");
|
panic("lser: Not clear to write\n");
|
||||||
}
|
}
|
||||||
ls->ls_wbusy = true;
|
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
|
static void lser_poll_until_write(struct lser_softc *sc) {
|
||||||
void
|
uint32_t val;
|
||||||
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 {
|
do {
|
||||||
val = bus_read_register(sc->ls_busdata, sc->ls_buspos,
|
val = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ);
|
||||||
LSER_REG_WIRQ);
|
} while ((val & LSER_IRQ_ACTIVE) == 0);
|
||||||
}
|
|
||||||
while ((val & LSER_IRQ_ACTIVE) == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void lser_writepolled(void *vsc, int ch) {
|
||||||
lser_writepolled(void *vsc, int ch)
|
struct lser_softc *sc = vsc;
|
||||||
{
|
bool irqpending;
|
||||||
struct lser_softc *sc = vsc;
|
|
||||||
bool irqpending;
|
|
||||||
|
|
||||||
spinlock_acquire(&sc->ls_lock);
|
spinlock_acquire(&sc->ls_lock);
|
||||||
|
|
||||||
if (sc->ls_wbusy) {
|
if (sc->ls_wbusy) {
|
||||||
irqpending = true;
|
irqpending = true;
|
||||||
lser_poll_until_write(sc);
|
lser_poll_until_write(sc);
|
||||||
/* Clear the ready condition, but leave the IRQ asserted */
|
/* Clear the ready condition, but leave the IRQ asserted */
|
||||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ,
|
||||||
LSER_REG_WIRQ,
|
LSER_IRQ_FORCE | LSER_IRQ_ENABLE);
|
||||||
LSER_IRQ_FORCE|LSER_IRQ_ENABLE);
|
} else {
|
||||||
}
|
irqpending = false;
|
||||||
else {
|
/* Clear the interrupt enable bit */
|
||||||
irqpending = false;
|
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ, 0);
|
||||||
/* Clear the interrupt enable bit */
|
}
|
||||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
|
||||||
LSER_REG_WIRQ, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send the character. */
|
/* Send the character. */
|
||||||
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_CHAR, ch);
|
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_CHAR, ch);
|
||||||
|
|
||||||
/* Wait until it's done. */
|
/* Wait until it's done. */
|
||||||
lser_poll_until_write(sc);
|
lser_poll_until_write(sc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there wasn't already an IRQ pending, clear the ready
|
* If there wasn't already an IRQ pending, clear the ready
|
||||||
* condition and turn interruption back on. But if there was,
|
* condition and turn interruption back on. But if there was,
|
||||||
* leave the register alone, with the ready condition set (and
|
* leave the register alone, with the ready condition set (and
|
||||||
* the force bit still on); in due course we'll get to the
|
* the force bit still on); in due course we'll get to the
|
||||||
* interrupt handler and they'll be cleared.
|
* interrupt handler and they'll be cleared.
|
||||||
*/
|
*/
|
||||||
if (!irqpending) {
|
if (!irqpending) {
|
||||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ,
|
||||||
LSER_REG_WIRQ, LSER_IRQ_ENABLE);
|
LSER_IRQ_ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
spinlock_release(&sc->ls_lock);
|
spinlock_release(&sc->ls_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int config_lser(struct lser_softc *sc, int lserno) {
|
||||||
config_lser(struct lser_softc *sc, int lserno)
|
(void)lserno;
|
||||||
{
|
|
||||||
(void)lserno;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable interrupting.
|
* Enable interrupting.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
spinlock_init(&sc->ls_lock);
|
spinlock_init(&sc->ls_lock);
|
||||||
sc->ls_wbusy = false;
|
sc->ls_wbusy = false;
|
||||||
|
|
||||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_RIRQ,
|
||||||
LSER_REG_RIRQ, LSER_IRQ_ENABLE);
|
LSER_IRQ_ENABLE);
|
||||||
bus_write_register(sc->ls_busdata, sc->ls_buspos,
|
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ,
|
||||||
LSER_REG_WIRQ, LSER_IRQ_ENABLE);
|
LSER_IRQ_ENABLE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,18 +33,18 @@
|
|||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
|
|
||||||
struct lser_softc {
|
struct lser_softc {
|
||||||
/* Initialized by config function */
|
/* Initialized by config function */
|
||||||
struct spinlock ls_lock; /* protects ls_wbusy and device regs */
|
struct spinlock ls_lock; /* protects ls_wbusy and device regs */
|
||||||
volatile bool ls_wbusy; /* true if write in progress */
|
volatile bool ls_wbusy; /* true if write in progress */
|
||||||
|
|
||||||
/* Initialized by lower-level attachment function */
|
/* Initialized by lower-level attachment function */
|
||||||
void *ls_busdata;
|
void *ls_busdata;
|
||||||
uint32_t ls_buspos;
|
uint32_t ls_buspos;
|
||||||
|
|
||||||
/* Initialized by higher-level attachment function */
|
/* Initialized by higher-level attachment function */
|
||||||
void *ls_devdata;
|
void *ls_devdata;
|
||||||
void (*ls_start)(void *devdata);
|
void (*ls_start)(void *devdata);
|
||||||
void (*ls_input)(void *devdata, int ch);
|
void (*ls_input)(void *devdata, int ch);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Functions called by lower-level drivers */
|
/* Functions called by lower-level drivers */
|
||||||
|
|||||||
@@ -34,30 +34,29 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Lowest revision we support */
|
/* Lowest revision we support */
|
||||||
#define LOW_VERSION 1
|
#define LOW_VERSION 1
|
||||||
|
|
||||||
struct lser_softc *
|
struct lser_softc *attach_lser_to_lamebus(int lserno,
|
||||||
attach_lser_to_lamebus(int lserno, struct lamebus_softc *sc)
|
struct lamebus_softc *sc) {
|
||||||
{
|
struct lser_softc *ls;
|
||||||
struct lser_softc *ls;
|
int slot =
|
||||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SERIAL,
|
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SERIAL, LOW_VERSION, NULL);
|
||||||
LOW_VERSION, NULL);
|
if (slot < 0) {
|
||||||
if (slot < 0) {
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ls = kmalloc(sizeof(struct lser_softc));
|
ls = kmalloc(sizeof(struct lser_softc));
|
||||||
if (ls==NULL) {
|
if (ls == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)lserno; // unused
|
(void)lserno; // unused
|
||||||
|
|
||||||
ls->ls_busdata = sc;
|
ls->ls_busdata = sc;
|
||||||
ls->ls_buspos = slot;
|
ls->ls_buspos = slot;
|
||||||
|
|
||||||
lamebus_mark(sc, slot);
|
lamebus_mark(sc, slot);
|
||||||
lamebus_attach_interrupt(sc, slot, ls, lser_irq);
|
lamebus_attach_interrupt(sc, slot, ls, lser_irq);
|
||||||
|
|
||||||
return ls;
|
return ls;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,92 +39,87 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Registers (offsets within slot) */
|
/* Registers (offsets within slot) */
|
||||||
#define LT_REG_SEC 0 /* time of day: seconds */
|
#define LT_REG_SEC 0 /* time of day: seconds */
|
||||||
#define LT_REG_NSEC 4 /* time of day: nanoseconds */
|
#define LT_REG_NSEC 4 /* time of day: nanoseconds */
|
||||||
#define LT_REG_ROE 8 /* Restart On countdown-timer Expiry flag */
|
#define LT_REG_ROE 8 /* Restart On countdown-timer Expiry flag */
|
||||||
#define LT_REG_IRQ 12 /* Interrupt status register */
|
#define LT_REG_IRQ 12 /* Interrupt status register */
|
||||||
#define LT_REG_COUNT 16 /* Time for countdown timer (usec) */
|
#define LT_REG_COUNT 16 /* Time for countdown timer (usec) */
|
||||||
#define LT_REG_SPKR 20 /* Beep control */
|
#define LT_REG_SPKR 20 /* Beep control */
|
||||||
|
|
||||||
/* Granularity of countdown timer (usec) */
|
/* Granularity of countdown timer (usec) */
|
||||||
#define LT_GRANULARITY 1000000
|
#define LT_GRANULARITY 1000000
|
||||||
|
|
||||||
static bool havetimerclock;
|
static bool havetimerclock;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup routine called by autoconf stuff when an ltimer is found.
|
* Setup routine called by autoconf stuff when an ltimer is found.
|
||||||
*/
|
*/
|
||||||
int
|
int config_ltimer(struct ltimer_softc *lt, int ltimerno) {
|
||||||
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
|
||||||
* Running on System/161 2.x, we always use the processor
|
* hardclock.
|
||||||
* 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
|
||||||
* Ideally there should be code here that will use an ltimer
|
* wanted to make OS/161 2.x run on System/161 1.x. However,
|
||||||
* for hardclock if nothing else is available; e.g. if we
|
* that requires a good bit more infrastructure for handling
|
||||||
* wanted to make OS/161 2.x run on System/161 1.x. However,
|
* timers than we have and it doesn't seem worthwhile.
|
||||||
* 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
|
||||||
* It would also require some hacking, because all CPUs need
|
* sure all CPUs receive exactly one timer interrupt? Remember
|
||||||
* to receive timer interrupts. (Exercise: how would you make
|
* that LAMEbus uses level-triggered interrupts, so the
|
||||||
* sure all CPUs receive exactly one timer interrupt? Remember
|
* hardware interrupt line will cause repeated interrupts if
|
||||||
* that LAMEbus uses level-triggered interrupts, so the
|
* it's not reset on the device; but if it's reset on the
|
||||||
* hardware interrupt line will cause repeated interrupts if
|
* device before all CPUs manage to see it, those CPUs won't
|
||||||
* it's not reset on the device; but if it's reset on the
|
* be interrupted at all.)
|
||||||
* 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.
|
||||||
* Note that the beep and rtclock devices *do* attach to
|
*/
|
||||||
* ltimer.
|
(void)ltimerno;
|
||||||
*/
|
lt->lt_hardclock = 0;
|
||||||
(void)ltimerno;
|
|
||||||
lt->lt_hardclock = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do, however, use ltimer for the timer clock, since the
|
* We do, however, use ltimer for the timer clock, since the
|
||||||
* on-chip timer can't do that.
|
* on-chip timer can't do that.
|
||||||
*/
|
*/
|
||||||
if (!havetimerclock) {
|
if (!havetimerclock) {
|
||||||
havetimerclock = true;
|
havetimerclock = true;
|
||||||
lt->lt_timerclock = 1;
|
lt->lt_timerclock = 1;
|
||||||
|
|
||||||
/* Wire it to go off once every second. */
|
/* 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_ROE, 1);
|
||||||
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_COUNT,
|
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_COUNT, LT_GRANULARITY);
|
||||||
LT_GRANULARITY);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Interrupt handler.
|
* Interrupt handler.
|
||||||
*/
|
*/
|
||||||
void
|
void ltimer_irq(void *vlt) {
|
||||||
ltimer_irq(void *vlt)
|
struct ltimer_softc *lt = vlt;
|
||||||
{
|
uint32_t val;
|
||||||
struct ltimer_softc *lt = vlt;
|
|
||||||
uint32_t val;
|
|
||||||
|
|
||||||
val = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_IRQ);
|
val = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_IRQ);
|
||||||
if (val) {
|
if (val) {
|
||||||
/*
|
/*
|
||||||
* Only call hardclock if we're responsible for hardclock.
|
* Only call hardclock if we're responsible for hardclock.
|
||||||
* (Any additional timer devices are unused.)
|
* (Any additional timer devices are unused.)
|
||||||
*/
|
*/
|
||||||
if (lt->lt_hardclock) {
|
if (lt->lt_hardclock) {
|
||||||
hardclock();
|
hardclock();
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Likewise for timerclock.
|
* Likewise for timerclock.
|
||||||
*/
|
*/
|
||||||
if (lt->lt_timerclock) {
|
if (lt->lt_timerclock) {
|
||||||
timerclock();
|
timerclock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -132,12 +127,10 @@ ltimer_irq(void *vlt)
|
|||||||
* doesn't matter what value you write. This function is called if
|
* doesn't matter what value you write. This function is called if
|
||||||
* the beep device is attached to this timer.
|
* the beep device is attached to this timer.
|
||||||
*/
|
*/
|
||||||
void
|
void ltimer_beep(void *vlt) {
|
||||||
ltimer_beep(void *vlt)
|
struct ltimer_softc *lt = 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
|
* This function gets called if the rtclock device is attached
|
||||||
* to this timer.
|
* to this timer.
|
||||||
*/
|
*/
|
||||||
void
|
void ltimer_gettime(void *vlt, struct timespec *ts) {
|
||||||
ltimer_gettime(void *vlt, struct timespec *ts)
|
struct ltimer_softc *lt = vlt;
|
||||||
{
|
uint32_t secs1, secs2;
|
||||||
struct ltimer_softc *lt = vlt;
|
int spl;
|
||||||
uint32_t secs1, secs2;
|
|
||||||
int spl;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the seconds twice, on either side of the nanoseconds.
|
* Read the seconds twice, on either side of the nanoseconds.
|
||||||
* If nsecs is small, use the *later* value of seconds, in case
|
* If nsecs is small, use the *later* value of seconds, in case
|
||||||
* the nanoseconds turned over between the time we got the earlier
|
* the nanoseconds turned over between the time we got the earlier
|
||||||
* value and the time we got nsecs.
|
* value and the time we got nsecs.
|
||||||
*
|
*
|
||||||
* Note that the clock in the ltimer device is accurate down
|
* Note that the clock in the ltimer device is accurate down
|
||||||
* to a single processor cycle, so this might actually matter
|
* to a single processor cycle, so this might actually matter
|
||||||
* now and then.
|
* now and then.
|
||||||
*
|
*
|
||||||
* Do it with interrupts off on the current processor to avoid
|
* Do it with interrupts off on the current processor to avoid
|
||||||
* getting garbage if we get an interrupt among the register
|
* getting garbage if we get an interrupt among the register
|
||||||
* reads.
|
* reads.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
spl = splhigh();
|
spl = splhigh();
|
||||||
|
|
||||||
secs1 = bus_read_register(lt->lt_bus, lt->lt_buspos,
|
secs1 = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_SEC);
|
||||||
LT_REG_SEC);
|
ts->tv_nsec = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_NSEC);
|
||||||
ts->tv_nsec = bus_read_register(lt->lt_bus, lt->lt_buspos,
|
secs2 = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_SEC);
|
||||||
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) {
|
if (ts->tv_nsec < 5000000) {
|
||||||
ts->tv_sec = secs2;
|
ts->tv_sec = secs2;
|
||||||
}
|
} else {
|
||||||
else {
|
ts->tv_sec = secs1;
|
||||||
ts->tv_sec = secs1;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,21 +36,21 @@ struct timespec;
|
|||||||
* Hardware device data for LAMEbus timer device
|
* Hardware device data for LAMEbus timer device
|
||||||
*/
|
*/
|
||||||
struct ltimer_softc {
|
struct ltimer_softc {
|
||||||
/* Initialized by config function */
|
/* Initialized by config function */
|
||||||
int lt_hardclock; /* true if we should call hardclock() */
|
int lt_hardclock; /* true if we should call hardclock() */
|
||||||
int lt_timerclock; /* true if we should call timerclock() */
|
int lt_timerclock; /* true if we should call timerclock() */
|
||||||
|
|
||||||
/* Initialized by lower-level attach routine */
|
/* Initialized by lower-level attach routine */
|
||||||
void *lt_bus; /* bus we're on */
|
void *lt_bus; /* bus we're on */
|
||||||
uint32_t lt_buspos; /* position (slot) on that bus */
|
uint32_t lt_buspos; /* position (slot) on that bus */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Functions called by lower-level drivers */
|
/* 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 */
|
/* 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,
|
void ltimer_gettime(/*struct ltimer_softc*/ void *devdata,
|
||||||
struct timespec *ts); // for rtclock
|
struct timespec *ts); // for rtclock
|
||||||
|
|
||||||
#endif /* _LAMEBUS_LTIMER_H_ */
|
#endif /* _LAMEBUS_LTIMER_H_ */
|
||||||
|
|||||||
@@ -37,34 +37,33 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Lowest revision we support */
|
/* Lowest revision we support */
|
||||||
#define LOW_VERSION 1
|
#define LOW_VERSION 1
|
||||||
|
|
||||||
struct ltimer_softc *
|
struct ltimer_softc *attach_ltimer_to_lamebus(int ltimerno,
|
||||||
attach_ltimer_to_lamebus(int ltimerno, struct lamebus_softc *sc)
|
struct lamebus_softc *sc) {
|
||||||
{
|
struct ltimer_softc *lt;
|
||||||
struct ltimer_softc *lt;
|
int slot =
|
||||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TIMER,
|
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TIMER, LOW_VERSION, NULL);
|
||||||
LOW_VERSION, NULL);
|
if (slot < 0) {
|
||||||
if (slot < 0) {
|
/* No ltimer (or no additional ltimer) found */
|
||||||
/* No ltimer (or no additional ltimer) found */
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
lt = kmalloc(sizeof(struct ltimer_softc));
|
lt = kmalloc(sizeof(struct ltimer_softc));
|
||||||
if (lt==NULL) {
|
if (lt == NULL) {
|
||||||
/* out of memory */
|
/* out of memory */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)ltimerno; // unused
|
(void)ltimerno; // unused
|
||||||
|
|
||||||
/* Record what bus it's on */
|
/* Record what bus it's on */
|
||||||
lt->lt_bus = sc;
|
lt->lt_bus = sc;
|
||||||
lt->lt_buspos = slot;
|
lt->lt_buspos = slot;
|
||||||
|
|
||||||
/* Mark the slot in use and hook that slot's interrupt */
|
/* Mark the slot in use and hook that slot's interrupt */
|
||||||
lamebus_mark(sc, slot);
|
lamebus_mark(sc, slot);
|
||||||
lamebus_attach_interrupt(sc, slot, lt, ltimer_irq);
|
lamebus_attach_interrupt(sc, slot, lt, ltimer_irq);
|
||||||
|
|
||||||
return lt;
|
return lt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,83 +34,67 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Registers (offsets within slot) */
|
/* Registers (offsets within slot) */
|
||||||
#define LTRACE_REG_TRON 0 /* trace on */
|
#define LTRACE_REG_TRON 0 /* trace on */
|
||||||
#define LTRACE_REG_TROFF 4 /* trace off */
|
#define LTRACE_REG_TROFF 4 /* trace off */
|
||||||
#define LTRACE_REG_DEBUG 8 /* debug code */
|
#define LTRACE_REG_DEBUG 8 /* debug code */
|
||||||
#define LTRACE_REG_DUMP 12 /* dump the system */
|
#define LTRACE_REG_DUMP 12 /* dump the system */
|
||||||
#define LTRACE_REG_STOP 16 /* stop for the debugger */
|
#define LTRACE_REG_STOP 16 /* stop for the debugger */
|
||||||
#define LTRACE_REG_PROFEN 20 /* turn profiling on/off */
|
#define LTRACE_REG_PROFEN 20 /* turn profiling on/off */
|
||||||
#define LTRACE_REG_PROFCL 24 /* clear the profile */
|
#define LTRACE_REG_PROFCL 24 /* clear the profile */
|
||||||
|
|
||||||
static struct ltrace_softc *the_trace;
|
static struct ltrace_softc *the_trace;
|
||||||
|
|
||||||
void
|
void ltrace_on(uint32_t code) {
|
||||||
ltrace_on(uint32_t code)
|
if (the_trace != NULL) {
|
||||||
{
|
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||||
if (the_trace != NULL) {
|
LTRACE_REG_TRON, code);
|
||||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
}
|
||||||
LTRACE_REG_TRON, code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ltrace_off(uint32_t code) {
|
||||||
ltrace_off(uint32_t code)
|
if (the_trace != NULL) {
|
||||||
{
|
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||||
if (the_trace != NULL) {
|
LTRACE_REG_TROFF, code);
|
||||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
}
|
||||||
LTRACE_REG_TROFF, code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ltrace_debug(uint32_t code) {
|
||||||
ltrace_debug(uint32_t code)
|
if (the_trace != NULL) {
|
||||||
{
|
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||||
if (the_trace != NULL) {
|
LTRACE_REG_DEBUG, code);
|
||||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
}
|
||||||
LTRACE_REG_DEBUG, code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ltrace_dump(uint32_t code) {
|
||||||
ltrace_dump(uint32_t code)
|
if (the_trace != NULL) {
|
||||||
{
|
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||||
if (the_trace != NULL) {
|
LTRACE_REG_DUMP, code);
|
||||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
}
|
||||||
LTRACE_REG_DUMP, code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ltrace_stop(uint32_t code) {
|
||||||
ltrace_stop(uint32_t code)
|
if (the_trace != NULL && the_trace->lt_canstop) {
|
||||||
{
|
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||||
if (the_trace != NULL && the_trace->lt_canstop) {
|
LTRACE_REG_STOP, code);
|
||||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
}
|
||||||
LTRACE_REG_STOP, code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ltrace_setprof(uint32_t onoff) {
|
||||||
ltrace_setprof(uint32_t onoff)
|
if (the_trace != NULL && the_trace->lt_canprof) {
|
||||||
{
|
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||||
if (the_trace != NULL && the_trace->lt_canprof) {
|
LTRACE_REG_PROFEN, onoff);
|
||||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
}
|
||||||
LTRACE_REG_PROFEN, onoff);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ltrace_eraseprof(void) {
|
||||||
ltrace_eraseprof(void)
|
if (the_trace != NULL && the_trace->lt_canprof) {
|
||||||
{
|
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
||||||
if (the_trace != NULL && the_trace->lt_canprof) {
|
LTRACE_REG_PROFCL, 1);
|
||||||
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
|
}
|
||||||
LTRACE_REG_PROFCL, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int config_ltrace(struct ltrace_softc *sc, int ltraceno) {
|
||||||
config_ltrace(struct ltrace_softc *sc, int ltraceno)
|
(void)ltraceno;
|
||||||
{
|
the_trace = sc;
|
||||||
(void)ltraceno;
|
return 0;
|
||||||
the_trace = sc;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,11 +31,11 @@
|
|||||||
#define _LAMEBUS_LTRACE_H_
|
#define _LAMEBUS_LTRACE_H_
|
||||||
|
|
||||||
struct ltrace_softc {
|
struct ltrace_softc {
|
||||||
/* Initialized by lower-level attachment function */
|
/* Initialized by lower-level attachment function */
|
||||||
void *lt_busdata;
|
void *lt_busdata;
|
||||||
uint32_t lt_buspos;
|
uint32_t lt_buspos;
|
||||||
bool lt_canstop;
|
bool lt_canstop;
|
||||||
bool lt_canprof;
|
bool lt_canprof;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -34,36 +34,35 @@
|
|||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
/* Lowest revision we support */
|
/* Lowest revision we support */
|
||||||
#define LOW_VERSION 1
|
#define LOW_VERSION 1
|
||||||
/* Revision that supports ltrace_stop() */
|
/* Revision that supports ltrace_stop() */
|
||||||
#define STOP_VERSION 2
|
#define STOP_VERSION 2
|
||||||
/* Revision that supports ltrace_prof() */
|
/* Revision that supports ltrace_prof() */
|
||||||
#define PROF_VERSION 3
|
#define PROF_VERSION 3
|
||||||
|
|
||||||
struct ltrace_softc *
|
struct ltrace_softc *attach_ltrace_to_lamebus(int ltraceno,
|
||||||
attach_ltrace_to_lamebus(int ltraceno, struct lamebus_softc *sc)
|
struct lamebus_softc *sc) {
|
||||||
{
|
struct ltrace_softc *lt;
|
||||||
struct ltrace_softc *lt;
|
uint32_t drl;
|
||||||
uint32_t drl;
|
int slot =
|
||||||
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TRACE,
|
lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TRACE, LOW_VERSION, &drl);
|
||||||
LOW_VERSION, &drl);
|
if (slot < 0) {
|
||||||
if (slot < 0) {
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
lt = kmalloc(sizeof(struct ltrace_softc));
|
lt = kmalloc(sizeof(struct ltrace_softc));
|
||||||
if (lt==NULL) {
|
if (lt == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)ltraceno; // unused
|
(void)ltraceno; // unused
|
||||||
|
|
||||||
lt->lt_busdata = sc;
|
lt->lt_busdata = sc;
|
||||||
lt->lt_buspos = slot;
|
lt->lt_buspos = slot;
|
||||||
lt->lt_canstop = drl >= STOP_VERSION;
|
lt->lt_canstop = drl >= STOP_VERSION;
|
||||||
lt->lt_canprof = drl >= PROF_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 <lamebus/lrandom.h>
|
||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
struct random_softc *
|
struct random_softc *attach_random_to_lrandom(int randomno,
|
||||||
attach_random_to_lrandom(int randomno, struct lrandom_softc *ls)
|
struct lrandom_softc *ls) {
|
||||||
{
|
struct random_softc *rs = kmalloc(sizeof(struct random_softc));
|
||||||
struct random_softc *rs = kmalloc(sizeof(struct random_softc));
|
if (rs == NULL) {
|
||||||
if (rs==NULL) {
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
(void)randomno; // unused
|
(void)randomno; // unused
|
||||||
|
|
||||||
rs->rs_devdata = ls;
|
rs->rs_devdata = ls;
|
||||||
rs->rs_random = lrandom_random;
|
rs->rs_random = lrandom_random;
|
||||||
rs->rs_randmax = lrandom_randmax;
|
rs->rs_randmax = lrandom_randmax;
|
||||||
rs->rs_read = lrandom_read;
|
rs->rs_read = lrandom_read;
|
||||||
|
|
||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,23 +44,22 @@
|
|||||||
#include <lamebus/ltimer.h>
|
#include <lamebus/ltimer.h>
|
||||||
#include "autoconf.h"
|
#include "autoconf.h"
|
||||||
|
|
||||||
struct rtclock_softc *
|
struct rtclock_softc *attach_rtclock_to_ltimer(int rtclockno,
|
||||||
attach_rtclock_to_ltimer(int rtclockno, struct ltimer_softc *ls)
|
struct ltimer_softc *ls) {
|
||||||
{
|
/*
|
||||||
/*
|
* No need to probe; ltimer always has a clock.
|
||||||
* No need to probe; ltimer always has a clock.
|
* Just allocate the rtclock, set our fields, and return it.
|
||||||
* Just allocate the rtclock, set our fields, and return it.
|
*/
|
||||||
*/
|
struct rtclock_softc *rtc = kmalloc(sizeof(struct rtclock_softc));
|
||||||
struct rtclock_softc *rtc = kmalloc(sizeof(struct rtclock_softc));
|
if (rtc == NULL) {
|
||||||
if (rtc==NULL) {
|
/* Out of memory */
|
||||||
/* Out of memory */
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
(void)rtclockno; // unused
|
(void)rtclockno; // unused
|
||||||
|
|
||||||
rtc->rtc_devdata = ls;
|
rtc->rtc_devdata = ls;
|
||||||
rtc->rtc_gettime = ltimer_gettime;
|
rtc->rtc_gettime = ltimer_gettime;
|
||||||
|
|
||||||
return rtc;
|
return rtc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
* Constants
|
* Constants
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SEMFS_ROOTDIR 0xffffffffU /* semnum for root dir */
|
#define SEMFS_ROOTDIR 0xffffffffU /* semnum for root dir */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A user-facing semaphore.
|
* A user-facing semaphore.
|
||||||
@@ -52,11 +52,11 @@
|
|||||||
* XXX: or would we? review once all this is done.
|
* XXX: or would we? review once all this is done.
|
||||||
*/
|
*/
|
||||||
struct semfs_sem {
|
struct semfs_sem {
|
||||||
struct lock *sems_lock; /* Lock to protect count */
|
struct lock *sems_lock; /* Lock to protect count */
|
||||||
struct cv *sems_cv; /* CV to wait */
|
struct cv *sems_cv; /* CV to wait */
|
||||||
unsigned sems_count; /* Semaphore count */
|
unsigned sems_count; /* Semaphore count */
|
||||||
bool sems_hasvnode; /* The vnode exists */
|
bool sems_hasvnode; /* The vnode exists */
|
||||||
bool sems_linked; /* In the directory */
|
bool sems_linked; /* In the directory */
|
||||||
};
|
};
|
||||||
DECLARRAY(semfs_sem, SEMFS_INLINE);
|
DECLARRAY(semfs_sem, SEMFS_INLINE);
|
||||||
|
|
||||||
@@ -64,8 +64,8 @@ DECLARRAY(semfs_sem, SEMFS_INLINE);
|
|||||||
* Directory entry; name and reference to a semaphore.
|
* Directory entry; name and reference to a semaphore.
|
||||||
*/
|
*/
|
||||||
struct semfs_direntry {
|
struct semfs_direntry {
|
||||||
char *semd_name; /* Name */
|
char *semd_name; /* Name */
|
||||||
unsigned semd_semnum; /* Which semaphore */
|
unsigned semd_semnum; /* Which semaphore */
|
||||||
};
|
};
|
||||||
DECLARRAY(semfs_direntry, SEMFS_INLINE);
|
DECLARRAY(semfs_direntry, SEMFS_INLINE);
|
||||||
|
|
||||||
@@ -77,9 +77,9 @@ DECLARRAY(semfs_direntry, SEMFS_INLINE);
|
|||||||
* practice. XXX: review after finishing)
|
* practice. XXX: review after finishing)
|
||||||
*/
|
*/
|
||||||
struct semfs_vnode {
|
struct semfs_vnode {
|
||||||
struct vnode semv_absvn; /* Abstract vnode */
|
struct vnode semv_absvn; /* Abstract vnode */
|
||||||
struct semfs *semv_semfs; /* Back-pointer to fs */
|
struct semfs *semv_semfs; /* Back-pointer to fs */
|
||||||
unsigned semv_semnum; /* Which semaphore */
|
unsigned semv_semnum; /* Which semaphore */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -87,14 +87,14 @@ struct semfs_vnode {
|
|||||||
* is only one of these.
|
* is only one of these.
|
||||||
*/
|
*/
|
||||||
struct semfs {
|
struct semfs {
|
||||||
struct fs semfs_absfs; /* Abstract fs object */
|
struct fs semfs_absfs; /* Abstract fs object */
|
||||||
|
|
||||||
struct lock *semfs_tablelock; /* Lock for following */
|
struct lock *semfs_tablelock; /* Lock for following */
|
||||||
struct vnodearray *semfs_vnodes; /* Currently extant vnodes */
|
struct vnodearray *semfs_vnodes; /* Currently extant vnodes */
|
||||||
struct semfs_semarray *semfs_sems; /* Semaphores */
|
struct semfs_semarray *semfs_sems; /* Semaphores */
|
||||||
|
|
||||||
struct lock *semfs_dirlock; /* Lock for following */
|
struct lock *semfs_dirlock; /* Lock for following */
|
||||||
struct semfs_direntryarray *semfs_dents; /* The root directory */
|
struct semfs_direntryarray *semfs_dents; /* The root directory */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -104,7 +104,6 @@ struct semfs {
|
|||||||
DEFARRAY(semfs_sem, SEMFS_INLINE);
|
DEFARRAY(semfs_sem, SEMFS_INLINE);
|
||||||
DEFARRAY(semfs_direntry, SEMFS_INLINE);
|
DEFARRAY(semfs_direntry, SEMFS_INLINE);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions.
|
* Functions.
|
||||||
*/
|
*/
|
||||||
@@ -119,5 +118,4 @@ void semfs_direntry_destroy(struct semfs_direntry *);
|
|||||||
/* in semfs_vnops.c */
|
/* in semfs_vnops.c */
|
||||||
int semfs_getvnode(struct semfs *, unsigned, struct vnode **ret);
|
int semfs_getvnode(struct semfs *, unsigned, struct vnode **ret);
|
||||||
|
|
||||||
|
|
||||||
#endif /* SEMFS_H */
|
#endif /* SEMFS_H */
|
||||||
|
|||||||
@@ -42,185 +42,163 @@
|
|||||||
/*
|
/*
|
||||||
* Sync doesn't need to do anything.
|
* Sync doesn't need to do anything.
|
||||||
*/
|
*/
|
||||||
static
|
static int semfs_sync(struct fs *fs) {
|
||||||
int
|
(void)fs;
|
||||||
semfs_sync(struct fs *fs)
|
return 0;
|
||||||
{
|
|
||||||
(void)fs;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have only one volume name and it's hardwired.
|
* We have only one volume name and it's hardwired.
|
||||||
*/
|
*/
|
||||||
static
|
static const char *semfs_getvolname(struct fs *fs) {
|
||||||
const char *
|
(void)fs;
|
||||||
semfs_getvolname(struct fs *fs)
|
return "sem";
|
||||||
{
|
|
||||||
(void)fs;
|
|
||||||
return "sem";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the root directory vnode.
|
* Get the root directory vnode.
|
||||||
*/
|
*/
|
||||||
static
|
static int semfs_getroot(struct fs *fs, struct vnode **ret) {
|
||||||
int
|
struct semfs *semfs = fs->fs_data;
|
||||||
semfs_getroot(struct fs *fs, struct vnode **ret)
|
struct vnode *vn;
|
||||||
{
|
int result;
|
||||||
struct semfs *semfs = fs->fs_data;
|
|
||||||
struct vnode *vn;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
result = semfs_getvnode(semfs, SEMFS_ROOTDIR, &vn);
|
result = semfs_getvnode(semfs, SEMFS_ROOTDIR, &vn);
|
||||||
if (result) {
|
if (result) {
|
||||||
kprintf("semfs: couldn't load root vnode: %s\n",
|
kprintf("semfs: couldn't load root vnode: %s\n", strerror(result));
|
||||||
strerror(result));
|
return result;
|
||||||
return result;
|
}
|
||||||
}
|
*ret = vn;
|
||||||
*ret = vn;
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// mount and unmount logic
|
// mount and unmount logic
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destructor for struct semfs.
|
* Destructor for struct semfs.
|
||||||
*/
|
*/
|
||||||
static
|
static void semfs_destroy(struct semfs *semfs) {
|
||||||
void
|
struct semfs_sem *sem;
|
||||||
semfs_destroy(struct semfs *semfs)
|
struct semfs_direntry *dent;
|
||||||
{
|
unsigned i, num;
|
||||||
struct semfs_sem *sem;
|
|
||||||
struct semfs_direntry *dent;
|
|
||||||
unsigned i, num;
|
|
||||||
|
|
||||||
num = semfs_semarray_num(semfs->semfs_sems);
|
num = semfs_semarray_num(semfs->semfs_sems);
|
||||||
for (i=0; i<num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
sem = semfs_semarray_get(semfs->semfs_sems, i);
|
sem = semfs_semarray_get(semfs->semfs_sems, i);
|
||||||
semfs_sem_destroy(sem);
|
semfs_sem_destroy(sem);
|
||||||
}
|
}
|
||||||
semfs_semarray_setsize(semfs->semfs_sems, 0);
|
semfs_semarray_setsize(semfs->semfs_sems, 0);
|
||||||
|
|
||||||
num = semfs_direntryarray_num(semfs->semfs_dents);
|
num = semfs_direntryarray_num(semfs->semfs_dents);
|
||||||
for (i=0; i<num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
dent = semfs_direntryarray_get(semfs->semfs_dents, i);
|
dent = semfs_direntryarray_get(semfs->semfs_dents, i);
|
||||||
semfs_direntry_destroy(dent);
|
semfs_direntry_destroy(dent);
|
||||||
}
|
}
|
||||||
semfs_direntryarray_setsize(semfs->semfs_dents, 0);
|
semfs_direntryarray_setsize(semfs->semfs_dents, 0);
|
||||||
|
|
||||||
semfs_direntryarray_destroy(semfs->semfs_dents);
|
semfs_direntryarray_destroy(semfs->semfs_dents);
|
||||||
lock_destroy(semfs->semfs_dirlock);
|
lock_destroy(semfs->semfs_dirlock);
|
||||||
semfs_semarray_destroy(semfs->semfs_sems);
|
semfs_semarray_destroy(semfs->semfs_sems);
|
||||||
vnodearray_destroy(semfs->semfs_vnodes);
|
vnodearray_destroy(semfs->semfs_vnodes);
|
||||||
lock_destroy(semfs->semfs_tablelock);
|
lock_destroy(semfs->semfs_tablelock);
|
||||||
kfree(semfs);
|
kfree(semfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unmount routine. XXX: Since semfs is attached at boot and can't be
|
* Unmount routine. XXX: Since semfs is attached at boot and can't be
|
||||||
* remounted, maybe unmounting it shouldn't be allowed.
|
* remounted, maybe unmounting it shouldn't be allowed.
|
||||||
*/
|
*/
|
||||||
static
|
static int semfs_unmount(struct fs *fs) {
|
||||||
int
|
struct semfs *semfs = fs->fs_data;
|
||||||
semfs_unmount(struct fs *fs)
|
|
||||||
{
|
|
||||||
struct semfs *semfs = fs->fs_data;
|
|
||||||
|
|
||||||
lock_acquire(semfs->semfs_tablelock);
|
lock_acquire(semfs->semfs_tablelock);
|
||||||
if (vnodearray_num(semfs->semfs_vnodes) > 0) {
|
if (vnodearray_num(semfs->semfs_vnodes) > 0) {
|
||||||
lock_release(semfs->semfs_tablelock);
|
lock_release(semfs->semfs_tablelock);
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock_release(semfs->semfs_tablelock);
|
lock_release(semfs->semfs_tablelock);
|
||||||
semfs_destroy(semfs);
|
semfs_destroy(semfs);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Operations table.
|
* Operations table.
|
||||||
*/
|
*/
|
||||||
static const struct fs_ops semfs_fsops = {
|
static const struct fs_ops semfs_fsops = {
|
||||||
.fsop_sync = semfs_sync,
|
.fsop_sync = semfs_sync,
|
||||||
.fsop_getvolname = semfs_getvolname,
|
.fsop_getvolname = semfs_getvolname,
|
||||||
.fsop_getroot = semfs_getroot,
|
.fsop_getroot = semfs_getroot,
|
||||||
.fsop_unmount = semfs_unmount,
|
.fsop_unmount = semfs_unmount,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constructor for struct semfs.
|
* Constructor for struct semfs.
|
||||||
*/
|
*/
|
||||||
static
|
static struct semfs *semfs_create(void) {
|
||||||
struct semfs *
|
struct semfs *semfs;
|
||||||
semfs_create(void)
|
|
||||||
{
|
|
||||||
struct semfs *semfs;
|
|
||||||
|
|
||||||
semfs = kmalloc(sizeof(*semfs));
|
semfs = kmalloc(sizeof(*semfs));
|
||||||
if (semfs == NULL) {
|
if (semfs == NULL) {
|
||||||
goto fail_total;
|
goto fail_total;
|
||||||
}
|
}
|
||||||
|
|
||||||
semfs->semfs_tablelock = lock_create("semfs_table");
|
semfs->semfs_tablelock = lock_create("semfs_table");
|
||||||
if (semfs->semfs_tablelock == NULL) {
|
if (semfs->semfs_tablelock == NULL) {
|
||||||
goto fail_semfs;
|
goto fail_semfs;
|
||||||
}
|
}
|
||||||
semfs->semfs_vnodes = vnodearray_create();
|
semfs->semfs_vnodes = vnodearray_create();
|
||||||
if (semfs->semfs_vnodes == NULL) {
|
if (semfs->semfs_vnodes == NULL) {
|
||||||
goto fail_tablelock;
|
goto fail_tablelock;
|
||||||
}
|
}
|
||||||
semfs->semfs_sems = semfs_semarray_create();
|
semfs->semfs_sems = semfs_semarray_create();
|
||||||
if (semfs->semfs_sems == NULL) {
|
if (semfs->semfs_sems == NULL) {
|
||||||
goto fail_vnodes;
|
goto fail_vnodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
semfs->semfs_dirlock = lock_create("semfs_dir");
|
semfs->semfs_dirlock = lock_create("semfs_dir");
|
||||||
if (semfs->semfs_dirlock == NULL) {
|
if (semfs->semfs_dirlock == NULL) {
|
||||||
goto fail_sems;
|
goto fail_sems;
|
||||||
}
|
}
|
||||||
semfs->semfs_dents = semfs_direntryarray_create();
|
semfs->semfs_dents = semfs_direntryarray_create();
|
||||||
if (semfs->semfs_dents == NULL) {
|
if (semfs->semfs_dents == NULL) {
|
||||||
goto fail_dirlock;
|
goto fail_dirlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
semfs->semfs_absfs.fs_data = semfs;
|
semfs->semfs_absfs.fs_data = semfs;
|
||||||
semfs->semfs_absfs.fs_ops = &semfs_fsops;
|
semfs->semfs_absfs.fs_ops = &semfs_fsops;
|
||||||
return semfs;
|
return semfs;
|
||||||
|
|
||||||
fail_dirlock:
|
fail_dirlock:
|
||||||
lock_destroy(semfs->semfs_dirlock);
|
lock_destroy(semfs->semfs_dirlock);
|
||||||
fail_sems:
|
fail_sems:
|
||||||
semfs_semarray_destroy(semfs->semfs_sems);
|
semfs_semarray_destroy(semfs->semfs_sems);
|
||||||
fail_vnodes:
|
fail_vnodes:
|
||||||
vnodearray_destroy(semfs->semfs_vnodes);
|
vnodearray_destroy(semfs->semfs_vnodes);
|
||||||
fail_tablelock:
|
fail_tablelock:
|
||||||
lock_destroy(semfs->semfs_tablelock);
|
lock_destroy(semfs->semfs_tablelock);
|
||||||
fail_semfs:
|
fail_semfs:
|
||||||
kfree(semfs);
|
kfree(semfs);
|
||||||
fail_total:
|
fail_total:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the semfs. There is only one semfs and it's attached as
|
* Create the semfs. There is only one semfs and it's attached as
|
||||||
* "sem:" during bootup.
|
* "sem:" during bootup.
|
||||||
*/
|
*/
|
||||||
void
|
void semfs_bootstrap(void) {
|
||||||
semfs_bootstrap(void)
|
struct semfs *semfs;
|
||||||
{
|
int result;
|
||||||
struct semfs *semfs;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
semfs = semfs_create();
|
semfs = semfs_create();
|
||||||
if (semfs == NULL) {
|
if (semfs == NULL) {
|
||||||
panic("Out of memory creating semfs\n");
|
panic("Out of memory creating semfs\n");
|
||||||
}
|
}
|
||||||
result = vfs_addfs("sem", &semfs->semfs_absfs);
|
result = vfs_addfs("sem", &semfs->semfs_absfs);
|
||||||
if (result) {
|
if (result) {
|
||||||
panic("Attaching semfs: %s\n", strerror(result));
|
panic("Attaching semfs: %s\n", strerror(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,74 +40,69 @@
|
|||||||
/*
|
/*
|
||||||
* Constructor for semfs_sem.
|
* Constructor for semfs_sem.
|
||||||
*/
|
*/
|
||||||
struct semfs_sem *
|
struct semfs_sem *semfs_sem_create(const char *name) {
|
||||||
semfs_sem_create(const char *name)
|
struct semfs_sem *sem;
|
||||||
{
|
char lockname[32];
|
||||||
struct semfs_sem *sem;
|
char cvname[32];
|
||||||
char lockname[32];
|
|
||||||
char cvname[32];
|
|
||||||
|
|
||||||
snprintf(lockname, sizeof(lockname), "sem:l.%s", name);
|
snprintf(lockname, sizeof(lockname), "sem:l.%s", name);
|
||||||
snprintf(cvname, sizeof(cvname), "sem:%s", name);
|
snprintf(cvname, sizeof(cvname), "sem:%s", name);
|
||||||
|
|
||||||
sem = kmalloc(sizeof(*sem));
|
sem = kmalloc(sizeof(*sem));
|
||||||
if (sem == NULL) {
|
if (sem == NULL) {
|
||||||
goto fail_return;
|
goto fail_return;
|
||||||
}
|
}
|
||||||
sem->sems_lock = lock_create(lockname);
|
sem->sems_lock = lock_create(lockname);
|
||||||
if (sem->sems_lock == NULL) {
|
if (sem->sems_lock == NULL) {
|
||||||
goto fail_sem;
|
goto fail_sem;
|
||||||
}
|
}
|
||||||
sem->sems_cv = cv_create(cvname);
|
sem->sems_cv = cv_create(cvname);
|
||||||
if (sem->sems_cv == NULL) {
|
if (sem->sems_cv == NULL) {
|
||||||
goto fail_lock;
|
goto fail_lock;
|
||||||
}
|
}
|
||||||
sem->sems_count = 0;
|
sem->sems_count = 0;
|
||||||
sem->sems_hasvnode = false;
|
sem->sems_hasvnode = false;
|
||||||
sem->sems_linked = false;
|
sem->sems_linked = false;
|
||||||
return sem;
|
return sem;
|
||||||
|
|
||||||
fail_lock:
|
fail_lock:
|
||||||
lock_destroy(sem->sems_lock);
|
lock_destroy(sem->sems_lock);
|
||||||
fail_sem:
|
fail_sem:
|
||||||
kfree(sem);
|
kfree(sem);
|
||||||
fail_return:
|
fail_return:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destructor for semfs_sem.
|
* Destructor for semfs_sem.
|
||||||
*/
|
*/
|
||||||
void
|
void semfs_sem_destroy(struct semfs_sem *sem) {
|
||||||
semfs_sem_destroy(struct semfs_sem *sem)
|
cv_destroy(sem->sems_cv);
|
||||||
{
|
lock_destroy(sem->sems_lock);
|
||||||
cv_destroy(sem->sems_cv);
|
kfree(sem);
|
||||||
lock_destroy(sem->sems_lock);
|
|
||||||
kfree(sem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper to insert a semfs_sem into the semaphore table.
|
* Helper to insert a semfs_sem into the semaphore table.
|
||||||
*/
|
*/
|
||||||
int
|
int semfs_sem_insert(struct semfs *semfs, struct semfs_sem *sem,
|
||||||
semfs_sem_insert(struct semfs *semfs, struct semfs_sem *sem, unsigned *ret)
|
unsigned *ret) {
|
||||||
{
|
unsigned i, num;
|
||||||
unsigned i, num;
|
|
||||||
|
|
||||||
KASSERT(lock_do_i_hold(semfs->semfs_tablelock));
|
KASSERT(lock_do_i_hold(semfs->semfs_tablelock));
|
||||||
num = semfs_semarray_num(semfs->semfs_sems);
|
num = semfs_semarray_num(semfs->semfs_sems);
|
||||||
if (num == SEMFS_ROOTDIR) {
|
if (num == SEMFS_ROOTDIR) {
|
||||||
/* Too many */
|
/* Too many */
|
||||||
return ENOSPC;
|
return ENOSPC;
|
||||||
}
|
}
|
||||||
for (i=0; i<num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
if (semfs_semarray_get(semfs->semfs_sems, i) == NULL) {
|
if (semfs_semarray_get(semfs->semfs_sems, i) == NULL) {
|
||||||
semfs_semarray_set(semfs->semfs_sems, i, sem);
|
semfs_semarray_set(semfs->semfs_sems, i, sem);
|
||||||
*ret = i;
|
*ret = i;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return semfs_semarray_add(semfs->semfs_sems, sem, ret);
|
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.
|
* Constructor for semfs_direntry.
|
||||||
*/
|
*/
|
||||||
struct semfs_direntry *
|
struct semfs_direntry *semfs_direntry_create(const char *name,
|
||||||
semfs_direntry_create(const char *name, unsigned semnum)
|
unsigned semnum) {
|
||||||
{
|
struct semfs_direntry *dent;
|
||||||
struct semfs_direntry *dent;
|
|
||||||
|
|
||||||
dent = kmalloc(sizeof(*dent));
|
dent = kmalloc(sizeof(*dent));
|
||||||
if (dent == NULL) {
|
if (dent == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
dent->semd_name = kstrdup(name);
|
dent->semd_name = kstrdup(name);
|
||||||
if (dent->semd_name == NULL) {
|
if (dent->semd_name == NULL) {
|
||||||
kfree(dent);
|
kfree(dent);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
dent->semd_semnum = semnum;
|
dent->semd_semnum = semnum;
|
||||||
return dent;
|
return dent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destructor for semfs_direntry.
|
* Destructor for semfs_direntry.
|
||||||
*/
|
*/
|
||||||
void
|
void semfs_direntry_destroy(struct semfs_direntry *dent) {
|
||||||
semfs_direntry_destroy(struct semfs_direntry *dent)
|
kfree(dent->semd_name);
|
||||||
{
|
kfree(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
Reference in New Issue
Block a user