From 96fa3896181956dad257415411aa390bcef1a487 Mon Sep 17 00:00:00 2001 From: "Ronald G. Minnich" Date: Mon, 16 Oct 2000 03:03:03 +0000 Subject: [PATCH] Building the new src tree --- src/cpu/p5/cpuid.c | 215 ++++++ src/lib/definitions.h | 35 + src/lib/inflate.c | 1214 ++++++++++++++++++++++++++++++ src/lib/linuxbiosmain.c | 1579 +++++++++++++++++++++++++++++++++++++++ src/lib/linuxpci.c | 478 ++++++++++++ src/lib/newpci.c | 993 ++++++++++++++++++++++++ src/lib/printk.c | 62 ++ src/lib/vsprintf.c | 331 ++++++++ src/pc80/serial.inc | 192 +++++ 9 files changed, 5099 insertions(+) create mode 100644 src/cpu/p5/cpuid.c create mode 100644 src/lib/definitions.h create mode 100644 src/lib/inflate.c create mode 100644 src/lib/linuxbiosmain.c create mode 100644 src/lib/linuxpci.c create mode 100644 src/lib/newpci.c create mode 100644 src/lib/printk.c create mode 100644 src/lib/vsprintf.c create mode 100644 src/pc80/serial.inc diff --git a/src/cpu/p5/cpuid.c b/src/cpu/p5/cpuid.c new file mode 100644 index 0000000000..82615535c9 --- /dev/null +++ b/src/cpu/p5/cpuid.c @@ -0,0 +1,215 @@ +#include "intel_conf.h" +#include "intel_subr.h" +#include "printk.h" + +#ifdef i586 +#include +#endif + +#ifdef i586 +int intel_mtrr_check(void) +{ + unsigned long low, high; + + printk(KERN_INFO "\nMTRR check\n"); + + rdmsr(0x2ff, low, high); + low = low >> 10; + + printk(KERN_INFO "Fixed MTRRs : "); + if (low & 0x01) + printk(KERN_INFO "Enabled\n"); + else + printk(KERN_INFO "Disabled\n"); + + printk(KERN_INFO "Variable MTRRs: "); + if (low & 0x02) + printk(KERN_INFO "Enabled\n"); + else + printk(KERN_INFO "Disabled\n"); + + printk(KERN_INFO "\n"); + + return ((int) low); +} +#endif + +void intel_display_cpuid(void) +{ + int op, eax, ebx, ecx, edx; + int max_op; + + max_op = 0; + + printk(KERN_INFO "\n"); + + for (op = 0; op <= max_op; op++) { + intel_cpuid(op, &eax, &ebx, &ecx, &edx); + + if (0 == op) { + max_op = eax; + printk(KERN_INFO "Max cpuid index : %d\n", eax); + printk(KERN_INFO "Vendor ID : " + "%c%c%c%c%c%c%c%c%c%c%c%c\n", + ebx, ebx >> 8, ebx >> 16, ebx >> 24, edx, + edx >> 8, edx >> 16, edx >> 24, ecx, ecx >> 8, + ecx >> 16, ecx >> 24); + } else if (1 == op) { + printk(KERN_INFO "Processor Type : 0x%02x\n", + (eax >> 12) & 0x03); + printk(KERN_INFO "Processor Family : 0x%02x\n", + (eax >> 8) & 0x0f); + printk(KERN_INFO "Processor Model : 0x%02x\n", + (eax >> 4) & 0x0f); + printk(KERN_INFO "Processor Mask : 0x%02x\n", + (ecx >> 0) & 0x0f); + printk(KERN_INFO "Processor Stepping : 0x%02x\n", + (eax >> 0) & 0x0f); + printk(KERN_INFO "Feature flags : 0x%08x\n", edx); + } else if (2 == op) { + int desc[4]; + int ii; + int _desc; + + printk(KERN_INFO "\n"); + + printk(KERN_INFO "Cache/TLB descriptor values: %d " + "reads required\n", eax & 0xff); + + desc[0] = eax; + desc[1] = ebx; + desc[2] = ecx; + desc[3] = edx; + + for (ii = 1; ii < 16; ii++) { + if (desc[ii >> 2] & 0x80000000) { + printk(KERN_INFO + "reserved descriptor\n"); + continue; + } + + _desc = + ((desc[ii>>2]) >> ((ii & 0x3) << 3)) & 0xff; + printk(KERN_INFO "Desc 0x%02x : ", _desc); + + switch (_desc) { + case 0x00: + printk(KERN_INFO "null\n"); + break; + + case 0x01: + printk(KERN_INFO "Instr TLB: " + "4KB pages, " + "4-way set assoc, " + "32 entries\n"); + break; + + case 0x02: + printk(KERN_INFO "Instr TLB: " + "4MB pages, " + "fully assoc, " + "2 entries\n"); + break; + + case 0x03: + printk(KERN_INFO "Data TLB: " + "4KB pages, " + "4-way set assoc, " + "64 entries\n"); + break; + + case 0x04: + printk(KERN_INFO "Data TLB: " + "4MB pages, " + "4-way set assoc, " + "8 entries\n"); + break; + + case 0x06: + printk(KERN_INFO "Inst cache: " + "8K bytes, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x08: + printk(KERN_INFO "Inst cache: " + "16K bytes, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x0a: + printk(KERN_INFO "Data cache: " + "8K bytes, " + "2-way set assoc, " + "32 byte line size\n"); + break; + + case 0x0c: + printk(KERN_INFO "Data cache: " + "16K bytes, " + "2-way or 4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x40: + printk(KERN_INFO "No L2 cache\n"); + break; + + case 0x41: + printk(KERN_INFO "L2 Unified cache: " + "128K bytes, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x42: + printk(KERN_INFO "L2 Unified cache: " + "256K bytes, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x43: + printk(KERN_INFO "L2 Unified cache: " + "512K bytes, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x44: + printk(KERN_INFO "L2 Unified cache: " + "1M byte, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x45: + printk(KERN_INFO "L2 Unified cache: " + "2M byte, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x82: + printk(KERN_INFO "L2 Unified cache: " + "256K bytes, " + "8-way set assoc, " + "32 byte line size\n"); + break; + + default: + printk(KERN_INFO "UNKNOWN\n"); + } + } + printk(KERN_INFO "\n"); + } else { + printk(KERN_INFO "op: 0x%02x eax:0x%08x " + "ebx:0x%08x ecx:0x%08x edx:0x%08x\n", + op, eax, ebx, ecx, edx); + } + } + + printk(KERN_INFO "\n"); +} diff --git a/src/lib/definitions.h b/src/lib/definitions.h new file mode 100644 index 0000000000..3786632d41 --- /dev/null +++ b/src/lib/definitions.h @@ -0,0 +1,35 @@ +/* Comment this out unless you are debugging under linux */ +#define EMULATE +#undef EMULATE + +#ifdef EMULATE +#include +#else +typedef unsigned long size_t; +#endif + +#ifdef EMULATE + #define MEMSIZE 2*1024*1024 /* Make a 2MB fake memory space */ + char memimage[MEMSIZE]; /* Make a 2MB fake memory space */ +#else + #define memimage 0x0 /* Ignore memimage */ +#endif + +#define KERNEL_START (0x100000 + memimage) /* Put our copy of linux here */ + +#if 0 +#define ZIP_START (0x30000 + memimage) /* The zip file starts here */ +#define ZIP_SIZE 262164 /* linux.gz size (we ought to */ +#endif + +/* with flash, it's a bunch of 64k segments. */ +#define ZIP_START (0xfff40000) +#define ZIP_SIZE (0x10000) + +#ifdef EMULATE +char input_array[0x100000]; +#undef ZIP_START +#define ZIP_START (input_array + 0x40000) +#endif + /* make this dynamic) */ + diff --git a/src/lib/inflate.c b/src/lib/inflate.c new file mode 100644 index 0000000000..6f691c297f --- /dev/null +++ b/src/lib/inflate.c @@ -0,0 +1,1214 @@ +#define DEBG(x) +#define DEBGINT(x) +#define DEBG1(x) +#define DEBGH(x) +#define DEBGDYN(x) +/* Taken from /usr/src/linux/lib/inflate.c [unmodified] + Used for start32, 1/11/2000 + James Hendricks, Dale Webster */ + +/* inflate.c -- Not copyrighted 1992 by Mark Adler + version c10p1, 10 January 1993 */ + +/* + * Adapted for booting Linux by Hannu Savolainen 1993 + * based on gzip-1.0.3 + */ + +/* + Inflate deflated (PKZIP's method 8 compressed) data. The compression + method searches for as much of the current string of bytes (up to a + length of 258) in the previous 32 K bytes. If it doesn't find any + matches (of at least length 3), it codes the next byte. Otherwise, it + codes the length of the matched string and its distance backwards from + the current position. There is a single Huffman code that codes both + single bytes (called "literals") and match lengths. A second Huffman + code codes the distance information, which follows a length code. Each + length or distance code actually represents a base value and a number + of "extra" (sometimes zero) bits to get to add to the base value. At + the end of each deflated block is a special end-of-block (EOB) literal/ + length code. The decoding process is basically: get a literal/length + code; if EOB then done; if a literal, emit the decoded byte; if a + length then get the distance and emit the referred-to bytes from the + sliding window of previously emitted data. + + There are (currently) three kinds of inflate blocks: stored, fixed, and + dynamic. The compressor deals with some chunk of data at a time, and + decides which method to use on a chunk-by-chunk basis. A chunk might + typically be 32 K or 64 K. If the chunk is incompressible, then the + "stored" method is used. In this case, the bytes are simply stored as + is, eight bits per byte, with none of the above coding. The bytes are + preceded by a count, since there is no longer an EOB code. + + If the data is compressible, then either the fixed or dynamic methods + are used. In the dynamic method, the compressed data is preceded by + an encoding of the literal/length and distance Huffman codes that are + to be used to decode this block. The representation is itself Huffman + coded, and so is preceded by a description of that code. These code + descriptions take up a little space, and so for small blocks, there is + a predefined set of codes, called the fixed codes. The fixed method is + used if the block codes up smaller that way (usually for quite small + chunks), otherwise the dynamic method is used. In the latter case, the + codes are customized to the probabilities in the current block, and so + can code it much better than the pre-determined fixed codes. + + The Huffman codes themselves are decoded using a multi-level table + lookup, in order to maximize the speed of decoding plus the speed of + building the decoding tables. See the comments below that precede the + lbits and dbits tuning parameters. + */ + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarly, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + +#ifdef RCSID +static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #"; +#endif + +#ifndef STATIC + +#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H) +# include +# include +#endif + + +#include "gzip.h" +#define STATIC +#endif /* !STATIC */ + +#define slide window + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). + Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 + means that v is a literal, 16 < e < 32 means that v is a pointer to + the next table, which codes e - 16 bits, and lastly e == 99 indicates + an unused code. If a code with e == 99 is looked up, this implies an + error in the data. */ +struct huft { + uch e; /* number of extra bits or operation */ + uch b; /* number of bits in this code or subcode */ + union { + ush n; /* literal, length base, or distance base */ + struct huft *t; /* pointer to next level of table */ + } v; +}; + + +/* Function prototypes */ +STATIC int huft_build OF((unsigned *, unsigned, unsigned, const ush *, + const ush *, struct huft **, int *)); +STATIC int huft_free OF((struct huft *)); +STATIC int inflate_codes OF((struct huft *, struct huft *, int, int)); +STATIC int inflate_stored OF((void)); +STATIC int inflate_fixed OF((void)); +STATIC int inflate_dynamic OF((void)); +STATIC int inflate_block OF((int *)); +STATIC int inflate OF((void)); + + +/* The inflate algorithm uses a sliding 32 K byte window on the uncompressed + stream to find repeated byte strings. This is implemented here as a + circular buffer. The index is updated simply by incrementing and then + ANDing with 0x7fff (32K-1). */ +/* It is left to other modules to supply the 32 K area. It is assumed + to be usable as if it were declared "uch slide[32768];" or as just + "uch *slide;" and then malloc'ed in the latter case. The definition + must be in unzip.h, included above. */ +/* unsigned wp; current position in slide */ +#define wp outcnt +#define flush_output(w) (wp=(w),flush_window()) + +/* Tables for deflate from PKZIP's appnote.txt. */ +const unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +const ush cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ +const ush cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ +const ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +const ush cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + + +/* Macros for inflate() bit peeking and grabbing. + The usage is: + + NEEDBITS(j) + x = b & mask_bits[j]; + DUMPBITS(j) + + where NEEDBITS makes sure that b has at least j bits in it, and + DUMPBITS removes the bits from b. The macros use the variable k + for the number of bits in b. Normally, b and k are register + variables for speed, and are initialized at the beginning of a + routine that uses these macros from a global bit buffer and count. + + If we assume that EOB will be the longest code, then we will never + ask for bits with NEEDBITS that are beyond the end of the stream. + So, NEEDBITS should not read any more bytes than are needed to + meet the request. Then no bytes need to be "returned" to the buffer + at the end of the last block. + + However, this assumption is not true for fixed blocks--the EOB code + is 7 bits, but the other literal/length codes can be 8 or 9 bits. + (The EOB code is shorter than other codes because fixed blocks are + generally short. So, while a block always has an EOB, many other + literal/length codes have a significantly lower probability of + showing up at all.) However, by making the first table have a + lookup of seven bits, the EOB code will be found in that first + lookup, and so will not require that too many bits be pulled from + the stream. + */ + +STATIC ulg bb; /* bit buffer */ +STATIC unsigned bk; /* bits in bit buffer */ + +const ush mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +#define NEXTBYTE() (uch)get_byte() +#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<>=(n);k-=(n);} + + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +STATIC int lbits ; /* bits in base literal/length lookup table */ +STATIC int dbits ; /* bits in base distance lookup table */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + + +STATIC unsigned hufts; /* track memory usage */ + + +STATIC int huft_build( + unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ + unsigned n, /* number of codes (assumed <= N_MAX) */ + unsigned s, /* number of simple-valued codes (0..s-1) */ + const ush *d, /* list of base values for non-simple codes */ + const ush *e, /* list of extra bits for non-simple codes */ + struct huft **t, /* result: starting table */ + int *m) /* maximum lookup bits, returns actual */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. */ +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX+1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX+1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + +DEBGH("huft1 "); + + /* Generate counts for each bit length */ + memzero(c, sizeof(c)); + p = b; i = n; + do { + Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), + n-i, *p)); + c[*p]++; /* assume all entries <= BMAX */ + p++; /* Can't combine with above line (Solaris bug) */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = 0; + *m = 0; + return 0; + } + +DEBGH("huft2 "); + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned)l > i) + l = i; + *m = l; + +DEBGH("huft3 "); + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + +DEBGH("huft4 "); + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + +DEBGH("huft5 "); + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + +DEBGH("h6 "); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = 0; /* just to keep compilers happy */ + q = (struct huft *)0; /* ditto */ + z = 0; /* ditto */ +DEBGH("h6a "); + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { +DEBGH("h6b "); + a = c[k]; + while (a--) + { +DEBGH("h6b1 "); + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { +DEBG1("1 "); + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ +DEBG1("2 "); + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } +DEBG1("3 "); + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) == 0) + { + if (h) + huft_free(u[0]); + return 3; /* not enough memory */ + } +DEBG1("4 "); + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = 0; + u[h] = ++q; /* table starts after link */ + +DEBG1("5 "); + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch)l; /* bits to dump before this table */ + r.e = (uch)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } +DEBG1("6 "); + } +DEBGH("h6c "); + + /* set up table entry in r */ + r.b = (uch)(k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (ush)(*p); /* simple code is just the value */ + p++; /* one compiler does not like *p++ */ + } + else + { + r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } +DEBGH("h6d "); + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } +DEBGH("h6e "); + } +DEBGH("h6f "); + } + +DEBGH("huft7 "); + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + + + +STATIC int huft_free( +struct huft *t) /* table to free */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register struct huft *p, *q; + + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != 0) + { + q = (--p)->v.t; + free((char*)p); + p = q; + } + return 0; +} + + +STATIC int inflate_codes( + struct huft *tl, + struct huft *td, /* literal/length and distance decoder tables */ + int bl, + int bd) /* number of bits decoded by tl[] and td[] */ +/* inflate (decompress) the codes in a deflated (compressed) block. + Return an error code or zero if it all goes ok. */ +{ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + for (;;) /* do until end of block */ + { + NEEDBITS((unsigned)bl) + if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + if (e == 16) /* then it's a literal */ + { +/* + DEBG("l"); + */ + slide[w++] = (uch)t->v.n; + Tracevv((stderr, "%c", slide[w-1])); + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if (e == 15) + break; + + /* get length of block to copy */ + NEEDBITS(e) + n = t->v.n + ((unsigned)b & mask_bits[e]); + DUMPBITS(e); + + /* decode distance of block to copy */ + NEEDBITS((unsigned)bd) + if ((e = (t = td + ((unsigned)b & md))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + NEEDBITS(e) + d = w - t->v.n - ((unsigned)b & mask_bits[e]); + DUMPBITS(e) + Tracevv((stderr,"\\[%d,%d]", w-d, n)); +/* + DEBG("D");printint(w-d);printint(n); + */ + + /* do the copy */ + do { + n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); +#if 0 + DEBG("memcpy %d to %d size %d"); printint(d); printint(w); + printint(e); + DEBG("\n"); +#endif +#if !defined(NOMEMCPY) && !defined(DEBUG) + if (w - d >= e) /* (this test assumes unsigned comparison) */ + { + memcpy(slide + w, slide + d, e); + w += e; + d += e; + } + else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + slide[w++] = slide[d++]; + Tracevv((stderr, "%c", slide[w-1])); + } while (--e); + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } while (n); + } + } + + + /* restore the globals from the locals */ + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + /* done */ + return 0; +} + + + +STATIC int inflate_stored(void) +/* "decompress" an inflated type 0 (stored) block. */ +{ + unsigned n; /* number of bytes in block */ + unsigned w; /* current window position */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + +DEBG(""); + return 0; +} + + + +STATIC int inflate_fixed(void) +/* decompress an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ +{ + int i; /* temporary variable */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned l[288]; /* length list for huft_build */ + +DEBG(" 1) + { + huft_free(tl); + + DEBG(">"); + return i; + } + + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; +} + + + +STATIC int inflate_dynamic(void) +/* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ +#ifdef PKZIP_BUG_WORKAROUND + unsigned ll[288+32]; /* literal/length and distance code lengths */ +#else + unsigned ll[286+30]; /* literal/length and distance code lengths */ +#endif + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + +#if 0 + for(i = 0; i < 288+32; i++) + if (ll[i]) { + display("non-zero ll index at "); + printint(i); + } +#endif +DEBG(" 288 || nd > 32) +#else + if (nl > 286 || nd > 30) +#endif + return 1; /* bad lengths */ +DEBGINT(nl); DEBGINT(nd); DEBGINT(nb); +DEBGDYN("dyn1 "); + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS(3) + ll[border[j]] = (unsigned)b & 7; + DUMPBITS(3) + } + for (; j < 19; j++) + ll[border[j]] = 0; + + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build(ll, 19, 19, 0, 0, &tl, &bl)) != 0) + { + if (i == 1) + huft_free(tl); + return i; /* incomplete code set */ + } + +DEBGDYN("dyn3 freemem now "); DEBGINT(free_mem_ptr); + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned)i < n) + { + NEEDBITS((unsigned)bl) + j = (td = tl + ((unsigned)b & m))->b; + DUMPBITS(j) + j = td->v.n; +/* + DEBGDYN("j is now"); DEBGINT(j); + */ + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS(2) + j = 3 + ((unsigned)b & 3); + DUMPBITS(2) +/* + DEBGDYN("j second is now"); DEBGINT(j); + */ + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS(3) + j = 3 + ((unsigned)b & 7); + DUMPBITS(3) +/* + DEBGDYN("j three is now"); DEBGINT(j); + */ + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS(7) + j = 11 + ((unsigned)b & 0x7f); + DUMPBITS(7) +/* + DEBGDYN("j four is now"); DEBGINT(j); + */ + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + } + +DEBGDYN("dyn4 "); + + /* free decoding table for trees */ + huft_free(tl); + +DEBGDYN("dyn5 free mem is now");DEBGINT(free_mem_ptr); + + /* restore the global bit buffer */ + bb = b; + bk = k; + +DEBGDYN("dyn5a "); + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) + { +DEBGDYN("dyn5b "); + if (i == 1) { + error(" incomplete literal tree\n"); + huft_free(tl); + } + return i; /* incomplete code set */ + } +DEBGDYN("dyn5c "); + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) + { +DEBGDYN("dyn5d "); + if (i == 1) { + error(" incomplete distance tree\n"); +#ifdef PKZIP_BUG_WORKAROUND + i = 0; + } +#else + huft_free(td); + } + huft_free(tl); + return i; /* incomplete code set */ +#endif + } + +DEBGDYN("dyn6 free_mem_ptr ");DEBGINT(free_mem_ptr); + + /* decompress until an end-of-block code */ +DEBG("inflate_codes inptr is "); DEBGINT(inptr); + if (inflate_codes(tl, td, bl, bd)) + return 1; + +DEBG("AFTER inflate_codes inptr is "); DEBGINT(inptr); +DEBGDYN("dyn7 "); + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + + DEBG(">"); + return 0; +} + + + +STATIC int inflate_block( +int *e) /* last block flag */ +/* decompress an inflated block */ +{ + unsigned t; /* block type */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + DEBG(""); + + /* bad block type */ + return 2; +} + + + +STATIC int inflate(void) +/* decompress an inflated entry */ +{ + int e; /* last block flag */ + int r; /* result code */ + unsigned h; /* maximum struct huft's malloc'ed */ + void *ptr; + + /* initialize window, bit buffer */ + wp = 0; + bk = 0; + bb = 0; + + + /* decompress until the last block */ + h = 0; + do { + hufts = 0; + gzip_mark(&ptr); + if ((r = inflate_block(&e)) != 0) { + gzip_release(&ptr); + return r; + } + gzip_release(&ptr); + if (hufts > h) + h = hufts; + } while (!e); + + /* Undo too much lookahead. The next read will be byte aligned so we + * can discard unused bits in the last meaningful byte. + */ + while (bk >= 8) { + bk -= 8; + inptr--; + } + + /* flush out slide */ + flush_output(wp); + + + /* return success */ + DBG("<%u> ", h); + return 0; +} + +/********************************************************************** + * + * The following are support routines for inflate.c + * + **********************************************************************/ + +static ulg crc_32_tab[256]; +/* note that this fails for NVRAM! */ +/* do assign below in makecrc */ +static ulg crc ; /*= (ulg)0xffffffffL; shift register contents */ +#define CRC_VALUE (crc ^ 0xffffffffL) + +/* + * Code to compute the CRC-32 table. Borrowed from + * gzip-1.0.3/makecrc.c. + */ + +static void +makecrc(void) +{ +/* Not copyrighted 1990 Mark Adler */ + + unsigned long c; /* crc shift register */ + unsigned long e; /* polynomial exclusive-or pattern */ + int i; /* counter for all possible eight bit values */ + int k; /* byte being shifted into crc apparatus */ + + /* terms of polynomial defining this crc (except x^32): */ + const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* move init of the lbits and dbits here, I know this is hokey -- rgm */ + lbits = 9; /* bits in base literal/length lookup table */ + dbits = 6; /* bits in base distance lookup table */ + crc = (ulg)0xffffffffL; /* shift register contents */ + /* Make exclusive-or pattern from polynomial */ + e = 0; + for (i = 0; i < sizeof(p)/sizeof(int); i++) + e |= 1L << (31 - p[i]); + + crc_32_tab[0] = 0; + + for (i = 1; i < 256; i++) + { + c = 0; + for (k = i | 256; k != 1; k >>= 1) + { + c = c & 1 ? (c >> 1) ^ e : c >> 1; + if (k & 1) + c ^= e; + } + crc_32_tab[i] = c; + } +} + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* + * Do the uncompression! + */ +static int gunzip(void) +{ + uch flags; + unsigned char magic[2]; /* magic header */ + char method; + ulg orig_crc = 0; /* original crc */ + ulg orig_len = 0; /* original uncompressed length */ + int res; + + magic[0] = (unsigned char)get_byte(); + magic[1] = (unsigned char)get_byte(); + method = (unsigned char)get_byte(); + + if (magic[0] != 037 || + ((magic[1] != 0213) && (magic[1] != 0236))) { + error("bad gzip magic numbers"); + return -1; + } + + /* We only support method #8, DEFLATED */ + if (method != 8) { + error("internal error, invalid method"); + return -1; + } + + flags = (uch)get_byte(); + if ((flags & ENCRYPTED) != 0) { + error("Input is encrypted\n"); + return -1; + } + if ((flags & CONTINUATION) != 0) { + error("Multi part input\n"); + return -1; + } + if ((flags & RESERVED) != 0) { + error("Input has invalid flags\n"); + return -1; + } + (ulg)get_byte(); /* Get timestamp */ + ((ulg)get_byte()) << 8; + ((ulg)get_byte()) << 16; + ((ulg)get_byte()) << 24; + + (void)get_byte(); /* Ignore extra flags for the moment */ + (void)get_byte(); /* Ignore OS type for the moment */ + + if ((flags & EXTRA_FIELD) != 0) { + unsigned len = (unsigned)get_byte(); + len |= ((unsigned)get_byte())<<8; + while (len--) (void)get_byte(); + } + + /* Get original file name if it was truncated */ + if ((flags & ORIG_NAME) != 0) { + /* Discard the old name */ + while (get_byte() != 0) /* null */ ; + } + + /* Discard file comment if any */ + if ((flags & COMMENT) != 0) { + while (get_byte() != 0) /* null */ ; + } + + /* Decompress */ + if ((res = inflate())) { + switch (res) { + case 0: + break; + case 1: + error("invalid compressed format (err=1)"); + break; + case 2: + error("invalid compressed format (err=2)"); + break; + case 3: + error("out of memory"); + break; + default: + error("invalid compressed format (other)"); + } + return -1; + } + + /* Get the crc and original length */ + /* crc32 (see algorithm.doc) + * uncompressed input size modulo 2^32 + */ + orig_crc = (ulg) get_byte(); + orig_crc |= (ulg) get_byte() << 8; + orig_crc |= (ulg) get_byte() << 16; + orig_crc |= (ulg) get_byte() << 24; + + orig_len = (ulg) get_byte(); + orig_len |= (ulg) get_byte() << 8; + orig_len |= (ulg) get_byte() << 16; + orig_len |= (ulg) get_byte() << 24; + + /* Validate decompression */ + if (orig_crc != CRC_VALUE) { + error("crc error"); + return -1; + } + if (orig_len != bytes_out) { + error("length error"); + return -1; + } + return 0; +} + + diff --git a/src/lib/linuxbiosmain.c b/src/lib/linuxbiosmain.c new file mode 100644 index 0000000000..aac89fa4e9 --- /dev/null +++ b/src/lib/linuxbiosmain.c @@ -0,0 +1,1579 @@ +/* main.c + + Taken from OpenBIOS 0.0.1/boot/boot32/main.c which was in turn taken + from /usr/src/linux/arch/i386/boot/compressed/misc.c + + Used for start32, 1/11/2000 + James Hendricks, Dale Webster */ + + +/* misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * puts by Nick Holloway 1993, better puts by Martin Mares 1995 + * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + */ + +#include "definitions.h" +#include "printk.h" +#include + +extern void intel_post(char value); + +#define DEBUG +#define ERRCHK +#undef TRACEV +#define MALLOCDBG + +#ifdef DEBUG +#define DBG(x...) printk(KERN_DEBUG x) +#else +#define DBG(x...) +#endif + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#undef memset +#undef memcpy +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define K64 (64*1024) +#define WSIZE 0x8000 /* Window size must be at least 32k, and a power of two */ + +uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +unsigned insize; /* valid bytes in inbuf */ +unsigned inptr; /* index of next byte to be processed in inbuf */ +unsigned outcnt; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +extern int fill_inbuf(void); +extern void error(char[]); +extern void displayinit(void); + +typedef void (*kernel) (); +kernel v; + +void malloc_init(unsigned long start, unsigned long end); +void *malloc(int size); + +static void flush_window(void); +static void free(void *where); +static void gzip_mark(void **); +static void gzip_release(void **); + +static long bytes_out; +static uch *output_data; +static unsigned long output_ptr; + +static long free_mem_ptr; /* Unused memory */ +static long free_mem_end_ptr; /* 128k */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +//static int verbose = 1; +/* Diagnostic functions */ +#ifdef ERRCHK +# define Assert(cond,msg) {if(!(cond)) error(msg);} +#else +# define Assert(cond,msg) +#endif + +#ifdef TRACEV +# define Trace(x) printk(KERN_DDEBUG x) +# define Tracev(x) {if (verbose) printk(KERN_DDEBUG x);} +# define Tracevv(x) {if (verbose>1) printk(KERN_DDEBUG x);} +# define Tracec(c,x) {if (verbose && (c)) printk(KERN_DDEBUG x);} +# define Tracecv(c,x) {if (verbose>1 && (c)) printk(KERN_DDEBUG x);} +#else +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +/* make this separately-compilable later. +#include "inflate.c" + */ +#define DEBG(x) +#define DEBGINT(x) +#define DEBG1(x) +#define DEBGH(x) +#define DEBGDYN(x) +/* Taken from /usr/src/linux/lib/inflate.c [unmodified] + Used for start32, 1/11/2000 + James Hendricks, Dale Webster */ + +/* inflate.c -- Not copyrighted 1992 by Mark Adler + version c10p1, 10 January 1993 */ + +/* + * Adapted for booting Linux by Hannu Savolainen 1993 + * based on gzip-1.0.3 + */ + +/* + Inflate deflated (PKZIP's method 8 compressed) data. The compression + method searches for as much of the current string of bytes (up to a + length of 258) in the previous 32 K bytes. If it doesn't find any + matches (of at least length 3), it codes the next byte. Otherwise, it + codes the length of the matched string and its distance backwards from + the current position. There is a single Huffman code that codes both + single bytes (called "literals") and match lengths. A second Huffman + code codes the distance information, which follows a length code. Each + length or distance code actually represents a base value and a number + of "extra" (sometimes zero) bits to get to add to the base value. At + the end of each deflated block is a special end-of-block (EOB) literal/ + length code. The decoding process is basically: get a literal/length + code; if EOB then done; if a literal, emit the decoded byte; if a + length then get the distance and emit the referred-to bytes from the + sliding window of previously emitted data. + + There are (currently) three kinds of inflate blocks: stored, fixed, and + dynamic. The compressor deals with some chunk of data at a time, and + decides which method to use on a chunk-by-chunk basis. A chunk might + typically be 32 K or 64 K. If the chunk is incompressible, then the + "stored" method is used. In this case, the bytes are simply stored as + is, eight bits per byte, with none of the above coding. The bytes are + preceded by a count, since there is no longer an EOB code. + + If the data is compressible, then either the fixed or dynamic methods + are used. In the dynamic method, the compressed data is preceded by + an encoding of the literal/length and distance Huffman codes that are + to be used to decode this block. The representation is itself Huffman + coded, and so is preceded by a description of that code. These code + descriptions take up a little space, and so for small blocks, there is + a predefined set of codes, called the fixed codes. The fixed method is + used if the block codes up smaller that way (usually for quite small + chunks), otherwise the dynamic method is used. In the latter case, the + codes are customized to the probabilities in the current block, and so + can code it much better than the pre-determined fixed codes. + + The Huffman codes themselves are decoded using a multi-level table + lookup, in order to maximize the speed of decoding plus the speed of + building the decoding tables. See the comments below that precede the + lbits and dbits tuning parameters. + */ + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarly, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + +#ifdef RCSID +static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #"; +#endif + +#ifndef STATIC + +#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H) +# include +# include +#endif + + +#include "gzip.h" +#define STATIC +#endif /* !STATIC */ + +#define slide window + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). + Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 + means that v is a literal, 16 < e < 32 means that v is a pointer to + the next table, which codes e - 16 bits, and lastly e == 99 indicates + an unused code. If a code with e == 99 is looked up, this implies an + error in the data. */ +struct huft { + uch e; /* number of extra bits or operation */ + uch b; /* number of bits in this code or subcode */ + union { + ush n; /* literal, length base, or distance base */ + struct huft *t; /* pointer to next level of table */ + } v; +}; + + +/* Function prototypes */ +STATIC int huft_build OF((unsigned *, unsigned, unsigned, const ush *, + const ush *, struct huft **, int *)); +STATIC int huft_free OF((struct huft *)); +STATIC int inflate_codes OF((struct huft *, struct huft *, int, int)); +STATIC int inflate_stored OF((void)); +STATIC int inflate_fixed OF((void)); +STATIC int inflate_dynamic OF((void)); +STATIC int inflate_block OF((int *)); +STATIC int inflate OF((void)); + + +/* The inflate algorithm uses a sliding 32 K byte window on the uncompressed + stream to find repeated byte strings. This is implemented here as a + circular buffer. The index is updated simply by incrementing and then + ANDing with 0x7fff (32K-1). */ +/* It is left to other modules to supply the 32 K area. It is assumed + to be usable as if it were declared "uch slide[32768];" or as just + "uch *slide;" and then malloc'ed in the latter case. The definition + must be in unzip.h, included above. */ +/* unsigned wp; current position in slide */ +#define wp outcnt +#define flush_output(w) (wp=(w),flush_window()) + +/* Tables for deflate from PKZIP's appnote.txt. */ +const unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +const ush cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ +const ush cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ +const ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +const ush cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + + +/* Macros for inflate() bit peeking and grabbing. + The usage is: + + NEEDBITS(j) + x = b & mask_bits[j]; + DUMPBITS(j) + + where NEEDBITS makes sure that b has at least j bits in it, and + DUMPBITS removes the bits from b. The macros use the variable k + for the number of bits in b. Normally, b and k are register + variables for speed, and are initialized at the beginning of a + routine that uses these macros from a global bit buffer and count. + + If we assume that EOB will be the longest code, then we will never + ask for bits with NEEDBITS that are beyond the end of the stream. + So, NEEDBITS should not read any more bytes than are needed to + meet the request. Then no bytes need to be "returned" to the buffer + at the end of the last block. + + However, this assumption is not true for fixed blocks--the EOB code + is 7 bits, but the other literal/length codes can be 8 or 9 bits. + (The EOB code is shorter than other codes because fixed blocks are + generally short. So, while a block always has an EOB, many other + literal/length codes have a significantly lower probability of + showing up at all.) However, by making the first table have a + lookup of seven bits, the EOB code will be found in that first + lookup, and so will not require that too many bits be pulled from + the stream. + */ + +STATIC ulg bb; /* bit buffer */ +STATIC unsigned bk; /* bits in bit buffer */ + +const ush mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +#define NEXTBYTE() (uch)get_byte() +#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<>=(n);k-=(n);} + + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +STATIC int lbits ; /* bits in base literal/length lookup table */ +STATIC int dbits ; /* bits in base distance lookup table */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + + +STATIC unsigned hufts; /* track memory usage */ + + +STATIC int huft_build( + unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ + unsigned n, /* number of codes (assumed <= N_MAX) */ + unsigned s, /* number of simple-valued codes (0..s-1) */ + const ush *d, /* list of base values for non-simple codes */ + const ush *e, /* list of extra bits for non-simple codes */ + struct huft **t, /* result: starting table */ + int *m) /* maximum lookup bits, returns actual */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. */ +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX+1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX+1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + +DEBGH("huft1 "); + + /* Generate counts for each bit length */ + memzero(c, sizeof(c)); + p = b; i = n; + do { + Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), + n-i, *p)); + c[*p]++; /* assume all entries <= BMAX */ + p++; /* Can't combine with above line (Solaris bug) */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = 0; + *m = 0; + return 0; + } + +DEBGH("huft2 "); + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned)l > i) + l = i; + *m = l; + +DEBGH("huft3 "); + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + +DEBGH("huft4 "); + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + +DEBGH("huft5 "); + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + +DEBGH("h6 "); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = 0; /* just to keep compilers happy */ + q = (struct huft *)0; /* ditto */ + z = 0; /* ditto */ +DEBGH("h6a "); + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { +DEBGH("h6b "); + a = c[k]; + while (a--) + { +DEBGH("h6b1 "); + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { +DEBG1("1 "); + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ +DEBG1("2 "); + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } +DEBG1("3 "); + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) == 0) + { + if (h) + huft_free(u[0]); + return 3; /* not enough memory */ + } +DEBG1("4 "); + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = 0; + u[h] = ++q; /* table starts after link */ + +DEBG1("5 "); + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch)l; /* bits to dump before this table */ + r.e = (uch)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } +DEBG1("6 "); + } +DEBGH("h6c "); + + /* set up table entry in r */ + r.b = (uch)(k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (ush)(*p); /* simple code is just the value */ + p++; /* one compiler does not like *p++ */ + } + else + { + r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } +DEBGH("h6d "); + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } +DEBGH("h6e "); + } +DEBGH("h6f "); + } + +DEBGH("huft7 "); + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + + + +STATIC int huft_free( +struct huft *t) /* table to free */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register struct huft *p, *q; + + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != 0) + { + q = (--p)->v.t; + free((char*)p); + p = q; + } + return 0; +} + + +STATIC int inflate_codes( + struct huft *tl, + struct huft *td, /* literal/length and distance decoder tables */ + int bl, + int bd) /* number of bits decoded by tl[] and td[] */ +/* inflate (decompress) the codes in a deflated (compressed) block. + Return an error code or zero if it all goes ok. */ +{ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + for (;;) /* do until end of block */ + { + NEEDBITS((unsigned)bl) + if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + if (e == 16) /* then it's a literal */ + { +/* + DEBG("l"); + */ + slide[w++] = (uch)t->v.n; + Tracevv((stderr, "%c", slide[w-1])); + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if (e == 15) + break; + + /* get length of block to copy */ + NEEDBITS(e) + n = t->v.n + ((unsigned)b & mask_bits[e]); + DUMPBITS(e); + + /* decode distance of block to copy */ + NEEDBITS((unsigned)bd) + if ((e = (t = td + ((unsigned)b & md))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + NEEDBITS(e) + d = w - t->v.n - ((unsigned)b & mask_bits[e]); + DUMPBITS(e) + Tracevv((stderr,"\\[%d,%d]", w-d, n)); +/* + DEBG("D");printint(w-d);printint(n); + */ + + /* do the copy */ + do { + n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); +#if 0 + DEBG("memcpy %d to %d size %d"); printint(d); printint(w); + printint(e); + DEBG("\n"); +#endif +#if !defined(NOMEMCPY) && !defined(DEBUG) + if (w - d >= e) /* (this test assumes unsigned comparison) */ + { + memcpy(slide + w, slide + d, e); + w += e; + d += e; + } + else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + slide[w++] = slide[d++]; + Tracevv((stderr, "%c", slide[w-1])); + } while (--e); + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } while (n); + } + } + + + /* restore the globals from the locals */ + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + /* done */ + return 0; +} + + + +STATIC int inflate_stored(void) +/* "decompress" an inflated type 0 (stored) block. */ +{ + unsigned n; /* number of bytes in block */ + unsigned w; /* current window position */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + +DEBG(""); + return 0; +} + + + +STATIC int inflate_fixed(void) +/* decompress an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ +{ + int i; /* temporary variable */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned l[288]; /* length list for huft_build */ + +DEBG(" 1) + { + huft_free(tl); + + DEBG(">"); + return i; + } + + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; +} + + + +STATIC int inflate_dynamic(void) +/* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ +#ifdef PKZIP_BUG_WORKAROUND + unsigned ll[288+32]; /* literal/length and distance code lengths */ +#else + unsigned ll[286+30]; /* literal/length and distance code lengths */ +#endif + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + +#if 0 + for(i = 0; i < 288+32; i++) + if (ll[i]) { + display("non-zero ll index at "); + printint(i); + } +#endif +DEBG(" 288 || nd > 32) +#else + if (nl > 286 || nd > 30) +#endif + return 1; /* bad lengths */ +DEBGINT(nl); DEBGINT(nd); DEBGINT(nb); +DEBGDYN("dyn1 "); + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS(3) + ll[border[j]] = (unsigned)b & 7; + DUMPBITS(3) + } + for (; j < 19; j++) + ll[border[j]] = 0; + + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build(ll, 19, 19, 0, 0, &tl, &bl)) != 0) + { + if (i == 1) + huft_free(tl); + return i; /* incomplete code set */ + } + +DEBGDYN("dyn3 freemem now "); DEBGINT(free_mem_ptr); + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned)i < n) + { + NEEDBITS((unsigned)bl) + j = (td = tl + ((unsigned)b & m))->b; + DUMPBITS(j) + j = td->v.n; +/* + DEBGDYN("j is now"); DEBGINT(j); + */ + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS(2) + j = 3 + ((unsigned)b & 3); + DUMPBITS(2) +/* + DEBGDYN("j second is now"); DEBGINT(j); + */ + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS(3) + j = 3 + ((unsigned)b & 7); + DUMPBITS(3) +/* + DEBGDYN("j three is now"); DEBGINT(j); + */ + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS(7) + j = 11 + ((unsigned)b & 0x7f); + DUMPBITS(7) +/* + DEBGDYN("j four is now"); DEBGINT(j); + */ + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + } + +DEBGDYN("dyn4 "); + + /* free decoding table for trees */ + huft_free(tl); + +DEBGDYN("dyn5 free mem is now");DEBGINT(free_mem_ptr); + + /* restore the global bit buffer */ + bb = b; + bk = k; + +DEBGDYN("dyn5a "); + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) + { +DEBGDYN("dyn5b "); + if (i == 1) { + error(" incomplete literal tree\n"); + huft_free(tl); + } + return i; /* incomplete code set */ + } +DEBGDYN("dyn5c "); + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) + { +DEBGDYN("dyn5d "); + if (i == 1) { + error(" incomplete distance tree\n"); +#ifdef PKZIP_BUG_WORKAROUND + i = 0; + } +#else + huft_free(td); + } + huft_free(tl); + return i; /* incomplete code set */ +#endif + } + +DEBGDYN("dyn6 free_mem_ptr ");DEBGINT(free_mem_ptr); + + /* decompress until an end-of-block code */ +DEBG("inflate_codes inptr is "); DEBGINT(inptr); + if (inflate_codes(tl, td, bl, bd)) + return 1; + +DEBG("AFTER inflate_codes inptr is "); DEBGINT(inptr); +DEBGDYN("dyn7 "); + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + + DEBG(">"); + return 0; +} + + + +STATIC int inflate_block( +int *e) /* last block flag */ +/* decompress an inflated block */ +{ + unsigned t; /* block type */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + DEBG(""); + + /* bad block type */ + return 2; +} + + + +STATIC int inflate(void) +/* decompress an inflated entry */ +{ + int e; /* last block flag */ + int r; /* result code */ + unsigned h; /* maximum struct huft's malloc'ed */ + void *ptr; + + /* initialize window, bit buffer */ + wp = 0; + bk = 0; + bb = 0; + + + /* decompress until the last block */ + h = 0; + do { + hufts = 0; + gzip_mark(&ptr); + if ((r = inflate_block(&e)) != 0) { + gzip_release(&ptr); + return r; + } + gzip_release(&ptr); + if (hufts > h) + h = hufts; + } while (!e); + + /* Undo too much lookahead. The next read will be byte aligned so we + * can discard unused bits in the last meaningful byte. + */ + while (bk >= 8) { + bk -= 8; + inptr--; + } + + /* flush out slide */ + flush_output(wp); + + + /* return success */ + DBG("<%u> ", h); + return 0; +} + +/********************************************************************** + * + * The following are support routines for inflate.c + * + **********************************************************************/ + +static ulg crc_32_tab[256]; +/* note that this fails for NVRAM! */ +/* do assign below in makecrc */ +static ulg crc ; /*= (ulg)0xffffffffL; shift register contents */ +#define CRC_VALUE (crc ^ 0xffffffffL) + +/* + * Code to compute the CRC-32 table. Borrowed from + * gzip-1.0.3/makecrc.c. + */ + +static void +makecrc(void) +{ +/* Not copyrighted 1990 Mark Adler */ + + unsigned long c; /* crc shift register */ + unsigned long e; /* polynomial exclusive-or pattern */ + int i; /* counter for all possible eight bit values */ + int k; /* byte being shifted into crc apparatus */ + + /* terms of polynomial defining this crc (except x^32): */ + const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* move init of the lbits and dbits here, I know this is hokey -- rgm */ + lbits = 9; /* bits in base literal/length lookup table */ + dbits = 6; /* bits in base distance lookup table */ + crc = (ulg)0xffffffffL; /* shift register contents */ + /* Make exclusive-or pattern from polynomial */ + e = 0; + for (i = 0; i < sizeof(p)/sizeof(int); i++) + e |= 1L << (31 - p[i]); + + crc_32_tab[0] = 0; + + for (i = 1; i < 256; i++) + { + c = 0; + for (k = i | 256; k != 1; k >>= 1) + { + c = c & 1 ? (c >> 1) ^ e : c >> 1; + if (k & 1) + c ^= e; + } + crc_32_tab[i] = c; + } +} + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* + * Do the uncompression! + */ +static int gunzip(void) +{ + uch flags; + unsigned char magic[2]; /* magic header */ + char method; + ulg orig_crc = 0; /* original crc */ + ulg orig_len = 0; /* original uncompressed length */ + int res; + + magic[0] = (unsigned char)get_byte(); + magic[1] = (unsigned char)get_byte(); + method = (unsigned char)get_byte(); + + if (magic[0] != 037 || + ((magic[1] != 0213) && (magic[1] != 0236))) { + error("bad gzip magic numbers"); + return -1; + } + + /* We only support method #8, DEFLATED */ + if (method != 8) { + error("internal error, invalid method"); + return -1; + } + + flags = (uch)get_byte(); + if ((flags & ENCRYPTED) != 0) { + error("Input is encrypted\n"); + return -1; + } + if ((flags & CONTINUATION) != 0) { + error("Multi part input\n"); + return -1; + } + if ((flags & RESERVED) != 0) { + error("Input has invalid flags\n"); + return -1; + } + (ulg)get_byte(); /* Get timestamp */ + ((ulg)get_byte()) << 8; + ((ulg)get_byte()) << 16; + ((ulg)get_byte()) << 24; + + (void)get_byte(); /* Ignore extra flags for the moment */ + (void)get_byte(); /* Ignore OS type for the moment */ + + if ((flags & EXTRA_FIELD) != 0) { + unsigned len = (unsigned)get_byte(); + len |= ((unsigned)get_byte())<<8; + while (len--) (void)get_byte(); + } + + /* Get original file name if it was truncated */ + if ((flags & ORIG_NAME) != 0) { + /* Discard the old name */ + while (get_byte() != 0) /* null */ ; + } + + /* Discard file comment if any */ + if ((flags & COMMENT) != 0) { + while (get_byte() != 0) /* null */ ; + } + + /* Decompress */ + if ((res = inflate())) { + switch (res) { + case 0: + break; + case 1: + error("invalid compressed format (err=1)"); + break; + case 2: + error("invalid compressed format (err=2)"); + break; + case 3: + error("out of memory"); + break; + default: + error("invalid compressed format (other)"); + } + return -1; + } + + /* Get the crc and original length */ + /* crc32 (see algorithm.doc) + * uncompressed input size modulo 2^32 + */ + orig_crc = (ulg) get_byte(); + orig_crc |= (ulg) get_byte() << 8; + orig_crc |= (ulg) get_byte() << 16; + orig_crc |= (ulg) get_byte() << 24; + + orig_len = (ulg) get_byte(); + orig_len |= (ulg) get_byte() << 8; + orig_len |= (ulg) get_byte() << 16; + orig_len |= (ulg) get_byte() << 24; + + /* Validate decompression */ + if (orig_crc != CRC_VALUE) { + error("crc error"); + return -1; + } + if (orig_len != bytes_out) { + error("length error"); + return -1; + } + return 0; +} + + + +void malloc_init(unsigned long start, unsigned long end) +{ + free_mem_ptr = start; + free_mem_end_ptr = end; +} + +void *malloc(int size) +{ + void *p; + + if (size < 0) + error("Error! malloc: Size < 0"); + if (free_mem_ptr <= 0) + error("Error! malloc: Free_mem_ptr <= 0"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *) free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("Error! malloc: Free_mem_ptr >= free_mem_end_ptr"); + + MALLOCDBG("malloc 0x%08x\n", (unsigned int)p); + + return p; +} + +static void free(void *where) +{ + /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; + DBG("gzip_mark 0x%08x\n", (unsigned int)free_mem_ptr); +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; + DBG("gzip_release 0x%08x\n", (unsigned int)free_mem_ptr); +} + +void *memset(void *s, int c, size_t n) +{ + int i; + char *ss = (char *) s; + + for (i = 0; i < n; i++) + ss[i] = c; + + return s; +} + +void *memcpy(void *__dest, __const void *__src, size_t __n) +{ + int i; + char *d = (char *) __dest, *s = (char *) __src; + + for (i = 0; i < __n; i++) + d[i] = s[i]; + + return __dest; +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window() +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, *out, ch; + + in = window; + out = &output_data[output_ptr]; + DBG("flush 0x%08x count 0x%08x\n", (unsigned long) out, outcnt); + + for (n = 0; n < outcnt; n++) { + ch = *out++ = *in++; + c = crc_32_tab[((int) c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg) outcnt; + output_ptr += (ulg) outcnt; + outcnt = 0; +} + +void setup_output_buffer() +{ + output_data = (char *) KERNEL_START; + DBG("output data is 0x%08x\n", (unsigned long) output_data); +} + +/* TODO: this must move to chip/intel */ +/* we have to do more than we thought. I assumed Linux would do all the + * interesting parts, and I was wrong. + */ +struct ioapicreg { + unsigned int reg; + unsigned int value; +}; + +struct ioapicreg ioapicregvalues[] = { + {0x10, 0x10000}, {0x11, 0x0}, + {0x12, 0x959}, {0x13, 0xff000000}, + {0x14, 0x951}, {0x15, 0xff000000}, + {0x16, 0x961}, {0x17, 0x0}, + {0x18, 0x969}, {0x19, 0xff000000}, + {0x1a, 0x971}, {0x1b, 0x0}, + {0x1c, 0x979}, {0x1d, 0x0}, + {0x1e, 0x981}, {0x1f, 0x0}, + {0x20, 0x989}, {0x21, 0xff000000}, + {0x22, 0x10000}, {0x23, 0x0}, + {0x24, 0x10000}, {0x25, 0x0}, + {0x26, 0x10000}, {0x27, 0x0}, + {0x28, 0x991}, {0x29, 0xff000000}, + {0x2a, 0x10000}, {0x2b, 0x0}, + {0x2c, 0x999}, {0x2d, 0x0}, + {0x2e, 0x9a1}, {0x2f, 0x0}, + {0x30, 0x10000}, {0x31, 0x0}, + {0x32, 0x10000}, {0x33, 0x0}, + {0x34, 0x10000}, {0x35, 0x0}, + {0x36, 0xa9a9}, {0x37, 0xff000000}, + {0x38, 0x10000}, {0x39, 0x0}, + {0x3a, 0xa9b1}, {0x3b, 0xff000000}, + {0x3c, 0x10000}, {0x3d, 0x0}, + {0x3e, 0x10000}, {0x3f, 0x0} +}; + +void setup_apic() +{ + int i; + unsigned long l1; + unsigned long nvram = 0xfec00000; + volatile unsigned long *l; + struct ioapicreg *a = ioapicregvalues; + + l = (unsigned long *) nvram; + for (i = 0; i < sizeof(ioapicregvalues) / sizeof(ioapicregvalues[0]); + i++, a++) { + *l = a->reg; + l[4] = a->value; + l1 = l[4]; + if ((i==0) && (l1 == 0xffffffff)) { + DBG("IO APIC not responding.\n"); + return; + } + DBG("for IRQ, reg 0x%08x value 0x%08x\n", a->reg, l1); + } +} + +int +linuxbiosmain(unsigned long base, unsigned long totalram) +{ + unsigned char *empty_zero_page; + extern int firstfill; + + /* common globals -- don't rely on init! */ + insize = 0; + inptr = 0; + firstfill = 1; + outcnt = 0; + bytes_out = 0; + output_ptr = 0; + + printk("Welcome to start32, the open sourced starter.\n"); + printk("This space will eventually hold more diagnostic information.\n"); + printk("\n"); + printk("January 2000, James Hendricks, Dale Webster, and Ron Minnich.\n"); + printk("Version 0.1\n"); + printk("\n"); + + setup_output_buffer(); + + DBG("Making CRC\n"); + makecrc(); + intel_post(0xf1); + + DBG("Gunzipping boot code\n"); + if (gunzip() != 0) { + printk("gunzip failed\n"); + intel_post(0xff); + return 0; + } + intel_post(0xf8); + + /* parameter passing to linux. You have to get the pointer to the + * empty_zero_page, then fill it in. + */ + /* should we do this in intel_main(). If we did we would have to save it + * maybe -- 0x90000 might get stomped. We do it here as the last step. + */ + /* yes I know we need prototypes -- we'll do it soon */ + empty_zero_page = get_empty_zero_page(); + init_params(empty_zero_page); + intel_post(0xf9); + + /* the ram address should be the last mbyte, AFAIK. Subtract one for the + * low 1 MB. So subtract 2K total + */ + set_memory_size(empty_zero_page, 0x3c00, totalram - 2048); + intel_post(0xfa); +#ifdef CMD_LINE + DBG("using custom command line - [%s]\n", CMD_LINE); +#else +#define CMD_LINE "root=/dev/hda1 single" + DBG("using default command line - [%s]\n", CMD_LINE); +#endif + + set_command_line(empty_zero_page, CMD_LINE); + set_root_rdonly(empty_zero_page); + set_display(empty_zero_page, 25, 80); + + /* set up the IO-APIC for the clock interrupt. */ + /* this needs to move to intel_main.c at some point. */ + setup_apic(); + intel_post(0xfc); + + DBG("Jumping to boot code\n"); + intel_post(0xfe); + + /* there seems to be a bug in gas? it's generating wrong bit-patterns ... + v = (kernel)KERNEL_START; + v(); + */ + /* move 0x90000 to into esi (This is the address of the linux parameter page) + * Linux then copies this page into it's ``empty_zero_page'' so it isn't + * stomped while things are being setup. + * Later the ``empty_zero_page'' is zeroed and used fulfill read demands + * on memory mappings of file holes and the like. + * As of 2.4.0-test4 the linux parameter page isn't hardwired to be + * at 0x90000 anymore. + */ + /* move 0 to ebx. This is for SMP support. Jump to kernel */ + __asm__ __volatile__("movl $0x90000, %%esi\n\t" + "movl $0, %%ebx\n\t" + "ljmp $0x10, %0\n\t" + :: "i" (0x100000)); + + return 0; /* It should not ever return */ +} diff --git a/src/lib/linuxpci.c b/src/lib/linuxpci.c new file mode 100644 index 0000000000..3c9828a77b --- /dev/null +++ b/src/lib/linuxpci.c @@ -0,0 +1,478 @@ +/* + * $Id$ + * + * PCI Bus Services, see include/linux/pci.h for further explanation. + * + * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, + * David Mosberger-Tang + * + * Copyright 1997 -- 1999 Martin Mares + */ + +/* the intent of this file is to easily copy any new pci.c from the + * linux source tree, so keep your mods to a minimum, please + * RGM + */ +#include +#include + +extern void intel_post(unsigned char value); +#define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(KERN_DEBUG x) +#else +#define DBG(x...) +#endif + +/** + * This is the root of the PCI tree. A PCI tree always has + * one bus, bus 0. Bus 0 contains devices and bridges. + */ +struct pci_bus pci_root; +/// Linked list of PCI devices. ALL devices are on this list +struct pci_dev *pci_devices = 0; +/// pointer to the last device */ +static struct pci_dev **pci_last_dev_p = &pci_devices; +/// We're going to probably delete this -- flag to add in reverse order */ +static int pci_reverse = 0; + +/** + * Given a bus and a devfn number, find the device structure + * @param bus The bus number + * @param devfn a device/function number + * @return pointer to the device structure + */ +struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) +{ + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) + if (dev->bus->number == bus && dev->devfn == devfn) + break; + return dev; +} + +/** Find a device of a given vendor and type + * @param vendor Vendor ID (e.g. 0x8086 for Intel) + * @param device Device ID + * @param from Pointer to the device structure, used as a starting point + * in the linked list of devices, which can be 0 to start at the + * head of the list (i.e. pci_devices) + * @return Pointer to the device struct + */ +struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, struct pci_dev *from) +{ + if (!from) + from = pci_devices; + else + from = from->next; + while (from && (from->vendor != vendor || from->device != device)) + from = from->next; + return from; +} + +/** Find a device of a given class + * @param class Class of the device + * @param from Pointer to the device structure, used as a starting point + * in the linked list of devices, which can be 0 to start at the + * head of the list (i.e. pci_devices) + * @return Pointer to the device struct + */ +struct pci_dev *pci_find_class(unsigned int class, struct pci_dev *from) +{ + if (!from) + from = pci_devices; + else + from = from->next; + while (from && from->class != class) + from = from->next; + return from; +} + +/** Given a device, set the PCI_COMMAND_MASTER bit in the command register + * @param dev Pointer to the device structure + */ +void pci_set_master(struct pci_dev *dev) +{ + u16 cmd; + u8 lat; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_MASTER)) { + printk("PCI: Enabling bus mastering for device %02x:%02x\n", + dev->bus->number, dev->devfn); + cmd |= PCI_COMMAND_MASTER; + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + if (lat < 16) { + printk("PCI: Increasing latency timer of device %02x:%02x to 64\n", + dev->bus->number, dev->devfn); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); + } +} + +/** Given a device and register, read the size of the BAR for that register. + * @param dev Pointer to the device structure + * @param reg Which register to use + * @param addr Address to load into the register after size is found + */ +void pci_get_size(struct pci_dev *dev, unsigned long reg, unsigned long addr) +{ + u32 size; + unsigned long type; + + /* FIXME: more consideration for 64-bit PCI devices */ + // get the size + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), ~0); + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &size); + + // restore addr + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), addr); + + // Now compute the actual size, See PCI Spec 6.2.5.1 ... + if (size & PCI_BASE_ADDRESS_SPACE_IO) { + type = size & (~PCI_BASE_ADDRESS_IO_MASK); + size &= (PCI_BASE_ADDRESS_IO_MASK); + // BUG! Top 16 bits can be zero (or not) + // So set them to 0xffff so they go away ... + size |= 0xffff0000; + size = ~size; + size++; + } else { + type = size & (~PCI_BASE_ADDRESS_MEM_MASK); + size &= (PCI_BASE_ADDRESS_MEM_MASK); + size = ~size; + size++; + } + dev->size[reg] = size | type; +} + +/** Read the base address registers for a given device. + * @param dev Pointer to the dev structure + * @param howmany How many registers to read (6 for device, 2 for bridge) + */ +void pci_read_bases(struct pci_dev *dev, unsigned int howmany) +{ + unsigned int reg; + u32 /* unsigned long for 64 bits ?? */ addr; + + /* FIXME: to deal with 64-bits PCI */ + for (reg = 0; reg < howmany; reg++) { + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &addr); + if (addr == 0xffffffff) + continue; + + /* get address space size */ + pci_get_size(dev, reg, addr); + + addr &= (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK); + if (addr == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { + /* this is a 64-bit memory base address */ + reg++; + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &addr); + if (addr) { +#if BITS_PER_LONG == 64 + dev->base_address[reg - 1] |= ((unsigned long) addr) << 32; +#else + printk("PCI: Unable to handle 64-bit address for device " + "%02x:%02x\n", dev->bus->number, dev->devfn); + dev->base_address[reg - 1] = 0; +#endif + } + } + } +} + +/** Scan the bus, first for bridges and next for devices. + * @param pci_bus pointer to the bus structure + * @return The maximum bus number found, after scanning all subordinate busses + */ +unsigned int pci_scan_bus(struct pci_bus *bus) +{ + unsigned int devfn, max; + struct pci_dev *dev, **bus_last; + struct pci_bus *child; + + DBG("PCI: pci_scan_bus for bus %d\n", bus->number); + + bus_last = &bus->devices; + max = bus->secondary; + + intel_post(0x24); + + /* probe all devices on this bus with some optimization for non-existance and + single funcion devices */ + for (devfn = 0; devfn < 0xff; devfn++) { + u32 id, class, addr; + u8 cmd, tmp, hdr_type; + + if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &id)) + continue; + + /* some broken boards return 0 if a slot is empty: */ + if (id == 0xffffffff || id == 0x00000000 || id == 0x0000ffff || id == 0xffff0000) { + if (PCI_FUNC(devfn) == 0x00) { + /* if this is a function 0 device and it is not present, + skip to next device */ + devfn += 0x07; + } + /* multi function device, skip to next function */ + continue; + } + + if (pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type)) + continue; + + if (pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &class)) + continue; + + if ((dev = kmalloc(sizeof(*dev), GFP_ATOMIC)) == NULL) { + printk("PCI: out of memory.\n"); + continue; + } + + memset(dev, 0, sizeof(*dev)); + dev->bus = bus; + dev->devfn = devfn; + dev->vendor = id & 0xffff; + dev->device = (id >> 16) & 0xffff; + dev->hdr_type = hdr_type; + /* class code, the upper 3 bytes of PCI_CLASS_REVISION */ + dev->class = class >> 8; + class >>= 16; + + /* non-destructively determine if device can be a master: */ + pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &cmd); + pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, + cmd | PCI_COMMAND_MASTER); + pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &tmp); + dev->master = ((tmp & PCI_COMMAND_MASTER) != 0); + pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd); + + switch (hdr_type & 0x7f) { /* header type */ + case PCI_HEADER_TYPE_NORMAL: /* standard header */ + if (class == PCI_CLASS_BRIDGE_PCI) + goto bad; + /* read base address registers, again pci_fixup() can tweak these */ + pci_read_bases(dev, 6); + pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &addr); + dev->rom_address = (addr == 0xffffffff) ? 0 : addr; + break; + case PCI_HEADER_TYPE_BRIDGE: /* bridge header */ + if (class != PCI_CLASS_BRIDGE_PCI) + goto bad; + pci_read_bases(dev, 2); + pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &addr); + dev->rom_address = (addr == 0xffffffff) ? 0 : addr; + break; + case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ + if (class != PCI_CLASS_BRIDGE_CARDBUS) + goto bad; + pci_read_bases(dev, 1); + break; + default: /* unknown header */ + bad: + printk("PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, " + "ignoring.\n", + bus->number, dev->devfn, dev->vendor, dev->device, class, + hdr_type); + continue; + } + + DBG("PCI: %02x:%02x [%04x/%04x]\n", bus->number, dev->devfn, + dev->vendor, dev->device); + + /* Put it into the global PCI device chain. It's used to find devices once + everything is set up. */ + if (!pci_reverse) { + *pci_last_dev_p = dev; + pci_last_dev_p = &dev->next; + } else { + dev->next = pci_devices; + pci_devices = dev; + } + + /* Now insert it into the list of devices held by the parent bus. */ + *bus_last = dev; + bus_last = &dev->sibling; + + if (PCI_FUNC(devfn) == 0x00 && (hdr_type & 0x80) != 0x80) { + /* if this is not a multi function device, don't waste time probe + another function. Skip to next device. */ + devfn += 0x07; + } + } + + intel_post(0x25); + /* + * After performing arch-dependent fixup of the bus, look behind + * all PCI-to-PCI bridges on this bus. + */ + //pcibios_fixup_bus(bus); + /* + * The fixup code may have just found some peer pci bridges on this + * machine. Update the max variable if that happened so we don't + * get duplicate bus numbers. + */ + for (child = &pci_root; child; child = child->next) + max = ((max > child->subordinate) ? max : child->subordinate); + + for (dev = bus->devices; dev; dev = dev->sibling) + /* If it's a bridge, scan the bus behind it. */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + unsigned int buses; + unsigned int devfn = dev->devfn; + unsigned short cr; +#define NOTUSED +#ifdef NOTUSED + /* + * Check for a duplicate bus. If we already scanned + * this bus number as a peer bus, don't also scan it + * as a child bus + */ + if (((dev->vendor == PCI_VENDOR_ID_RCC) && + ((dev->device == PCI_DEVICE_ID_RCC_HE) || + (dev->device == PCI_DEVICE_ID_RCC_LE))) || + ((dev->vendor == PCI_VENDOR_ID_COMPAQ) && + (dev->device == PCI_DEVICE_ID_COMPAQ_6010)) || + ((dev->vendor == PCI_VENDOR_ID_INTEL) && + ((dev->device == PCI_DEVICE_ID_INTEL_82454NX)|| + (dev->device == PCI_DEVICE_ID_INTEL_82451NX)))) + goto skip_it; + + /* Read the existing primary/secondary/subordinate bus number + configuration to determine if the PCI bridge has already been + configured by the system. If so, check to see if we've already + scanned this bus as a result of peer bus scanning, if so, skip this. + FIMXE: We are BIOS, is there anyone else doing this dirty job BEFORE us ?? */ + pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses); + if ((buses & 0xFFFFFF) != 0) { + for (child = pci_root.next; child; child = child->next) + if (child->number == ((buses >> 8) & 0xff)) + goto skip_it; + } +#endif + /* Insert it into the tree of buses. */ + if ((child = kmalloc(sizeof(*child), GFP_ATOMIC)) == NULL) { + printk("PCI: out of memory for bridge.\n"); + continue; + } + memset(child, 0, sizeof(*child)); + child->next = bus->children; + bus->children = child; + child->self = dev; + child->parent = bus; + + /* Set up the primary, secondary and subordinate bus numbers. We have + no idea how many buses are behind this bridge yet, so we set the + subordinate bus number to 0xff for the moment */ + child->number = child->secondary = ++max; + child->primary = bus->secondary; + child->subordinate = 0xff; + + /* Clear all status bits and turn off memory, I/O and master enables. */ + pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr); + pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000); + pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff); + + /* + * Read the existing primary/secondary/subordinate bus + * number configuration to determine if the PCI bridge + * has already been configured by the system. If so, + * do not modify the configuration, merely note it. + */ + pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses); + +#ifdef BRIDGE_CONFIGURED_AT_POWERUP + // There is some hardware (ALPHA) that configures bridges in hardware, at bootup. + // We need to take that into account at some point. + // At the same time, we're finding buggy bridge hardware that comes up + // with these registers non-zero (VIA VT8601). Hence this #ifdef -- in some cases, + // you should never check the buses; in other cases, you have no choice. + if ((buses & 0xFFFFFF) != 0) { + unsigned int cmax; + + child->primary = buses & 0xFF; + child->secondary = (buses >> 8) & 0xFF; + child->subordinate = (buses >> 16) & 0xFF; + child->number = child->secondary; + cmax = pci_scan_bus(child); + if (cmax > max) + max = cmax; + } else +#endif + { + /* Configure the bus numbers for this bridge: the configuration + transactions will not be propagated by the bridge if it is not + correctly configured */ + buses &= 0xff000000; + buses |= (((unsigned int) (child->primary) << 0) | + ((unsigned int) (child->secondary) << 8) | + ((unsigned int) (child->subordinate) << 16)); + pcibios_write_config_dword(bus->number, devfn, + PCI_PRIMARY_BUS, buses); + + /* Now we can scan all subordinate buses i.e. the bus hehind the bridge */ + max = pci_scan_bus(child); + + /* We know the number of buses behind this bridge. Set the subordinate + bus number to its real value */ + child->subordinate = max; + buses = (buses & 0xff00ffff) | + ((unsigned int) (child->subordinate) << 16); + pcibios_write_config_dword(bus->number, devfn, + PCI_PRIMARY_BUS, buses); + } + + pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr); + skip_it: + } + /* + * We've scanned the bus and so we know all about what's on + * the other side of any bridges that may be on this bus plus + * any devices. + * + * Return how far we've got finding sub-buses. + */ + DBG("PCI: pci_scan_bus returning with max=%02x\n", max); + intel_post(0x55); + return max; +} + +/** Scan a peer bridge. + * First, scan all the bus structs for this bus number. If this bus + * is found, that means it was configured, so just return the pointer. + * If the bus is not found, it needs to be configured. Allocate memory + * for the struct, link it in to the linked list of bridges, and then + * scan it. + * @param bus The bus number supported by the peer bridge + * @return Pointer to the bus struct for this bus number. +struct pci_bus *pci_scan_peer_bridge(int bus) +{ + struct pci_bus *b; + + b = &pci_root; + while ((b != NULL) && (bus != 0)) { + if (b->number == bus) + return (b); + b = b->next; + } + b = kmalloc(sizeof(*b), GFP_KERNEL); + memset(b, 0, sizeof(*b)); + b->next = pci_root.next; + pci_root.next = b; + b->number = b->secondary = bus; + b->subordinate = pci_scan_bus(b); + return b; +} + +/** Initialize pci root struct, then scan starting at the root. + * Note that this function will recurse at each bridge. + */ +void pci_init(void) +{ + memset(&pci_root, 0, sizeof(pci_root)); + pci_root.subordinate = pci_scan_bus(&pci_root); +} diff --git a/src/lib/newpci.c b/src/lib/newpci.c new file mode 100644 index 0000000000..37ec768c49 --- /dev/null +++ b/src/lib/newpci.c @@ -0,0 +1,993 @@ +/* + * Low-Level PCI Support for PC + * + * (c) 1999--2000 Martin Mares + */ +/* lots of mods by ron minnich (rminnich@lanl.gov), with + * the final architecture guidance from Tom Merritt (tjm@codegen.com) + * In particular, we changed from the one-pass original version to + * Tom's recommended multiple-pass version. I wasn't sure about doing + * it with multiple passes, until I actually started doing it and saw + * the wisdom of Tom's recommendations ... + */ +/* single-pass allocation appears to be the way to go. */ +#include +#undef __KERNEL__ +#include +#include + +#ifdef EMULATE +#define DEBUG +#endif + +#define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(KERN_DEBUG x) +#else +#define DBG(x...) +#endif + +#define ONEMEG (1 << 20) +#undef TWO_PASS_ALLOCATE + +#define PCI_MEM_START 0x80000000 +#define PCI_IO_START 0x1000 + +static const struct pci_ops *conf; + +struct pci_ops { + int (*read_byte) (u8 bus, int devfn, int where, u8 * val); + int (*read_word) (u8 bus, int devfn, int where, u16 * val); + int (*read_dword) (u8 bus, int devfn, int where, u32 * val); + int (*write_byte) (u8 bus, int devfn, int where, u8 val); + int (*write_word) (u8 bus, int devfn, int where, u16 val); + int (*write_dword) (u8 bus, int devfn, int where, u32 val); +}; + + +/* + * Direct access to PCI hardware... + */ + + +/* + * Functions for accessing PCI configuration space with type 1 accesses + */ + +#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3)) + +static int pci_conf1_read_config_byte(unsigned char bus, int devfn, int where, u8 * value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + *value = inb(0xCFC + (where & 3)); + return 0; +} + +static int pci_conf1_read_config_word(unsigned char bus, int devfn, int where, u16 * value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + *value = inw(0xCFC + (where & 2)); + return 0; +} + +static int pci_conf1_read_config_dword(unsigned char bus, int devfn, int where, u32 * value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + *value = inl(0xCFC); + return 0; +} + +static int pci_conf1_write_config_byte(unsigned char bus, int devfn, int where, u8 value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outb(value, 0xCFC + (where & 3)); + return 0; +} + +static int pci_conf1_write_config_word(unsigned char bus, int devfn, int where, u16 value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outw(value, 0xCFC + (where & 2)); + return 0; +} + +static int pci_conf1_write_config_dword(unsigned char bus, int devfn, int where, u32 value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outl(value, 0xCFC); + return 0; +} + +#undef CONFIG_CMD + +static const struct pci_ops pci_direct_conf1 = +{ + pci_conf1_read_config_byte, + pci_conf1_read_config_word, + pci_conf1_read_config_dword, + pci_conf1_write_config_byte, + pci_conf1_write_config_word, + pci_conf1_write_config_dword +}; + +/* + * Functions for accessing PCI configuration space with type 2 accesses + */ + +#define IOADDR(devfn, where) ((0xC000 | ((devfn & 0x78) << 5)) + where) +#define FUNC(devfn) (((devfn & 7) << 1) | 0xf0) +#define SET(bus,devfn) if (devfn & 0x80) return -1;outb(FUNC(devfn), 0xCF8); outb(bus, 0xCFA); + +static int pci_conf2_read_config_byte(unsigned char bus, int devfn, int where, u8 * value) +{ + SET(bus, devfn); + *value = inb(IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +static int pci_conf2_read_config_word(unsigned char bus, int devfn, int where, u16 * value) +{ + SET(bus, devfn); + *value = inw(IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +static int pci_conf2_read_config_dword(unsigned char bus, int devfn, int where, u32 * value) +{ + SET(bus, devfn); + *value = inl(IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +static int pci_conf2_write_config_byte(unsigned char bus, int devfn, int where, u8 value) +{ + SET(bus, devfn); + outb(value, IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +static int pci_conf2_write_config_word(unsigned char bus, int devfn, int where, u16 value) +{ + SET(bus, devfn); + outw(value, IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +static int pci_conf2_write_config_dword(unsigned char bus, int devfn, int where, u32 value) +{ + SET(bus, devfn); + outl(value, IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +#undef SET +#undef IOADDR +#undef FUNC + +static const struct pci_ops pci_direct_conf2 = +{ + pci_conf2_read_config_byte, + pci_conf2_read_config_word, + pci_conf2_read_config_dword, + pci_conf2_write_config_byte, + pci_conf2_write_config_word, + pci_conf2_write_config_dword +}; + +/* + * Before we decide to use direct hardware access mechanisms, we try to do some + * trivial checks to ensure it at least _seems_ to be working -- we just test + * whether bus 00 contains a host bridge (this is similar to checking + * techniques used in XFree86, but ours should be more reliable since we + * attempt to make use of direct access hints provided by the PCI BIOS). + * + * This should be close to trivial, but it isn't, because there are buggy + * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. + */ +static int pci_sanity_check(const struct pci_ops *o) +{ + u16 x; + u8 bus; + int devfn; +#define PCI_CLASS_BRIDGE_HOST 0x0600 +#define PCI_CLASS_DISPLAY_VGA 0x0300 +#define PCI_VENDOR_ID_COMPAQ 0x0e11 +#define PCI_VENDOR_ID_INTEL 0x8086 + + for (bus = 0, devfn = 0; devfn < 0x100; devfn++) + if ((!o->read_word(bus, devfn, PCI_CLASS_DEVICE, &x) && + (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) || + (!o->read_word(bus, devfn, PCI_VENDOR_ID, &x) && + (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ))) + return 1; + printk(KERN_ERR "PCI: Sanity check failed\n"); + return 0; +} + +static const struct pci_ops *pci_check_direct(void) +{ + unsigned int tmp; + + /* + * Check if configuration type 1 works. + */ + { + outb(0x01, 0xCFB); + tmp = inl(0xCF8); + outl(0x80000000, 0xCF8); + if (inl(0xCF8) == 0x80000000 && + pci_sanity_check(&pci_direct_conf1)) { + outl(tmp, 0xCF8); + printk(KERN_INFO "PCI: Using configuration type 1\n"); + return &pci_direct_conf1; + } + outl(tmp, 0xCF8); + } + + /* + * Check if configuration type 2 works. + */ + { + outb(0x00, 0xCFB); + outb(0x00, 0xCF8); + outb(0x00, 0xCFA); + if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 && + pci_sanity_check(&pci_direct_conf2)) { + printk(KERN_INFO "PCI: Using configuration type 2\n"); + return &pci_direct_conf2; + } + } + + return 0; +} +// Need to merge all these functions. Sorry about this. +// changing horses in mid-stream! + + +int pci_read_config_byte(struct pci_dev *dev, u8 where, u8 * val) +{ + return conf->read_byte(dev->bus->number, dev->devfn, where, val); +} + +int pci_read_config_word(struct pci_dev *dev, u8 where, u16 * val) +{ + return conf->read_word(dev->bus->number, dev->devfn, where, val); +} + +int pci_read_config_dword(struct pci_dev *dev, u8 where, u32 * val) +{ + return conf->read_dword(dev->bus->number, dev->devfn, where, val); +} + +int pci_write_config_byte(struct pci_dev *dev, u8 where, u8 val) +{ + return conf->write_byte(dev->bus->number, dev->devfn, where, val); +} + +int pci_write_config_word(struct pci_dev *dev, u8 where, u16 val) +{ + return conf->write_word(dev->bus->number, dev->devfn, where, val); +} + +int pci_write_config_dword(struct pci_dev *dev, u8 where, u32 val) +{ + return conf->write_dword(dev->bus->number, dev->devfn, where, val); +} + +int pci_debugwrite_config_byte(struct pci_dev *dev, u8 where, u8 val) +{ +#ifndef DEBUG + return conf->write_byte(dev->bus->number, dev->devfn, where, val); +#else + printk("Write config byte bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", + dev->bus->number, dev->devfn, where, val); + return 0; +#endif + +} + +int pci_debugwrite_config_word(struct pci_dev *dev, u8 where, u16 val) +{ +#ifndef DEBUG + return conf->write_word(dev->bus->number, dev->devfn, where, val); +#else + printk("Write config byte bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", + dev->bus->number, dev->devfn, where, val); + return 0; +#endif +} + +int pci_debugwrite_config_dword(struct pci_dev *dev, u8 where, u32 val) +{ +#ifndef DEBUG + return conf->write_dword(dev->bus->number, dev->devfn, where, val); +#else + printk("Write config byte bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", + dev->bus->number, dev->devfn, where, val); + return 0; +#endif +} + + +int pcibios_read_config_byte(unsigned char bus, unsigned char devfn, u8 where, u8 * val) +{ + return conf->read_byte(bus, devfn, where, val); +} + +int pcibios_read_config_word(unsigned char bus, unsigned char devfn, u8 where, u16 * val) +{ + return conf->read_word(bus, devfn, where, val); +} + +int pcibios_read_config_dword(unsigned char bus, unsigned char devfn, u8 where, u32 * val) +{ + return conf->read_dword(bus, devfn, where, val); +} + +int pcibios_write_config_byte(unsigned char bus, unsigned char devfn, u8 where, u8 val) +{ + return conf->write_byte(bus, devfn, where, val); +} + +int pcibios_write_config_word(unsigned char bus, unsigned char devfn, u8 where, u16 val) +{ + return conf->write_word(bus, devfn, where, val); +} + +int pcibios_write_config_dword(unsigned char bus, unsigned char devfn, u8 where, u32 val) +{ + return conf->write_dword(bus, devfn, where, val); +} + + +int pcibios_debugwrite_config_byte(unsigned char bus, unsigned char devfn, u8 where, u8 val) +{ +#ifndef DEBUG + return conf->write_byte(bus, devfn, where, val); +#else + printk("Write byte bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", + bus, devfn, where, val); + return 0; +#endif +} + +int pcibios_debugwrite_config_word(unsigned char bus, unsigned char devfn, u8 where, u16 val) +{ +#ifndef DEBUG + return conf->write_word(bus, devfn, where, val); +#else + printk("Write word bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", + bus, devfn, where, val); + return 0; +#endif + +} + +int pcibios_debugwrite_config_dword(unsigned char bus, unsigned char devfn, u8 where, u32 val) +{ +#ifndef DEBUG + return conf->write_dword(bus, devfn, where, val); +#else + printk("Write doubleword bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", + bus, devfn, where, val); + return 0; +#endif + +} + +/** round a number to an alignment. + * @param val the starting value + * @param roundup Alignment as a power of two + * @returns rounded up number + */ +unsigned long round(unsigned long val, unsigned long roundup) +{ + // ROUNDUP MUST BE A POWER OF TWO. + unsigned long inverse; + inverse = ~(roundup - 1); + val += (roundup - 1); + val &= inverse; + return val; +} + +/** Set the method to be used for PCI, type I or type II + */ +void pci_set_method() +{ + conf = &pci_direct_conf1; + conf = pci_check_direct(); +} + +/* allocating resources on PCI is a mess. The reason is that + * the BAR size is actually two things: one is the size, and + * the other is the alignment of the data. Take, for example, the + * SiS agp hardware. BAR 0 reports a size as follows: 0xf8000008. + * This means prefetchable, and you can compute the size of + * 0x8000000 (128 Mbytes). But it also turns you that only the + * top five bits of the address are decoded. So you can not, for + * example, allocate address space at 0x400000 for 0x8000000 bytes, + * because in the register that will turn into 0. You have + * to allocate address space using only the top five bits of the + * PCI address space, i.e. you have to start allocating at 0x8000000. + * + * we have a more complex algorithm for address space allocation in the + * works, that is actually simple code but gets the desired behavior. + * For now, though, we operate as follows: + * as you encounter BAR values, just round up the current usage + * to be aligned to the BAR size. Then allocate. + * This has the advantage of being simple, and in practice there are + * so few large BAR areas that we expect it to cover all cases. + * If we find problems with this strategy we'll go to the more complex + * algorithm. + */ +/* it's worse than I thought ... + * rules: + * bridges contain all sub-bridges, and the address space for mem and + * prefetch has to be contiguous. + * Anyway, this has gotten so complicated we're going to a one-pass + * allocate for now. + */ + +#ifdef TWO_PASS_ALLOCATE +void compute_resources(struct pci_bus *bus) +{ + int i; + struct pci_bus *curbus; + struct pci_dev *curdev; + unsigned long mem, prefmem, io; + mem = prefmem = io = 0; + // first, walk all the bridges + // Sum up the memory requirements of each bridge and add it into the + // total. + for (curbus = bus->children; curbus; curbus = curbus->next) { + + compute_resources(curbus); + mem += curbus->mem; + prefmem += curbus->prefmem; + io += curbus->io; + printk(KERN_DEBUG "Bridge Bus %d,mem 0x%lx, " + "prefmem 0x%lx, io 0x%lx\n", + curbus->number, mem, prefmem, io); + } + + // second, walk all the devices. Add these. + for (curdev = bus->devices; curdev; curdev = curdev->sibling) { + for (i = 0; i < 6; i++) { + unsigned long size = curdev->size[i]; + if (size & PCI_BASE_ADDRESS_SPACE_IO) { + unsigned long iosize; + iosize = size & PCI_BASE_ADDRESS_IO_MASK; + printk(KERN_DEBUG "Bus %d, devfn 0x%x, " + "reg %d: io 0x%lx\n", + curdev->bus->number, curdev->devfn, + i, iosize); + io += round(iosize, IO_ALIGN); + } else { + unsigned long memorysize = size & (PCI_BASE_ADDRESS_MEM_MASK); + unsigned long type = size & (~PCI_BASE_ADDRESS_MEM_MASK); + // at this point it's memory. What kind? + if (type == 0) { // normal + + unsigned long regmem; + // align the memory value + regmem = round(memorysize, MEM_ALIGN); + mem = round(mem, regmem); + printk(KERN_DEBUG "Bus %d, " + "devfn 0x%x, reg %d: " + "mem 0x%lx\n", + curdev->bus->number, + curdev->devfn, i, regmem); + mem += regmem; + } else if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { + unsigned long regmem; + // align the memory value + regmem = round(memorysize, MEM_ALIGN); + prefmem = round(prefmem, regmem); + printk(KERN_DEBUG "Bus %d, " + "devfn 0x%x, reg %d: " + "prefmem 0x%lx\n", + curdev->bus->number, + curdev->devfn, i, regmem); + prefmem += regmem; + } else + printk(KERN_DEBUG "Bus %d, " + "devfn 0x%x: Unsupported " + "memory type 0x%lx\n", + curdev->bus->number, + curdev->devfn, type); + + } + } + } + + // assign to this bus. + bus->mem = round(mem, ONEMEG); + bus->prefmem = round(prefmem, ONEMEG); + bus->io = round(io, IO_BRIDGE_ALIGN); +} + +void allocate_resources(struct pci_bus *bus) +{ + int i; + struct pci_bus *curbus; + struct pci_dev *curdev; + unsigned long mem, io, prefmem; + + // first, walk all the bridges + // Give each bridge what it needs, then call that bridge to configure + // itself and its devices. + mem = bus->membase; + prefmem = bus->prefmembase; + io = bus->iobase; + + for (curbus = bus->children; curbus; curbus = curbus->next) { + unsigned long memincrement; + unsigned long ioincrement; + // we don't need to round here -- all sizes are already rounded! + + if (curbus->mem) { + curbus->membase = mem; + memincrement = curbus->mem; + curbus->memlimit = curbus->membase + memincrement - 1; + mem += memincrement; + } + if (curbus->prefmem) { + curbus->prefmembase = prefmem; + memincrement = curbus->prefmem; + curbus->prefmemlimit = curbus->prefmembase + memincrement - 1; + prefmem += memincrement; + } + if (curbus->io) { + curbus->iobase = io; + ioincrement = curbus->io; + curbus->iolimit = curbus->io + ioincrement - 1; + io += ioincrement; + } + allocate_resources(curbus); + + printk(KERN_DEBUG "Bridge Bus %d,mem 0x%lx, " + "prefmem 0x%lx, io 0x%lx\n", + curbus->number, mem, prefmem, io); + } + + // Now hand out device memory. + for (curdev = bus->devices; curdev; curdev = curdev->sibling) { + for (i = 0; i < 6; i++) { + if (!curdev->size[i]) + continue; + if (curdev->size[i] & PCI_BASE_ADDRESS_SPACE_IO) { + curdev->command |= PCI_COMMAND_IO; + curdev->base_address[i] = io; + printk(KERN_DEBUG "bus %d devfn 0x%x " + "reg %d io 0x%lx\n", + bus->number, curdev->devfn, i, io); + io += curdev->size[i] & PCI_BASE_ADDRESS_IO_MASK; + } else { + if (curdev->size[i] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + unsigned long size = curdev->size[i] & PCI_BASE_ADDRESS_MEM_MASK; + // align the memory + size = round(size, MEM_ALIGN); + prefmem = round(prefmem, size); + curdev->command |= PCI_COMMAND_MEMORY; + curdev->base_address[i] = prefmem; + printk(KERN_DEBUG "bus %d devfn 0x%x " + "reg %d prefmem 0x%lx\n", + bus->number, curdev->devfn, + i, prefmem); + prefmem += size; + } else { + unsigned long size = curdev->size[i] & PCI_BASE_ADDRESS_MEM_MASK; + // align the memory + size = round(size, MEM_ALIGN); + mem = round(mem, size); + curdev->command |= PCI_COMMAND_MEMORY; + curdev->base_address[i] = mem; + printk(KERN_DEBUG "bus %d devfn 0x%x " + "reg %d mem 0x%lx\n", + bus->number, curdev->devfn, + i, mem); + mem += size; + + } + } + } + } + + +} + +#else /* single pass allocation */ +/** Given a desired amount of io, round it to IO_BRIDGE_ALIGN + * @param amount Amount of memory desired. + */ +unsigned long iolimit(unsigned long amount) +{ + amount = round(amount, IO_BRIDGE_ALIGN) - 1; + return amount; +} + +/** Given a desired amount of memory, round it to ONEMEG + * @param amount Amount of memory desired. + */ +unsigned long memlimit(unsigned long amount) +{ + amount = round(amount, ONEMEG) - 1; + return amount; +} + +/** Compute and allocate the io for this bus. + * @param bus Pointer to the struct for this bus. + */ +void compute_allocate_io(struct pci_bus *bus) +{ + int i; + struct pci_bus *curbus; + struct pci_dev *curdev; + unsigned long io_base; + + io_base = bus->iobase; + DBG("compute_allocate_mem: base 0x%lx\n", bus->iobase); + + /* First, walk all the bridges. When you return, grow the limit of the current bus + since sub-busses need IO rounded to 4096 */ + for (curbus = bus->children; curbus; curbus = curbus->next) { + curbus->iobase = io_base; + compute_allocate_io(curbus); + io_base = round(curbus->iolimit, IO_BRIDGE_ALIGN); + DBG("BUSIO: done Bridge Bus 0x%x, iobase now 0x%lx\n", + curbus->number, io_base); + } + + /* Walk through all the devices on current bus and oompute IO address space.*/ + for (curdev = bus->devices; curdev; curdev = curdev->sibling) { + for (i = 0; i < 6; i++) { + unsigned long size = curdev->size[i]; + if (size & PCI_BASE_ADDRESS_SPACE_IO) { + unsigned long iosize = size & PCI_BASE_ADDRESS_IO_MASK; + if (!iosize) + continue; + + DBG("DEVIO: Bus 0x%x, devfn 0x%x, reg 0x%x: " + "iosize 0x%lx\n", + curdev->bus->number, curdev->devfn, i, iosize); + curdev->base_address[i] = io_base; + // some chipsets allow us to set/clear the IO bit. + // (e.g. VIA 82c686a.) So set it to be safe) + curdev->base_address[i] |= + PCI_BASE_ADDRESS_SPACE_IO; + DBG("-->set base to 0x%lx\n", io_base); + io_base += round(iosize, IO_ALIGN); + curdev->command |= PCI_COMMAND_IO; + } + } + } + bus->iolimit = iolimit(io_base); + + DBG("BUS %d: set iolimit to 0x%lx\n", bus->number, bus->iolimit); +} + +/** Compute and allocate the memory for this bus. + * @param bus Pointer to the struct for this bus. + */ +void compute_allocate_mem(struct pci_bus *bus) +{ + int i; + struct pci_bus *curbus; + struct pci_dev *curdev; + unsigned long mem_base; + + mem_base = bus->membase; + DBG("compute_allocate_mem: base 0x%lx\n", bus->membase); + + /* First, walk all the bridges. When you return, grow the limit of the current bus + since sub-busses need MEMORY rounded to 1 Mega */ + for (curbus = bus->children; curbus; curbus = curbus->next) { + curbus->membase = mem_base; + compute_allocate_mem(curbus); + mem_base = round(curbus->memlimit, ONEMEG); + DBG("BUSMEM: Bridge Bus 0x%x,membase now 0x%lx\n", + curbus->number, mem_base); + } + + /* Walk through all the devices on current bus and oompute MEMORY address space.*/ + for (curdev = bus->devices; curdev; curdev = curdev->sibling) { + for (i = 0; i < 6; i++) { + unsigned long size = curdev->size[i]; + unsigned long memorysize = size & (PCI_BASE_ADDRESS_MEM_MASK); + unsigned long type = size & (~PCI_BASE_ADDRESS_MEM_MASK); + + if (!memorysize) + continue; + + if (type == 0) { + /* this is normal memory space */ + unsigned long regmem; + + /* PCI BUS Spec suggests that the memory address should be + consumed in 4KB unit */ + regmem = round(memorysize, MEM_ALIGN); + mem_base = round(mem_base, regmem); + DBG("DEVMEM: Bus 0x%x, devfn 0x%x, reg 0x%x: " + "memsize 0x%lx\n", + curdev->bus->number, curdev->devfn, i, regmem); + curdev->base_address[i] = mem_base; + DBG("-->set base to 0x%lx\n", mem_base); + mem_base += regmem; + curdev->command |= PCI_COMMAND_MEMORY; + } + } + } + bus->memlimit = memlimit(mem_base); + + DBG("BUS %d: set memlimit to 0x%lx\n", bus->number, bus->memlimit); +} + +/** Compute and allocate the prefetch memory for this bus. + * @param bus Pointer to the struct for this bus. + */ +void compute_allocate_prefmem(struct pci_bus *bus) +{ + int i; + struct pci_bus *curbus; + struct pci_dev *curdev; + unsigned long prefmem_base; + + prefmem_base = bus->prefmembase; + DBG("Compute_allocate_prefmem: base 0x%lx\n", bus->prefmembase); + + /* First, walk all the bridges. When you return, grow the limit of the current bus + since sub-busses need MEMORY rounded to 1 Mega */ + for (curbus = bus->children; curbus; curbus = curbus->next) { + curbus->prefmembase = prefmem_base; + compute_allocate_prefmem(curbus); + prefmem_base = round(curbus->prefmemlimit, ONEMEG); + DBG("BUSPREFMEM: Bridge Bus 0x%x, prefmem base now 0x%lx\n", + curbus->number, prefmem_base); + } + + /* Walk through all the devices on current bus and oompute PREFETCHABLE MEMORY address space.*/ + for (curdev = bus->devices; curdev; curdev = curdev->sibling) { + for (i = 0; i < 6; i++) { + unsigned long size = curdev->size[i]; + unsigned long memorysize = size & (PCI_BASE_ADDRESS_MEM_MASK); + unsigned long type = size & (~PCI_BASE_ADDRESS_MEM_MASK); + + if (!memorysize) + continue; + + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* this is a prefetchable memory area */ + unsigned long regmem; + + /* PCI BUS Spec suggests that the memory address should be + consumed in 4KB unit */ + regmem = round(memorysize, MEM_ALIGN); + prefmem_base = round(prefmem_base, regmem); + DBG("DEVPREFMEM: Bus 0x%x, devfn 0x%x, reg 0x%x: " + "prefmemsize 0x%lx\n", + curdev->bus->number, curdev->devfn, i, regmem); + curdev->base_address[i] = prefmem_base; + DBG("-->set base to 0x%lx\n", prefmem_base); + prefmem_base += regmem; + curdev->command |= PCI_COMMAND_MEMORY; + } + } + } + bus->prefmemlimit = memlimit(prefmem_base); + + DBG("BUS %d: set prefmemlimit to 0x%lx\n", bus->number, bus->prefmemlimit); +} + +/** Compute and allocate resources. + * This is a one-pass process. We first compute all the IO, then + * memory, then prefetchable memory. + * This is really only called at the top level + * @param bus Pointer to the struct for this bus. + */ +void compute_allocate_resources(struct pci_bus *bus) +{ + DBG("COMPUTE_ALLOCATE: do IO\n"); + compute_allocate_io(bus); + + DBG("COMPUTE_ALLOCATE: do MEM\n"); + compute_allocate_mem(bus); + + // now put the prefetchable memory at the end of the memory + bus->prefmembase = round(bus->memlimit, ONEMEG); + + DBG("COMPUTE_ALLOCATE: do PREFMEM\n"); + compute_allocate_prefmem(bus); +} + +#endif /* TWO_PASS_ALLOCATE */ + +/** Assign the computed resources to the bridges and devices on the bus. + * Recurse to any bridges found on this bus first. Then do the devices + * on this bus. + * @param bus Pointer to the structure for this bus + */ + +void assign_resources(struct pci_bus *bus) +{ + struct pci_dev *curdev = pci_devices; + struct pci_bus *curbus; + + DBG("ASSIGN RESOURCES, bus %d\n", bus->number); + + /* wlak trhough all the buses, assign resources for bridges */ + for (curbus = bus->children; curbus; curbus = curbus->next) { + curbus->self->command = 0; + + /* set the IO ranges + WARNING: we don't really do 32-bit addressing for IO yet! */ + if (curbus->iobase) { + curbus->self->command |= PCI_COMMAND_IO; + pci_write_config_byte(curbus->self, PCI_IO_BASE, + curbus->iobase >> 8); + pci_write_config_byte(curbus->self, PCI_IO_LIMIT, + curbus->iolimit >> 8); + DBG("Bus 0x%x iobase to 0x%x iolimit 0x%x\n", + bus->number, curbus->iobase, curbus->iolimit); + } + + // set the memory range + if (curbus->membase) { + curbus->self->command |= PCI_COMMAND_MEMORY; + pci_write_config_word(curbus->self, PCI_MEMORY_BASE, + curbus->membase >> 16); + pci_write_config_word(curbus->self, PCI_MEMORY_LIMIT, + curbus->memlimit >> 16); + DBG("Bus 0x%x membase to 0x%x memlimit 0x%x\n", + bus->number, curbus->membase, curbus->memlimit); + + } + + // set the prefetchable memory range + if (curbus->prefmembase) { + curbus->self->command |= PCI_COMMAND_MEMORY; + pci_write_config_word(curbus->self, PCI_PREF_MEMORY_BASE, + curbus->prefmembase >> 16); + pci_write_config_word(curbus->self, PCI_PREF_MEMORY_LIMIT, + curbus->prefmemlimit >> 16); + DBG("Bus 0x%x prefmembase to 0x%x prefmemlimit 0x%x\n", + bus->number, curbus->prefmembase, curbus->prefmemlimit); + + } + curbus->self->command |= PCI_COMMAND_MASTER; + } + + for (curdev = pci_devices; curdev; curdev = curdev->next) { + int i; + for (i = 0; i < 6; i++) { + unsigned long reg; + if (curdev->base_address[i] == 0) + continue; + + reg = PCI_BASE_ADDRESS_0 + (i << 2); + pci_write_config_dword(curdev, reg, curdev->base_address[i]); + DBG("Bus 0x%x devfn 0x%x reg 0x%x base to 0x%lx\n", + curdev->bus->number, curdev->devfn, i, + curdev->base_address[i]); + } + } +} + +void enable_resources(struct pci_bus *bus) +{ + struct pci_dev *curdev = pci_devices; + + /* walk through the chain of all pci device, this time we don't have to deal + with the device v.s. bridge stuff, since every bridge has its own pci_dev + assocaited with it */ + for (curdev = pci_devices; curdev; curdev = curdev->next) { + u16 command; + pci_read_config_word(curdev, PCI_COMMAND, &command); + command |= curdev->command; + pci_write_config_word(curdev, PCI_COMMAND, command); + DBG("DEV Set command bus 0x%x devfn 0x%x to 0x%x\n", + curdev->bus->number, curdev->devfn, command); + } +} + +/** Enumerate the resources on the PCI by calling pci_init + */ +void pci_enumerate() +{ + // scan it. + pci_init(); +} + +/** Starting at the root, compute what resources are needed and allocate them. + * We start memory, prefetchable memory at PCI_MEM_START. I/O starts at + * PCI_IO_START. Since the assignment is hierarchical we set the values + * into the pci_root struct. + */ +void pci_configure() +{ + pci_root.membase = PCI_MEM_START; + pci_root.prefmembase = PCI_MEM_START; + pci_root.iobase = PCI_IO_START; + + compute_allocate_resources(&pci_root); + // now just set things into registers ... we hope ... + assign_resources(&pci_root); +} + +/** Starting at the root, walk the tree and enable all devices/bridges. + * What really happens is computed COMMAND bits get set in register 4 + */ +void pci_enable() +{ + // now enable everything. + enable_resources(&pci_root); +} + +// is this dead code? think so. -- RGM +int configure_pci(unsigned long memstart, unsigned long iostart) +{ +#ifdef EMULATE + int iopl(int level); + iopl(3); + // pick how to scan the bus + pci_set_method(); +#else + // FIX ME. We really should use whatever is set up elsewhere. + void malloc_init(unsigned long start, unsigned long end); + // pick the last 1M of memory to put our structures in. + malloc_init(memstart - ONEMEG, memstart - 1); +#endif + + // scan it. + pci_init(); + +#ifdef TWO_PASS_ALLOCATE + /* compute the memory resources. You can't just add up the + * per-device resources. You have to walk the bridges, because + * bridges require 1M granularity at 1M alignments (!) + */ + pci_root.mem = pci_root.prefmem = pci_root.io = 0; + compute_resources(&pci_root); + printk(KERN_DEBUG "Total: 0x%lx mem, 0x%lx prefmem, 0x%lx io\n", + pci_root.mem, pci_root.prefmem, pci_root.io); + // set in the bases and limits for the root. These really apply to the + // subordinate busses and devices. + pci_root.membase = memstart; + pci_root.memlimit = pci_root.membase + pci_root.mem - 1; + pci_root.prefmembase = round(pci_root.memlimit, ONEMEG); + pci_root.prefmemlimit = pci_root.prefmembase + pci_root.prefmem - 1; + pci_root.iobase = iostart; + pci_root.iolimit = 0xffff - iostart; + allocate_resources(&pci_root); +#else + pci_root.membase = PCI_MEM_START; + pci_root.prefmembase = PCI_MEM_START; + pci_root.iobase = PCI_IO_START; + compute_allocate_resources(&pci_root); +#endif /* TWO_PASS_ALLOCATE */ + + // now just set things into registers ... we hope ... + assign_resources(&pci_root); + // now enable everything. + enable_resources(&pci_root); + return 0; +} + +#ifdef EMULATE +/** deprecated, you can run this code in user mode for certain testing + * We haven't used this recently so it's unclear if it works. + */ +int main() +{ + unsigned long memstart = 0x40000000; + unsigned long iostart = 0x1000; + configure_pci(memstart, iostart); + return 0; +} +#endif diff --git a/src/lib/printk.c b/src/lib/printk.c new file mode 100644 index 0000000000..2707fabbef --- /dev/null +++ b/src/lib/printk.c @@ -0,0 +1,62 @@ +/* + * blantantly copied from linux/kernel/printk.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + */ + + +//typedef void * va_list; + +#include + +static char buf[1024]; + +/* printk's without a loglevel use this.. */ +#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ + +/* We show everything that is MORE important than this.. */ +#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ + +#ifndef DEFAULT_CONSOLE_LOGLEVEL +#define DEFAULT_CONSOLE_LOGLEVEL 8 /* anything MORE serious than KERN_WARNING */ +#endif + +/* Keep together for sysctl support */ + +int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; +int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL; +int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL; +int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; + +void display(char*); +extern int vsprintf(char *buf, const char *, va_list); + +int printk(const char *fmt, ...) +{ + va_list args; + int i; + char *p; + int msg_level; + + va_start(args, fmt); + i = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf)-4 */ + va_end(args); + p = buf; + if ( + p[0] == '<' && + p[1] > '0' && + p[1] <= '9' && + p[2] == '>' + ) { + msg_level = p[1] - '0'; + p +=3; + } else { + msg_level = default_message_loglevel; + } + if (msg_level < console_loglevel) { + display(p); + } + return i; +} + diff --git a/src/lib/vsprintf.c b/src/lib/vsprintf.c new file mode 100644 index 0000000000..f939bc249f --- /dev/null +++ b/src/lib/vsprintf.c @@ -0,0 +1,331 @@ +/* + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + + +#include +#include +#include + +/* haha, don't need ctype.c */ +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#define is_digit isdigit +#define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) +#define islower(c) ((c) >= 'a' && (c) <= 'z') +#define toupper(c) __toupper(c) + +static inline unsigned char __toupper(unsigned char c) +{ + if (islower(c)) + c -= 'a'-'A'; + return c; +} + + +unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) +{ + unsigned long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) + ? toupper(*cp) : *cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +long simple_strtol(const char *cp,char **endp,unsigned int base) +{ + if(*cp=='-') + return -simple_strtoul(cp+1,endp,base); + return simple_strtoul(cp,endp,base); +} + + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static char * number(char * str, long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +/* Forward decl. needed for IP address printing stuff... */ +int sprintf(char * buf, const char *fmt, ...); + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} diff --git a/src/pc80/serial.inc b/src/pc80/serial.inc new file mode 100644 index 0000000000..c253dc3643 --- /dev/null +++ b/src/pc80/serial.inc @@ -0,0 +1,192 @@ + +/* Base Address */ +#define TTYS0 0x3f8 + +/* Data */ +#define TTYS0_RBR (TTYS0+0x00) + +/* Control */ +#define TTYS0_TBR TTYS0_RBR +#define TTYS0_IER (TTYS0+0x01) +#define TTYS0_IIR (TTYS0+0x02) +#define TTYS0_FCR TTYS0_IIR +#define TTYS0_LCR (TTYS0+0x03) +#define TTYS0_MCR (TTYS0+0x04) +#define TTYS0_DLL TTYS0_RBR +#define TTYS0_DLM TTYS0_IER + +/* Status */ +#define TTYS0_LSR (TTYS0+0x05) +#define TTYS0_MSR (TTYS0+0x06) +#define TTYS0_SCR (TTYS0+0x07) + + jmp serial0 + + /* uses: ax, dx */ + +#define TTYS0_TX_AL \ + mov %al, %ah ; \ +9: mov $TTYS0_LSR, %dx ; \ + inb %dx, %al ; \ + test $0x20, %al ; \ + je 9b ; \ + mov $TTYS0_TBR, %dx ; \ + mov %ah, %al ; \ + outb %al, %dx + + /* uses: esp, ax, dx */ +#define TTYS0_TX_CHAR(byte) \ + mov byte, %al ; \ + CALLSP(ttys0_tx_al) + + /* uses: esp, ax, dx */ +#define TTYS0_TX_HEX8(byte) \ + mov byte, %al ; \ + CALLSP(ttys0_tx_hex8) + + /* uses: esp, eax, ebx, dx */ +#define TTYS0_TX_HEX32(lword) \ + mov lword, %eax ; \ + CALLSP(ttys0_tx_hex32) + + /* uses: esp, ebx, ax, dx */ +#define TTYS0_TX_STRING(string) \ + mov string, %ebx ; \ + CALLSP(ttys0_tx_string) + + /* uses: esp, ax, dx */ +ttys0_tx_al: + TTYS0_TX_AL + RETSP + + /* uses: esp, ax, dx */ +ttys0_tx_hex8: + mov $TTYS0_SCR, %dx + outb %al, %dx + shr $4, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + TTYS0_TX_AL + mov $TTYS0_SCR, %dx + inb %dx, %al + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + TTYS0_TX_AL + RETSP + + /* uses: esp, ebx, eax, dx */ +ttys0_tx_hex32: + mov %eax, %ebx + shr $28, %eax + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + TTYS0_TX_AL + + mov %ebx, %eax + shr $24, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + TTYS0_TX_AL + + mov %ebx, %eax + shr $20, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + TTYS0_TX_AL + + mov %ebx, %eax + shr $16, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + TTYS0_TX_AL + + mov %ebx, %eax + shr $12, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + TTYS0_TX_AL + + mov %ebx, %eax + shr $8, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + TTYS0_TX_AL + + mov %ebx, %eax + shr $4, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + TTYS0_TX_AL + + mov %ebx, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + TTYS0_TX_AL + + RETSP + + /* Uses esp, ebx, ax, dx */ + +ttys0_tx_string: + mov (%ebx), %al + inc %ebx + cmp $0, %al + jne 9f + RETSP +9: TTYS0_TX_AL + jmp ttys0_tx_string + +serial0: + + /* Set 115.2Kbps,8n1 */ + + mov $TTYS0_LCR, %dx + mov $0x83, %al + out %al, %dx + mov $TTYS0_DLL, %dx + mov $0x01, %al + out %al, %dx + mov $TTYS0_DLM, %dx + mov $0x00, %al + out %al, %dx + mov $TTYS0_LCR, %dx + mov $0x03, %al + out %al, %dx