Unified · Split
| @@ -0,0 +1,31 @@ | ||
| 1 | +This copyright NOTICE applies to all files in this directory and | |
| 2 | +subdirectories, unless another copyright notice appears in a given | |
| 3 | +file or subdirectory. If you take substantial code from this software to use in | |
| 4 | +other programs, you must somehow include with it an appropriate | |
| 5 | +copyright notice that includes the copyright notice and the other | |
| 6 | +notices below. It is fine (and often tidier) to do that in a separate | |
| 7 | +file such as NOTICE, LICENCE or COPYING. | |
| 8 | + | |
| 9 | + Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. | |
| 10 | + Portions Copyright © 1997-1999 Vita Nuova Limited | |
| 11 | + Portions Copyright © 2000-2006 Vita Nuova Holdings Limited (www.vitanuova.com) | |
| 12 | + Revisions Copyright © 2000-2006 Lucent Technologies Inc. and others | |
| 13 | + | |
| 14 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 15 | +of this software and associated documentation files (the "Software"), to deal | |
| 16 | +in the Software without restriction, including without limitation the rights | |
| 17 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 18 | +copies of the Software, and to permit persons to whom the Software is | |
| 19 | +furnished to do so, subject to the following conditions: | |
| 20 | + | |
| 21 | +The above copyright notice and this permission notice shall be included in | |
| 22 | +all copies or substantial portions of the Software. | |
| 23 | + | |
| 24 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 25 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 26 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 27 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 28 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 29 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 30 | +THE SOFTWARE. | |
| 31 | + | |
| @@ -0,0 +1,32 @@ | ||
| 1 | +# a few sample native ports for different architectures | |
| 2 | + | |
| 3 | +cerf1110 arm Intrinsyc SA-1110 Cerf Cube | |
| 4 | +ipaq1110 arm Strongarm SA1110 native kernel for Compaq iPAQ 36xx | |
| 5 | +sa1110 arm SA1110 code common to most/all SA1110 platforms (eg, ipaq, cerf) | |
| 6 | + | |
| 7 | +cerf250 arm Intrinsyc Cerfboard250 (PXA250) | |
| 8 | +gum arm Gumstix PXA255 | |
| 9 | +pxa arm general PXA support | |
| 10 | + | |
| 11 | +js sparc original port to Javastation-1, not recently tested | |
| 12 | + | |
| 13 | +ks32 arm ARM Evaluator 7t demo | |
| 14 | + | |
| 15 | +manga arm Micrel KS8695P ARM922 core with 4-port switch and PCI support | |
| 16 | + | |
| 17 | +cerf405 power Cerfcube 405EP (based on IBM 405EP processor) | |
| 18 | + | |
| 19 | +ipengine power Bright Star Engineering (www.brightstareng.com) ipEngine-1 (MPC823) | |
| 20 | +rpcg power RPCG-Lite MPC823/850 board | |
| 21 | +fads power MPC8xx FADS development board | |
| 22 | +mpc power code common to ports to Motorola MPC8xx boards | |
| 23 | + | |
| 24 | +pc 386 basis for ports to various PC-based platforms | |
| 25 | + | |
| 26 | +# basic Inferno native kernel components | |
| 27 | +port common native operating system components | |
| 28 | +ip common Internet protocol stack, Ether and PPP media | |
| 29 | +init common Limbo initialisation program (run by native kernel on startup) | |
| 30 | + | |
| 31 | +# sample bootstraps | |
| 32 | +boot - directory of several bootstrap programs; see README there | |
| @@ -0,0 +1,33 @@ | ||
| 1 | +Often the devices we use now come with some | |
| 2 | +form of bootstrap (often annoyingly complicated, | |
| 3 | +which gets in the way). Older boards were sometimes | |
| 4 | +bare, and we had to provide something (often annoyingly | |
| 5 | +complicated...). On the PC it's currently helpful to | |
| 6 | +have something that can boot from disc or ether; | |
| 7 | +since it's a thankless task to write such a thing, we | |
| 8 | +use Plan 9's, and thank its authors. | |
| 9 | + | |
| 10 | +The current scheme on newer devices is to have a simple | |
| 11 | +program that can put a stripped-down Inferno kernel into | |
| 12 | +flash, and use that to boot from other devices (including over the net) | |
| 13 | +as required during development. | |
| 14 | + | |
| 15 | +There are two distinct models for bootstrap in this directory. | |
| 16 | + | |
| 17 | + Model I | |
| 18 | + | |
| 19 | +Each member of the first model is represented by a self-contained directory. | |
| 20 | +They are derived from various ages of Plan 9's /sys/src/boot/pc. | |
| 21 | + | |
| 22 | +arm1110 arm a prefix to a gzip'd kernel to decompress it (runs after basic bootloader) | |
| 23 | +pc 386 pc-specific bootstrap essentially identical to current Plan 9 | |
| 24 | + and covered by the Lucent Public License; it uses | |
| 25 | +libflate - zlib-style inflate/deflate library | |
| 26 | +mpc power PowerPC bootstrap for FADS board derived from an older version | |
| 27 | + of Plan 9 but covered by our Inferno licence (because it came with Inferno) | |
| 28 | +puma arm SA110 bootstrap for Teralogics Puma, also covered by the Inferno licence | |
| 29 | + | |
| 30 | + Model II | |
| 31 | +omap purpose-built bootstrap for the OMAP processor | |
| 32 | + | |
| 33 | +Not all of these are being distributed. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +#!/bin/rc | |
| 2 | +rfork ne | |
| 3 | +ROOT=/usr/inferno | |
| 4 | +fn cd | |
| 5 | +NPROC=3 | |
| 6 | +path=(/usr/inferno/Plan9/$cputype/bin $path) | |
| 7 | +#bind /usr/inferno/mkconfig.dist /usr/inferno/mkconfig | |
| 8 | +exec mk $* | |
| @@ -0,0 +1 @@ | ||
| 1 | +/* deliberately empty */ | |
| @@ -0,0 +1,332 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | + | |
| 4 | +#define PTR sizeof(char*) | |
| 5 | +#define SHORT sizeof(int) | |
| 6 | +#define INT sizeof(int) | |
| 7 | +#define LONG sizeof(long) | |
| 8 | +#define IDIGIT 30 | |
| 9 | +#define MAXCON 30 | |
| 10 | + | |
| 11 | +#define FLONG (1<<0) | |
| 12 | +#define FSHORT (1<<1) | |
| 13 | +#define FUNSIGN (1<<2) | |
| 14 | + | |
| 15 | +typedef struct Op Op; | |
| 16 | +struct Op | |
| 17 | +{ | |
| 18 | + char *p; | |
| 19 | + char *ep; | |
| 20 | + void *argp; | |
| 21 | + int f1; | |
| 22 | + int f2; | |
| 23 | + int f3; | |
| 24 | +}; | |
| 25 | + | |
| 26 | +static int noconv(Op*); | |
| 27 | +static int cconv(Op*); | |
| 28 | +static int dconv(Op*); | |
| 29 | +static int hconv(Op*); | |
| 30 | +static int lconv(Op*); | |
| 31 | +static int oconv(Op*); | |
| 32 | +static int sconv(Op*); | |
| 33 | +static int uconv(Op*); | |
| 34 | +static int xconv(Op*); | |
| 35 | +static int Xconv(Op*); | |
| 36 | +static int percent(Op*); | |
| 37 | + | |
| 38 | +static | |
| 39 | +int (*fmtconv[MAXCON])(Op*) = | |
| 40 | +{ | |
| 41 | + noconv, | |
| 42 | + cconv, dconv, hconv, lconv, | |
| 43 | + oconv, sconv, uconv, xconv, | |
| 44 | + Xconv, percent, | |
| 45 | +}; | |
| 46 | +static | |
| 47 | +char fmtindex[128] = | |
| 48 | +{ | |
| 49 | + ['c'] 1, | |
| 50 | + ['d'] 2, | |
| 51 | + ['h'] 3, | |
| 52 | + ['l'] 4, | |
| 53 | + ['o'] 5, | |
| 54 | + ['s'] 6, | |
| 55 | + ['u'] 7, | |
| 56 | + ['x'] 8, | |
| 57 | + ['X'] 9, | |
| 58 | + ['%'] 10, | |
| 59 | +}; | |
| 60 | + | |
| 61 | +static int convcount = { 11 }; | |
| 62 | +static int ucase; | |
| 63 | + | |
| 64 | +static void | |
| 65 | +PUT(Op *o, int c) | |
| 66 | +{ | |
| 67 | + static int pos; | |
| 68 | + int opos; | |
| 69 | + | |
| 70 | + if(c == '\t'){ | |
| 71 | + opos = pos; | |
| 72 | + pos = (opos+8) & ~7; | |
| 73 | + while(opos++ < pos && o->p < o->ep) | |
| 74 | + *o->p++ = ' '; | |
| 75 | + return; | |
| 76 | + } | |
| 77 | + if(o->p < o->ep){ | |
| 78 | + *o->p++ = c; | |
| 79 | + pos++; | |
| 80 | + } | |
| 81 | + if(c == '\n') | |
| 82 | + pos = 0; | |
| 83 | +} | |
| 84 | + | |
| 85 | +int | |
| 86 | +fmtinstall(char c, int (*f)(Op*)) | |
| 87 | +{ | |
| 88 | + | |
| 89 | + c &= 0177; | |
| 90 | + if(fmtindex[c] == 0) { | |
| 91 | + if(convcount >= MAXCON) | |
| 92 | + return 1; | |
| 93 | + fmtindex[c] = convcount++; | |
| 94 | + } | |
| 95 | + fmtconv[fmtindex[c]] = f; | |
| 96 | + return 0; | |
| 97 | +} | |
| 98 | + | |
| 99 | +char* | |
| 100 | +donprint(char *p, char *ep, char *fmt, void *argp) | |
| 101 | +{ | |
| 102 | + int sf1, c; | |
| 103 | + Op o; | |
| 104 | + | |
| 105 | + o.p = p; | |
| 106 | + o.ep = ep; | |
| 107 | + o.argp = argp; | |
| 108 | + | |
| 109 | +loop: | |
| 110 | + c = *fmt++; | |
| 111 | + if(c != '%') { | |
| 112 | + if(c == 0) { | |
| 113 | + if(o.p < o.ep) | |
| 114 | + *o.p = 0; | |
| 115 | + return o.p; | |
| 116 | + } | |
| 117 | + PUT(&o, c); | |
| 118 | + goto loop; | |
| 119 | + } | |
| 120 | + o.f1 = 0; | |
| 121 | + o.f2 = -1; | |
| 122 | + o.f3 = 0; | |
| 123 | + c = *fmt++; | |
| 124 | + sf1 = 0; | |
| 125 | + if(c == '-') { | |
| 126 | + sf1 = 1; | |
| 127 | + c = *fmt++; | |
| 128 | + } | |
| 129 | + while(c >= '0' && c <= '9') { | |
| 130 | + o.f1 = o.f1*10 + c-'0'; | |
| 131 | + c = *fmt++; | |
| 132 | + } | |
| 133 | + if(sf1) | |
| 134 | + o.f1 = -o.f1; | |
| 135 | + if(c != '.') | |
| 136 | + goto l1; | |
| 137 | + c = *fmt++; | |
| 138 | + while(c >= '0' && c <= '9') { | |
| 139 | + if(o.f2 < 0) | |
| 140 | + o.f2 = 0; | |
| 141 | + o.f2 = o.f2*10 + c-'0'; | |
| 142 | + c = *fmt++; | |
| 143 | + } | |
| 144 | +l1: | |
| 145 | + if(c == 0) | |
| 146 | + fmt--; | |
| 147 | + c = (*fmtconv[fmtindex[c&0177]])(&o); | |
| 148 | + if(c < 0) { | |
| 149 | + o.f3 |= -c; | |
| 150 | + c = *fmt++; | |
| 151 | + goto l1; | |
| 152 | + } | |
| 153 | + o.argp = (char*)o.argp + c; | |
| 154 | + goto loop; | |
| 155 | +} | |
| 156 | + | |
| 157 | +void | |
| 158 | +strconv(char *o, Op *op, int f1, int f2) | |
| 159 | +{ | |
| 160 | + int n, c; | |
| 161 | + char *p; | |
| 162 | + | |
| 163 | + n = strlen(o); | |
| 164 | + if(f1 >= 0) | |
| 165 | + while(n < f1) { | |
| 166 | + PUT(op, ' '); | |
| 167 | + n++; | |
| 168 | + } | |
| 169 | + for(p=o; c = *p++;) | |
| 170 | + if(f2 != 0) { | |
| 171 | + PUT(op, c); | |
| 172 | + f2--; | |
| 173 | + } | |
| 174 | + if(f1 < 0) { | |
| 175 | + f1 = -f1; | |
| 176 | + while(n < f1) { | |
| 177 | + PUT(op, ' '); | |
| 178 | + n++; | |
| 179 | + } | |
| 180 | + } | |
| 181 | +} | |
| 182 | + | |
| 183 | +int | |
| 184 | +numbconv(Op *op, int base) | |
| 185 | +{ | |
| 186 | + char b[IDIGIT]; | |
| 187 | + int i, f, n, r; | |
| 188 | + long v; | |
| 189 | + short h; | |
| 190 | + | |
| 191 | + f = 0; | |
| 192 | + switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) { | |
| 193 | + case FLONG: | |
| 194 | + v = *(long*)op->argp; | |
| 195 | + r = LONG; | |
| 196 | + break; | |
| 197 | + | |
| 198 | + case FUNSIGN|FLONG: | |
| 199 | + v = *(ulong*)op->argp; | |
| 200 | + r = LONG; | |
| 201 | + break; | |
| 202 | + | |
| 203 | + case FSHORT: | |
| 204 | + h = *(int*)op->argp; | |
| 205 | + v = h; | |
| 206 | + r = SHORT; | |
| 207 | + break; | |
| 208 | + | |
| 209 | + case FUNSIGN|FSHORT: | |
| 210 | + h = *(int*)op->argp; | |
| 211 | + v = (ushort)h; | |
| 212 | + r = SHORT; | |
| 213 | + break; | |
| 214 | + | |
| 215 | + default: | |
| 216 | + v = *(int*)op->argp; | |
| 217 | + r = INT; | |
| 218 | + break; | |
| 219 | + | |
| 220 | + case FUNSIGN: | |
| 221 | + v = *(unsigned*)op->argp; | |
| 222 | + r = INT; | |
| 223 | + break; | |
| 224 | + } | |
| 225 | + if(!(op->f3 & FUNSIGN) && v < 0) { | |
| 226 | + v = -v; | |
| 227 | + f = 1; | |
| 228 | + } | |
| 229 | + b[IDIGIT-1] = 0; | |
| 230 | + for(i = IDIGIT-2;; i--) { | |
| 231 | + n = (ulong)v % base; | |
| 232 | + n += '0'; | |
| 233 | + if(n > '9'){ | |
| 234 | + n += 'a' - ('9'+1); | |
| 235 | + if(ucase) | |
| 236 | + n += 'A'-'a'; | |
| 237 | + } | |
| 238 | + b[i] = n; | |
| 239 | + if(i < 2) | |
| 240 | + break; | |
| 241 | + v = (ulong)v / base; | |
| 242 | + if(op->f2 >= 0 && i >= IDIGIT-op->f2) | |
| 243 | + continue; | |
| 244 | + if(v <= 0) | |
| 245 | + break; | |
| 246 | + } | |
| 247 | + if(f) | |
| 248 | + b[--i] = '-'; | |
| 249 | + strconv(b+i, op, op->f1, -1); | |
| 250 | + return r; | |
| 251 | +} | |
| 252 | + | |
| 253 | +static int | |
| 254 | +noconv(Op *op) | |
| 255 | +{ | |
| 256 | + | |
| 257 | + strconv("***", op, 0, -1); | |
| 258 | + return 0; | |
| 259 | +} | |
| 260 | + | |
| 261 | +static int | |
| 262 | +cconv(Op *op) | |
| 263 | +{ | |
| 264 | + char b[2]; | |
| 265 | + | |
| 266 | + b[0] = *(int*)op->argp; | |
| 267 | + b[1] = 0; | |
| 268 | + strconv(b, op, op->f1, -1); | |
| 269 | + return INT; | |
| 270 | +} | |
| 271 | + | |
| 272 | +static int | |
| 273 | +dconv(Op *op) | |
| 274 | +{ | |
| 275 | + return numbconv(op, 10); | |
| 276 | +} | |
| 277 | + | |
| 278 | +static int | |
| 279 | +hconv(Op*) | |
| 280 | +{ | |
| 281 | + return -FSHORT; | |
| 282 | +} | |
| 283 | + | |
| 284 | +static int | |
| 285 | +lconv(Op*) | |
| 286 | +{ | |
| 287 | + return -FLONG; | |
| 288 | +} | |
| 289 | + | |
| 290 | +static int | |
| 291 | +oconv(Op *op) | |
| 292 | +{ | |
| 293 | + return numbconv(op, 8); | |
| 294 | +} | |
| 295 | + | |
| 296 | +static int | |
| 297 | +sconv(Op *op) | |
| 298 | +{ | |
| 299 | + strconv(*(char**)op->argp, op, op->f1, op->f2); | |
| 300 | + return PTR; | |
| 301 | +} | |
| 302 | + | |
| 303 | +static int | |
| 304 | +uconv(Op*) | |
| 305 | +{ | |
| 306 | + return -FUNSIGN; | |
| 307 | +} | |
| 308 | + | |
| 309 | +static int | |
| 310 | +xconv(Op *op) | |
| 311 | +{ | |
| 312 | + return numbconv(op, 16); | |
| 313 | +} | |
| 314 | + | |
| 315 | +static int | |
| 316 | +Xconv(Op *op) | |
| 317 | +{ | |
| 318 | + int r; | |
| 319 | + | |
| 320 | + ucase = 1; | |
| 321 | + r = numbconv(op, 16); | |
| 322 | + ucase = 0; | |
| 323 | + return r; | |
| 324 | +} | |
| 325 | + | |
| 326 | +static int | |
| 327 | +percent(Op *op) | |
| 328 | +{ | |
| 329 | + | |
| 330 | + PUT(op, '%'); | |
| 331 | + return 0; | |
| 332 | +} | |
| @@ -0,0 +1,7 @@ | ||
| 1 | +/* | |
| 2 | + * functions defined locally | |
| 3 | + */ | |
| 4 | +extern int gunzip(uchar *out, int outn, uchar *in, int inn); | |
| 5 | +extern void delay(int ms); | |
| 6 | +extern void serialputs(char *str, int n); | |
| 7 | +extern void draincache(void); | |
| @@ -0,0 +1,99 @@ | ||
| 1 | +#include "mem.h" | |
| 2 | +/* | |
| 3 | + * Entered here from Compaq's bootldr. First relocate to | |
| 4 | + * the location we're linked for and then copy back the | |
| 5 | + * decompressed kernel. | |
| 6 | + * | |
| 7 | + * All | |
| 8 | + */ | |
| 9 | +TEXT _start(SB), $-4 | |
| 10 | + MOVW $setR12(SB), R12 /* load the SB */ | |
| 11 | + MOVW $1, R0 /* dance to make 5l think that the magic */ | |
| 12 | + MOVW $1, R1 /* numbers in WORDs below are being used */ | |
| 13 | + CMP.S R0, R1 /* and to align them to where bootldr wants */ | |
| 14 | + BEQ _start2 | |
| 15 | + WORD $0x016f2818 /* magic number to say we are a kernel */ | |
| 16 | + WORD $0xc0008000 /* entry point address */ | |
| 17 | + WORD $0 /* size?, or end of data? */ | |
| 18 | + | |
| 19 | +_start2: | |
| 20 | + | |
| 21 | + /* SVC mode, interrupts disabled */ | |
| 22 | + MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R1 | |
| 23 | + MOVW R1, CPSR | |
| 24 | + | |
| 25 | + /* disable the MMU */ | |
| 26 | + MOVW $0x130, R1 | |
| 27 | + MCR CpMMU, 0, R1, C(CpControl), C(0x0) | |
| 28 | + | |
| 29 | + /* enable caches */ | |
| 30 | + MRC CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 31 | + ORR $(CpCdcache|CpCicache|CpCwb), R0 | |
| 32 | + MCR CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 33 | + | |
| 34 | + /* flush caches */ | |
| 35 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0 | |
| 36 | + /* drain prefetch */ | |
| 37 | + MOVW R0,R0 | |
| 38 | + MOVW R0,R0 | |
| 39 | + MOVW R0,R0 | |
| 40 | + MOVW R0,R0 | |
| 41 | + | |
| 42 | + /* drain write buffer */ | |
| 43 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4 | |
| 44 | + | |
| 45 | + /* relocate to where we expect to be */ | |
| 46 | + MOVW $(FLATESIZE),R3 | |
| 47 | + MOVW $0xC0008000,R1 | |
| 48 | + MOVW $0xC0200000,R2 | |
| 49 | + ADD R1,R3 | |
| 50 | +_relloop: | |
| 51 | + MOVW (R1),R0 | |
| 52 | + MOVW R0,(R2) | |
| 53 | + ADD $4,R1 | |
| 54 | + ADD $4,R2 | |
| 55 | + CMP.S R1,R3 | |
| 56 | + BNE _relloop | |
| 57 | + | |
| 58 | + MOVW $(MACHADDR+BY2PG), R13 /* stack */ | |
| 59 | + SUB $4, R13 /* link */ | |
| 60 | + | |
| 61 | + /* jump to where we've been relocated */ | |
| 62 | + MOVW $_relocated(SB),R15 | |
| 63 | + | |
| 64 | +TEXT _relocated(SB),$-4 | |
| 65 | + BL main(SB) | |
| 66 | + BL exit(SB) | |
| 67 | + /* we shouldn't get here */ | |
| 68 | +_mainloop: | |
| 69 | + B _mainloop | |
| 70 | + BL _div(SB) /* hack to get _div etc loaded */ | |
| 71 | + | |
| 72 | +TEXT mypc(SB),$-4 | |
| 73 | + MOVW R14,R0 | |
| 74 | + RET | |
| 75 | + | |
| 76 | +TEXT draincache(SB),$-4 | |
| 77 | + /* write back any dirty data */ | |
| 78 | + MOVW $0xe0000000,R0 | |
| 79 | + ADD $(8*1024),R0,R1 | |
| 80 | +_cfloop: | |
| 81 | + MOVW.P 32(R0),R2 | |
| 82 | + CMP.S R0,R1 | |
| 83 | + BNE _cfloop | |
| 84 | + | |
| 85 | + /* drain write buffer and invalidate i&d cache contents */ | |
| 86 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4 | |
| 87 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0 | |
| 88 | + | |
| 89 | + /* drain prefetch */ | |
| 90 | + MOVW R0,R0 | |
| 91 | + MOVW R0,R0 | |
| 92 | + MOVW R0,R0 | |
| 93 | + MOVW R0,R0 | |
| 94 | + | |
| 95 | + /* disable caches */ | |
| 96 | + MRC CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 97 | + BIC $(CpCdcache|CpCicache|CpCwb), R0 | |
| 98 | + MCR CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 99 | + RET | |
| @@ -0,0 +1,48 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "fns.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "mem.h" | |
| 6 | + | |
| 7 | +void | |
| 8 | +main(void) | |
| 9 | +{ | |
| 10 | + void (*f)(void); | |
| 11 | + ulong *kernel; | |
| 12 | + | |
| 13 | + print("inflating kernel\n"); | |
| 14 | + | |
| 15 | + kernel = (ulong*)(0xc0200000+20*1024); | |
| 16 | + if(gunzip((uchar*)0xc0008000, 2*1024*1024, (uchar*)kernel, FLATESIZE) > 0){ | |
| 17 | + f = (void (*)(void))0xc0008010; | |
| 18 | + draincache(); | |
| 19 | + } else { | |
| 20 | + print("inflation failed\n"); | |
| 21 | + f = nil; | |
| 22 | + } | |
| 23 | + (*f)(); | |
| 24 | +} | |
| 25 | + | |
| 26 | +void | |
| 27 | +exit(void) | |
| 28 | +{ | |
| 29 | + | |
| 30 | + void (*f)(void); | |
| 31 | + | |
| 32 | + delay(1000); | |
| 33 | + | |
| 34 | + print("it's a wonderful day to die\n"); | |
| 35 | + f = nil; | |
| 36 | + (*f)(); | |
| 37 | +} | |
| 38 | + | |
| 39 | +void | |
| 40 | +delay(int ms) | |
| 41 | +{ | |
| 42 | + int i; | |
| 43 | + | |
| 44 | + while(ms-- > 0){ | |
| 45 | + for(i = 0; i < 1000; i++) | |
| 46 | + ; | |
| 47 | + } | |
| 48 | +} | |
| @@ -0,0 +1,208 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | +#include <flate.h> | |
| 8 | + | |
| 9 | +typedef struct Biobuf Biobuf; | |
| 10 | + | |
| 11 | +struct Biobuf | |
| 12 | +{ | |
| 13 | + uchar *bp; | |
| 14 | + uchar *p; | |
| 15 | + uchar *ep; | |
| 16 | +}; | |
| 17 | + | |
| 18 | +static int header(Biobuf*); | |
| 19 | +static int trailer(Biobuf*, Biobuf*); | |
| 20 | +static int getc(void*); | |
| 21 | +static ulong offset(Biobuf*); | |
| 22 | +static int crcwrite(void *out, void *buf, int n); | |
| 23 | +static ulong get4(Biobuf *b); | |
| 24 | +static ulong Boffset(Biobuf *bp); | |
| 25 | + | |
| 26 | +/* GZIP flags */ | |
| 27 | +enum { | |
| 28 | + Ftext= (1<<0), | |
| 29 | + Fhcrc= (1<<1), | |
| 30 | + Fextra= (1<<2), | |
| 31 | + Fname= (1<<3), | |
| 32 | + Fcomment= (1<<4), | |
| 33 | + | |
| 34 | + GZCRCPOLY = 0xedb88320UL, | |
| 35 | +}; | |
| 36 | + | |
| 37 | +static ulong *crctab; | |
| 38 | +static ulong crc; | |
| 39 | + | |
| 40 | +int | |
| 41 | +gunzip(uchar *out, int outn, uchar *in, int inn) | |
| 42 | +{ | |
| 43 | + Biobuf bin, bout; | |
| 44 | + int err; | |
| 45 | + | |
| 46 | + crc = 0; | |
| 47 | + crctab = mkcrctab(GZCRCPOLY); | |
| 48 | + err = inflateinit(); | |
| 49 | + if(err != FlateOk) | |
| 50 | + print("inflateinit failed: %s\n", flateerr(err)); | |
| 51 | + | |
| 52 | + bin.bp = bin.p = in; | |
| 53 | + bin.ep = in+inn; | |
| 54 | + bout.bp = bout.p = out; | |
| 55 | + bout.ep = out+outn; | |
| 56 | + | |
| 57 | + err = header(&bin); | |
| 58 | + if(err != FlateOk) | |
| 59 | + return err; | |
| 60 | + | |
| 61 | + err = inflate(&bout, crcwrite, &bin, getc); | |
| 62 | + if(err != FlateOk) | |
| 63 | + print("inflate failed: %s\n", flateerr(err)); | |
| 64 | + | |
| 65 | + err = trailer(&bout, &bin); | |
| 66 | + if(err != FlateOk) | |
| 67 | + return err; | |
| 68 | + | |
| 69 | + return Boffset(&bout); | |
| 70 | +} | |
| 71 | + | |
| 72 | +static int | |
| 73 | +header(Biobuf *bin) | |
| 74 | +{ | |
| 75 | + int i, flag; | |
| 76 | + | |
| 77 | + if(getc(bin) != 0x1f || getc(bin) != 0x8b){ | |
| 78 | + print("bad magic\n"); | |
| 79 | + return FlateCorrupted; | |
| 80 | + } | |
| 81 | + if(getc(bin) != 8){ | |
| 82 | + print("unknown compression type\n"); | |
| 83 | + return FlateCorrupted; | |
| 84 | + } | |
| 85 | + | |
| 86 | + flag = getc(bin); | |
| 87 | + | |
| 88 | + /* mod time */ | |
| 89 | + get4(bin); | |
| 90 | + | |
| 91 | + /* extra flags */ | |
| 92 | + getc(bin); | |
| 93 | + | |
| 94 | + /* OS type */ | |
| 95 | + getc(bin); | |
| 96 | + | |
| 97 | + if(flag & Fextra) | |
| 98 | + for(i=getc(bin); i>0; i--) | |
| 99 | + getc(bin); | |
| 100 | + | |
| 101 | + /* name */ | |
| 102 | + if(flag&Fname) | |
| 103 | + while(getc(bin) != 0) | |
| 104 | + ; | |
| 105 | + | |
| 106 | + /* comment */ | |
| 107 | + if(flag&Fcomment) | |
| 108 | + while(getc(bin) != 0) | |
| 109 | + ; | |
| 110 | + | |
| 111 | + /* crc16 */ | |
| 112 | + if(flag&Fhcrc) { | |
| 113 | + getc(bin); | |
| 114 | + getc(bin); | |
| 115 | + } | |
| 116 | + | |
| 117 | + return FlateOk; | |
| 118 | +} | |
| 119 | + | |
| 120 | +static int | |
| 121 | +trailer(Biobuf *bout, Biobuf *bin) | |
| 122 | +{ | |
| 123 | + /* crc32 */ | |
| 124 | + ulong x; | |
| 125 | + | |
| 126 | + x = get4(bin); | |
| 127 | + if(crc != x){ | |
| 128 | + print("crc mismatch %lux %lux\n", crc, x); | |
| 129 | + return FlateCorrupted; | |
| 130 | + } | |
| 131 | + | |
| 132 | + /* length */ | |
| 133 | + if(get4(bin) != Boffset(bout)){ | |
| 134 | + print("bad output len\n"); | |
| 135 | + return FlateCorrupted; | |
| 136 | + } | |
| 137 | + return FlateOk; | |
| 138 | +} | |
| 139 | + | |
| 140 | +static ulong | |
| 141 | +get4(Biobuf *b) | |
| 142 | +{ | |
| 143 | + ulong v; | |
| 144 | + int i, c; | |
| 145 | + | |
| 146 | + v = 0; | |
| 147 | + for(i = 0; i < 4; i++){ | |
| 148 | + c = getc(b); | |
| 149 | + v |= c << (i * 8); | |
| 150 | + } | |
| 151 | + return v; | |
| 152 | +} | |
| 153 | + | |
| 154 | +static int | |
| 155 | +getc(void *in) | |
| 156 | +{ | |
| 157 | + Biobuf *bp = in; | |
| 158 | + | |
| 159 | + if((bp->p - bp->bp) % 10000 == 0) | |
| 160 | + print("."); | |
| 161 | + if(bp->p >= bp->ep) | |
| 162 | + return -1; | |
| 163 | + return *bp->p++; | |
| 164 | +} | |
| 165 | + | |
| 166 | +static ulong | |
| 167 | +Boffset(Biobuf *bp) | |
| 168 | +{ | |
| 169 | + return bp->p - bp->bp; | |
| 170 | +} | |
| 171 | + | |
| 172 | +static int | |
| 173 | +crcwrite(void *out, void *buf, int n) | |
| 174 | +{ | |
| 175 | + Biobuf *bp; | |
| 176 | + | |
| 177 | + crc = blockcrc(crctab, crc, buf, n); | |
| 178 | + bp = out; | |
| 179 | + if(n > bp->ep-bp->p) | |
| 180 | + n = bp->ep-bp->p; | |
| 181 | + memmove(bp->p, buf, n); | |
| 182 | + bp->p += n; | |
| 183 | + return n; | |
| 184 | +} | |
| 185 | + | |
| 186 | +#undef malloc | |
| 187 | +#undef free | |
| 188 | + | |
| 189 | +static ulong ibrkp = ~0; | |
| 190 | + | |
| 191 | +void * | |
| 192 | +malloc(ulong n) | |
| 193 | +{ | |
| 194 | + ulong rv; | |
| 195 | + | |
| 196 | + if(ibrkp == ~0) | |
| 197 | + ibrkp = ((ulong)end)+1024*1024; | |
| 198 | + n = (n+3)>>2; | |
| 199 | + n <<= 2; | |
| 200 | + rv = ibrkp; | |
| 201 | + ibrkp += n; | |
| 202 | + return (void*)rv; | |
| 203 | +} | |
| 204 | + | |
| 205 | +void | |
| 206 | +free(void *) | |
| 207 | +{ | |
| 208 | +} | |
| @@ -0,0 +1,261 @@ | ||
| 1 | +/* | |
| 2 | + * Definitions for IO devices. Used only in C. | |
| 3 | + */ | |
| 4 | + | |
| 5 | +enum | |
| 6 | +{ | |
| 7 | + /* hardware counter frequency */ | |
| 8 | + ClockFreq= 3686400, | |
| 9 | +}; | |
| 10 | + | |
| 11 | +/* | |
| 12 | + * IRQ's defined by SA1100 | |
| 13 | + */ | |
| 14 | +enum | |
| 15 | +{ | |
| 16 | + IRQgpio0= 0, | |
| 17 | + IRQgpio1= 1, | |
| 18 | + IRQgpio2= 2, | |
| 19 | + IRQgpio3= 3, | |
| 20 | + IRQgpio4= 4, | |
| 21 | + IRQgpio5= 5, | |
| 22 | + IRQgpio6= 6, | |
| 23 | + IRQgpio7= 7, | |
| 24 | + IRQgpio8= 8, | |
| 25 | + IRQgpio9= 9, | |
| 26 | + IRQgpio10= 10, | |
| 27 | + IRQgpiohi= 11, | |
| 28 | + IRQlcd= 12, | |
| 29 | + IRQudc= 13, | |
| 30 | + IRQuart1b= 15, | |
| 31 | + IRQuart2= 16, | |
| 32 | + IRQuart3= 17, | |
| 33 | + IRQmcp= 18, | |
| 34 | + IRQssp= 19, | |
| 35 | + IRQdma0= 20, | |
| 36 | + IRQdma1= 21, | |
| 37 | + IRQdma2= 22, | |
| 38 | + IRQdma3= 23, | |
| 39 | + IRQdma4= 24, | |
| 40 | + IRQdma5= 25, | |
| 41 | + IRQtimer0= 26, | |
| 42 | + IRQtimer1= 27, | |
| 43 | + IRQtimer2= 28, | |
| 44 | + IRQtimer3= 29, | |
| 45 | + IRQsecond= 30, | |
| 46 | + IRQrtc= 31, | |
| 47 | +}; | |
| 48 | + | |
| 49 | +/* | |
| 50 | + * GPIO lines (signal names from compaq document). _i indicates input | |
| 51 | + * and _o output. | |
| 52 | + */ | |
| 53 | +enum | |
| 54 | +{ | |
| 55 | + GPIO_PWR_ON_i= 1<<0, /* power button */ | |
| 56 | + GPIO_UP_IRQ_i= 1<<1, /* microcontroller interrupts */ | |
| 57 | + GPIO_LDD8_o= 1<<2, /* LCD data 8-15 */ | |
| 58 | + GPIO_LDD9_o= 1<<3, | |
| 59 | + GPIO_LDD10_o= 1<<4, | |
| 60 | + GPIO_LDD11_o= 1<<5, | |
| 61 | + GPIO_LDD12_o= 1<<6, | |
| 62 | + GPIO_LDD13_o= 1<<7, | |
| 63 | + GPIO_LDD14_o= 1<<8, | |
| 64 | + GPIO_LDD15_o= 1<<9, | |
| 65 | + GPIO_CARD_IND1_i= 1<<10, /* card inserted in PCMCIA socket 1 */ | |
| 66 | + GPIO_CARD_IRQ1_i= 1<<11, /* PCMCIA socket 1 interrupt */ | |
| 67 | + GPIO_CLK_SET0_o= 1<<12, /* clock selects for audio codec */ | |
| 68 | + GPIO_CLK_SET1_o= 1<<13, | |
| 69 | + GPIO_L3_SDA_io= 1<<14, /* UDA1341 interface */ | |
| 70 | + GPIO_L3_MODE_o= 1<<15, | |
| 71 | + GPIO_L3_SCLK_o= 1<<16, | |
| 72 | + GPIO_CARD_IND0_i= 1<<17, /* card inserted in PCMCIA socket 0 */ | |
| 73 | + GPIO_KEY_ACT_i= 1<<18, /* hot key from cradle */ | |
| 74 | + GPIO_SYS_CLK_i= 1<<19, /* clock from codec */ | |
| 75 | + GPIO_BAT_FAULT_i= 1<<20, /* battery fault */ | |
| 76 | + GPIO_CARD_IRQ0_i= 1<<21, /* PCMCIA socket 0 interrupt */ | |
| 77 | + GPIO_LOCK_i= 1<<22, /* expansion pack lock/unlock */ | |
| 78 | + GPIO_COM_DCD_i= 1<<23, /* DCD from UART3 */ | |
| 79 | + GPIO_OPT_IRQ_i= 1<<24, /* expansion pack IRQ */ | |
| 80 | + GPIO_COM_CTS_i= 1<<25, /* CTS from UART3 */ | |
| 81 | + GPIO_COM_RTS_o= 1<<26, /* RTS to UART3 */ | |
| 82 | + GPIO_OPT_IND_i= 1<<27, /* expansion pack inserted */ | |
| 83 | + | |
| 84 | +/* Peripheral Unit GPIO pin assignments: alternate functions */ | |
| 85 | + GPIO_SSP_TXD_o= 1<<10, /* SSP Transmit Data */ | |
| 86 | + GPIO_SSP_RXD_i= 1<<11, /* SSP Receive Data */ | |
| 87 | + GPIO_SSP_SCLK_o= 1<<12, /* SSP Sample CLocK */ | |
| 88 | + GPIO_SSP_SFRM_o= 1<<13, /* SSP Sample FRaMe */ | |
| 89 | + /* ser. port 1: */ | |
| 90 | + GPIO_UART_TXD_o= 1<<14, /* UART Transmit Data */ | |
| 91 | + GPIO_UART_RXD_i= 1<<15, /* UART Receive Data */ | |
| 92 | + GPIO_SDLC_SCLK_io= 1<<16, /* SDLC Sample CLocK (I/O) */ | |
| 93 | + GPIO_SDLC_AAF_o= 1<<17, /* SDLC Abort After Frame */ | |
| 94 | + GPIO_UART_SCLK1_i= 1<<18, /* UART Sample CLocK 1 */ | |
| 95 | + /* ser. port 4: */ | |
| 96 | + GPIO_SSP_CLK_i= 1<<19, /* SSP external CLocK */ | |
| 97 | + /* ser. port 3: */ | |
| 98 | + GPIO_UART_SCLK3_i= 1<<20, /* UART Sample CLocK 3 */ | |
| 99 | + /* ser. port 4: */ | |
| 100 | + GPIO_MCP_CLK_i= 1<<21, /* MCP CLocK */ | |
| 101 | + /* test controller: */ | |
| 102 | + GPIO_TIC_ACK_o= 1<<21, /* TIC ACKnowledge */ | |
| 103 | + GPIO_MBGNT_o= 1<<21, /* Memory Bus GraNT */ | |
| 104 | + GPIO_TREQA_i= 1<<22, /* TIC REQuest A */ | |
| 105 | + GPIO_MBREQ_i= 1<<22, /* Memory Bus REQuest */ | |
| 106 | + GPIO_TREQB_i= 1<<23, /* TIC REQuest B */ | |
| 107 | + GPIO_1Hz_o= 1<<25, /* 1 Hz clock */ | |
| 108 | + GPIO_RCLK_o= 1<<26, /* internal (R) CLocK (O, fcpu/2) */ | |
| 109 | + GPIO_32_768kHz_o= 1<<27, /* 32.768 kHz clock (O, RTC) */ | |
| 110 | +}; | |
| 111 | + | |
| 112 | +/* | |
| 113 | + * types of interrupts | |
| 114 | + */ | |
| 115 | +enum | |
| 116 | +{ | |
| 117 | + GPIOrising, | |
| 118 | + GPIOfalling, | |
| 119 | + GPIOboth, | |
| 120 | + IRQ, | |
| 121 | +}; | |
| 122 | + | |
| 123 | +/* hardware registers */ | |
| 124 | +typedef struct Uartregs Uartregs; | |
| 125 | +struct Uartregs | |
| 126 | +{ | |
| 127 | + ulong ctl[4]; | |
| 128 | + ulong dummya; | |
| 129 | + ulong data; | |
| 130 | + ulong dummyb; | |
| 131 | + ulong status[2]; | |
| 132 | +}; | |
| 133 | +Uartregs *uart3regs; | |
| 134 | + | |
| 135 | +/* general purpose I/O lines control registers */ | |
| 136 | +typedef struct GPIOregs GPIOregs; | |
| 137 | +struct GPIOregs | |
| 138 | +{ | |
| 139 | + ulong level; /* 1 == high */ | |
| 140 | + ulong direction; /* 1 == output */ | |
| 141 | + ulong set; /* a 1 sets the bit, 0 leaves it alone */ | |
| 142 | + ulong clear; /* a 1 clears the bit, 0 leaves it alone */ | |
| 143 | + ulong rising; /* rising edge detect enable */ | |
| 144 | + ulong falling; /* falling edge detect enable */ | |
| 145 | + ulong edgestatus; /* writing a 1 bit clears */ | |
| 146 | + ulong altfunc; /* turn on alternate function for any set bits */ | |
| 147 | +}; | |
| 148 | + | |
| 149 | +extern GPIOregs *gpioregs; | |
| 150 | + | |
| 151 | +/* extra general purpose I/O bits, output only */ | |
| 152 | +enum | |
| 153 | +{ | |
| 154 | + EGPIO_prog_flash= 1<<0, | |
| 155 | + EGPIO_pcmcia_reset= 1<<1, | |
| 156 | + EGPIO_exppack_reset= 1<<2, | |
| 157 | + EGPIO_codec_reset= 1<<3, | |
| 158 | + EGPIO_exp_nvram_power= 1<<4, | |
| 159 | + EGPIO_exp_full_power= 1<<5, | |
| 160 | + EGPIO_lcd_3v= 1<<6, | |
| 161 | + EGPIO_rs232_power= 1<<7, | |
| 162 | + EGPIO_lcd_ic_power= 1<<8, | |
| 163 | + EGPIO_ir_power= 1<<9, | |
| 164 | + EGPIO_audio_power= 1<<10, | |
| 165 | + EGPIO_audio_ic_power= 1<<11, | |
| 166 | + EGPIO_audio_mute= 1<<12, | |
| 167 | + EGPIO_fir= 1<<13, /* not set is sir */ | |
| 168 | + EGPIO_lcd_5v= 1<<14, | |
| 169 | + EGPIO_lcd_9v= 1<<15, | |
| 170 | +}; | |
| 171 | +extern ulong *egpioreg; | |
| 172 | + | |
| 173 | +/* Peripheral pin controller registers */ | |
| 174 | +typedef struct PPCregs PPCregs; | |
| 175 | +struct PPCregs { | |
| 176 | + ulong direction; | |
| 177 | + ulong state; | |
| 178 | + ulong assignment; | |
| 179 | + ulong sleepdir; | |
| 180 | + ulong flags; | |
| 181 | +}; | |
| 182 | +extern PPCregs *ppcregs; | |
| 183 | + | |
| 184 | +/* Synchronous Serial Port controller registers */ | |
| 185 | +typedef struct SSPregs SSPregs; | |
| 186 | +struct SSPregs { | |
| 187 | + ulong control0; | |
| 188 | + ulong control1; | |
| 189 | + ulong dummy0; | |
| 190 | + ulong data; | |
| 191 | + ulong dummy1; | |
| 192 | + ulong status; | |
| 193 | +}; | |
| 194 | +extern SSPregs *sspregs; | |
| 195 | + | |
| 196 | +/* Multimedia Communications Port controller registers */ | |
| 197 | +typedef struct MCPregs MCPregs; | |
| 198 | +struct MCPregs { | |
| 199 | + ulong control0; | |
| 200 | + ulong reserved0; | |
| 201 | + ulong data0; | |
| 202 | + ulong data1; | |
| 203 | + ulong data2; | |
| 204 | + ulong reserved1; | |
| 205 | + ulong status; | |
| 206 | + ulong reserved[11]; | |
| 207 | + ulong control1; | |
| 208 | +}; | |
| 209 | +extern MCPregs *mcpregs; | |
| 210 | + | |
| 211 | +/* | |
| 212 | + * memory configuration | |
| 213 | + */ | |
| 214 | +enum | |
| 215 | +{ | |
| 216 | + /* bit shifts for pcmcia access time counters */ | |
| 217 | + MECR_io0= 0, | |
| 218 | + MECR_attr0= 5, | |
| 219 | + MECR_mem0= 10, | |
| 220 | + MECR_fast0= 11, | |
| 221 | + MECR_io1= MECR_io0+16, | |
| 222 | + MECR_attr1= MECR_attr0+16, | |
| 223 | + MECR_mem1= MECR_mem0+16, | |
| 224 | + MECR_fast1= MECR_fast0+16, | |
| 225 | +}; | |
| 226 | + | |
| 227 | +typedef struct MemConfRegs MemConfRegs; | |
| 228 | +struct MemConfRegs | |
| 229 | +{ | |
| 230 | + ulong mdcnfg; /* dram */ | |
| 231 | + ulong mdcas00; /* dram banks 0/1 */ | |
| 232 | + ulong mdcas01; | |
| 233 | + ulong mdcas02; | |
| 234 | + ulong msc0; /* static */ | |
| 235 | + ulong msc1; | |
| 236 | + ulong mecr; /* pcmcia */ | |
| 237 | + ulong mdrefr; /* dram refresh */ | |
| 238 | + ulong mdcas20; /* dram banks 2/3 */ | |
| 239 | + ulong mdcas21; | |
| 240 | + ulong mdcas22; | |
| 241 | + ulong msc2; /* static */ | |
| 242 | + ulong smcnfg; /* SMROM config */ | |
| 243 | +}; | |
| 244 | +extern MemConfRegs *memconfregs; | |
| 245 | + | |
| 246 | +/* | |
| 247 | + * power management | |
| 248 | + */ | |
| 249 | +typedef struct PowerRegs PowerRegs; | |
| 250 | +struct PowerRegs | |
| 251 | +{ | |
| 252 | + ulong pmcr; /* Power manager control register */ | |
| 253 | + ulong pssr; /* Power manager sleep status register */ | |
| 254 | + ulong pspr; /* Power manager scratch pad register */ | |
| 255 | + ulong pwer; /* Power manager wakeup enable register */ | |
| 256 | + ulong pcfr; /* Power manager general configuration register */ | |
| 257 | + ulong ppcr; /* Power manager PPL configuration register */ | |
| 258 | + ulong pgsr; /* Power manager GPIO sleep state register */ | |
| 259 | + ulong posr; /* Power manager oscillator status register */ | |
| 260 | +}; | |
| 261 | +extern PowerRegs *powerregs; | |
| @@ -0,0 +1,454 @@ | ||
| 1 | +#include "mem.h" | |
| 2 | + | |
| 3 | +/* | |
| 4 | + * Entered here from Compaq's bootldr with MMU disabled. | |
| 5 | + */ | |
| 6 | +TEXT _start(SB), $-4 | |
| 7 | + MOVW $setR12(SB), R12 /* load the SB */ | |
| 8 | +_main: | |
| 9 | + /* SVC mode, interrupts disabled */ | |
| 10 | + MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R1 | |
| 11 | + MOVW R1, CPSR | |
| 12 | + | |
| 13 | + /* disable the MMU */ | |
| 14 | + MOVW $0x130, R1 | |
| 15 | + MCR CpMMU, 0, R1, C(CpControl), C(0x0) | |
| 16 | + | |
| 17 | + /* flush caches */ | |
| 18 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0 | |
| 19 | + /* drain prefetch */ | |
| 20 | + MOVW R0,R0 | |
| 21 | + MOVW R0,R0 | |
| 22 | + MOVW R0,R0 | |
| 23 | + MOVW R0,R0 | |
| 24 | + | |
| 25 | + /* drain write buffer */ | |
| 26 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4 | |
| 27 | + | |
| 28 | + MOVW $(MACHADDR+BY2PG), R13 /* stack */ | |
| 29 | + SUB $4, R13 /* link */ | |
| 30 | + BL main(SB) | |
| 31 | + BL exit(SB) | |
| 32 | + /* we shouldn't get here */ | |
| 33 | +_mainloop: | |
| 34 | + B _mainloop | |
| 35 | + BL _div(SB) /* hack to get _div etc loaded */ | |
| 36 | + | |
| 37 | +/* flush tlb's */ | |
| 38 | +TEXT mmuinvalidate(SB), $-4 | |
| 39 | + MCR CpMMU, 0, R0, C(CpTLBFlush), C(0x7) | |
| 40 | + RET | |
| 41 | + | |
| 42 | +/* flush tlb's */ | |
| 43 | +TEXT mmuinvalidateaddr(SB), $-4 | |
| 44 | + MCR CpMMU, 0, R0, C(CpTLBFlush), C(0x6), 1 | |
| 45 | + RET | |
| 46 | + | |
| 47 | +/* write back and invalidate i and d caches */ | |
| 48 | +TEXT cacheflush(SB), $-4 | |
| 49 | + /* write back any dirty data */ | |
| 50 | + MOVW $0xe0000000,R0 | |
| 51 | + ADD $(8*1024),R0,R1 | |
| 52 | +_cfloop: | |
| 53 | + MOVW.P 32(R0),R2 | |
| 54 | + CMP.S R0,R1 | |
| 55 | + BNE _cfloop | |
| 56 | + | |
| 57 | + /* drain write buffer and invalidate i&d cache contents */ | |
| 58 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4 | |
| 59 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0 | |
| 60 | + | |
| 61 | + /* drain prefetch */ | |
| 62 | + MOVW R0,R0 | |
| 63 | + MOVW R0,R0 | |
| 64 | + MOVW R0,R0 | |
| 65 | + MOVW R0,R0 | |
| 66 | + RET | |
| 67 | + | |
| 68 | +/* write back d cache */ | |
| 69 | +TEXT cachewb(SB), $-4 | |
| 70 | + /* write back any dirty data */ | |
| 71 | +_cachewb: | |
| 72 | + MOVW $0xe0000000,R0 | |
| 73 | + ADD $(8*1024),R0,R1 | |
| 74 | +_cwbloop: | |
| 75 | + MOVW.P 32(R0),R2 | |
| 76 | + CMP.S R0,R1 | |
| 77 | + BNE _cwbloop | |
| 78 | + | |
| 79 | + /* drain write buffer */ | |
| 80 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4 | |
| 81 | + RET | |
| 82 | + | |
| 83 | +/* write back a single cache line */ | |
| 84 | +TEXT cachewbaddr(SB), $-4 | |
| 85 | + BIC $31,R0 | |
| 86 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 1 | |
| 87 | + B _wbflush | |
| 88 | + | |
| 89 | +/* write back a region of cache lines */ | |
| 90 | +TEXT cachewbregion(SB), $-4 | |
| 91 | + MOVW 4(FP),R1 | |
| 92 | + CMP.S $(4*1024),R1 | |
| 93 | + BGT _cachewb | |
| 94 | + ADD R0,R1 | |
| 95 | + BIC $31,R0 | |
| 96 | +_cwbrloop: | |
| 97 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 1 | |
| 98 | + ADD $32,R0 | |
| 99 | + CMP.S R0,R1 | |
| 100 | + BGT _cwbrloop | |
| 101 | + B _wbflush | |
| 102 | + | |
| 103 | +/* invalidate the dcache */ | |
| 104 | +TEXT dcacheinvalidate(SB), $-4 | |
| 105 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x6) | |
| 106 | + RET | |
| 107 | + | |
| 108 | +/* invalidate the icache */ | |
| 109 | +TEXT icacheinvalidate(SB), $-4 | |
| 110 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x9) | |
| 111 | + RET | |
| 112 | + | |
| 113 | +/* drain write buffer */ | |
| 114 | +TEXT wbflush(SB), $-4 | |
| 115 | +_wbflush: | |
| 116 | + MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4 | |
| 117 | + RET | |
| 118 | + | |
| 119 | +/* return cpu id */ | |
| 120 | +TEXT getcpuid(SB), $-4 | |
| 121 | + MRC CpMMU, 0, R0, C(CpCPUID), C(0x0) | |
| 122 | + RET | |
| 123 | + | |
| 124 | +/* return fault status */ | |
| 125 | +TEXT getfsr(SB), $-4 | |
| 126 | + MRC CpMMU, 0, R0, C(CpFSR), C(0x0) | |
| 127 | + RET | |
| 128 | + | |
| 129 | +/* return fault address */ | |
| 130 | +TEXT getfar(SB), $-4 | |
| 131 | + MRC CpMMU, 0, R0, C(CpFAR), C(0x0) | |
| 132 | + RET | |
| 133 | + | |
| 134 | +/* return fault address */ | |
| 135 | +TEXT putfar(SB), $-4 | |
| 136 | + MRC CpMMU, 0, R0, C(CpFAR), C(0x0) | |
| 137 | + RET | |
| 138 | + | |
| 139 | +/* set the translation table base */ | |
| 140 | +TEXT putttb(SB), $-4 | |
| 141 | + MCR CpMMU, 0, R0, C(CpTTB), C(0x0) | |
| 142 | + RET | |
| 143 | + | |
| 144 | +/* | |
| 145 | + * enable mmu, i and d caches | |
| 146 | + */ | |
| 147 | +TEXT mmuenable(SB), $-4 | |
| 148 | + MRC CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 149 | + ORR $(CpCmmuena|CpCdcache|CpCicache|CpCwb), R0 | |
| 150 | + MCR CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 151 | + RET | |
| 152 | + | |
| 153 | +TEXT mmudisable(SB), $-4 | |
| 154 | + MRC CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 155 | + BIC $(CpCmmuena|CpCdcache|CpCicache|CpCwb|CpCvivec), R0 | |
| 156 | + MCR CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 157 | + RET | |
| 158 | + | |
| 159 | +/* | |
| 160 | + * use exception vectors at 0xffff0000 | |
| 161 | + */ | |
| 162 | +TEXT mappedIvecEnable(SB), $-4 | |
| 163 | + MRC CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 164 | + ORR $(CpCvivec), R0 | |
| 165 | + MCR CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 166 | + RET | |
| 167 | +TEXT mappedIvecDisable(SB), $-4 | |
| 168 | + MRC CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 169 | + BIC $(CpCvivec), R0 | |
| 170 | + MCR CpMMU, 0, R0, C(CpControl), C(0x0) | |
| 171 | + RET | |
| 172 | + | |
| 173 | +/* set the translation table base */ | |
| 174 | +TEXT putdac(SB), $-4 | |
| 175 | + MCR CpMMU, 0, R0, C(CpDAC), C(0x0) | |
| 176 | + RET | |
| 177 | + | |
| 178 | +/* set address translation pid */ | |
| 179 | +TEXT putpid(SB), $-4 | |
| 180 | + MCR CpMMU, 0, R0, C(CpPID), C(0x0) | |
| 181 | + RET | |
| 182 | + | |
| 183 | +/* | |
| 184 | + * set the stack value for the mode passed in R0 | |
| 185 | + */ | |
| 186 | +TEXT setr13(SB), $-4 | |
| 187 | + MOVW 4(FP), R1 | |
| 188 | + | |
| 189 | + MOVW CPSR, R2 | |
| 190 | + BIC $PsrMask, R2, R3 | |
| 191 | + ORR R0, R3 | |
| 192 | + MOVW R3, CPSR | |
| 193 | + | |
| 194 | + MOVW R13, R0 | |
| 195 | + MOVW R1, R13 | |
| 196 | + | |
| 197 | + MOVW R2, CPSR | |
| 198 | + RET | |
| 199 | + | |
| 200 | +/* | |
| 201 | + * exception vectors, copied by trapinit() to somewhere useful | |
| 202 | + */ | |
| 203 | + | |
| 204 | +TEXT vectors(SB), $-4 | |
| 205 | + MOVW 0x18(R15), R15 /* reset */ | |
| 206 | + MOVW 0x18(R15), R15 /* undefined */ | |
| 207 | + MOVW 0x18(R15), R15 /* SWI */ | |
| 208 | + MOVW 0x18(R15), R15 /* prefetch abort */ | |
| 209 | + MOVW 0x18(R15), R15 /* data abort */ | |
| 210 | + MOVW 0x18(R15), R15 /* reserved */ | |
| 211 | + MOVW 0x18(R15), R15 /* IRQ */ | |
| 212 | + MOVW 0x18(R15), R15 /* FIQ */ | |
| 213 | + | |
| 214 | +TEXT vtable(SB), $-4 | |
| 215 | + WORD $_vsvc(SB) /* reset, in svc mode already */ | |
| 216 | + WORD $_vund(SB) /* undefined, switch to svc mode */ | |
| 217 | + WORD $_vsvc(SB) /* swi, in svc mode already */ | |
| 218 | + WORD $_vpabt(SB) /* prefetch abort, switch to svc mode */ | |
| 219 | + WORD $_vdabt(SB) /* data abort, switch to svc mode */ | |
| 220 | + WORD $_vsvc(SB) /* reserved */ | |
| 221 | + WORD $_virq(SB) /* IRQ, switch to svc mode */ | |
| 222 | + WORD $_vfiq(SB) /* FIQ, switch to svc mode */ | |
| 223 | + | |
| 224 | +TEXT _vrst(SB), $-4 | |
| 225 | + BL resettrap(SB) | |
| 226 | + | |
| 227 | +TEXT _vsvc(SB), $-4 /* SWI */ | |
| 228 | + MOVW.W R14, -4(R13) /* ureg->pc = interupted PC */ | |
| 229 | + MOVW SPSR, R14 /* ureg->psr = SPSR */ | |
| 230 | + MOVW.W R14, -4(R13) /* ... */ | |
| 231 | + MOVW $PsrMsvc, R14 /* ureg->type = PsrMsvc */ | |
| 232 | + MOVW.W R14, -4(R13) /* ... */ | |
| 233 | + MOVM.DB.W.S [R0-R14], (R13) /* save user level registers, at end r13 points to ureg */ | |
| 234 | + MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ | |
| 235 | + MOVW R13, R0 /* first arg is pointer to ureg */ | |
| 236 | + SUB $8, R13 /* space for argument+link */ | |
| 237 | + | |
| 238 | + BL syscall(SB) | |
| 239 | + | |
| 240 | + ADD $(8+4*15), R13 /* make r13 point to ureg->type */ | |
| 241 | + MOVW 8(R13), R14 /* restore link */ | |
| 242 | + MOVW 4(R13), R0 /* restore SPSR */ | |
| 243 | + MOVW R0, SPSR /* ... */ | |
| 244 | + MOVM.DB.S (R13), [R0-R14] /* restore registers */ | |
| 245 | + ADD $8, R13 /* pop past ureg->{type+psr} */ | |
| 246 | + RFE /* MOVM.IA.S.W (R13), [R15] */ | |
| 247 | + | |
| 248 | +TEXT _vund(SB), $-4 /* undefined */ | |
| 249 | + MOVM.IA [R0-R4], (R13) /* free some working space */ | |
| 250 | + MOVW $PsrMund, R0 | |
| 251 | + B _vswitch | |
| 252 | + | |
| 253 | +TEXT _vpabt(SB), $-4 /* prefetch abort */ | |
| 254 | + MOVM.IA [R0-R4], (R13) /* free some working space */ | |
| 255 | + MOVW $PsrMabt, R0 /* r0 = type */ | |
| 256 | + B _vswitch | |
| 257 | + | |
| 258 | +TEXT _vdabt(SB), $-4 /* prefetch abort */ | |
| 259 | + MOVM.IA [R0-R4], (R13) /* free some working space */ | |
| 260 | + MOVW $(PsrMabt+1), R0 /* r0 = type */ | |
| 261 | + B _vswitch | |
| 262 | + | |
| 263 | +TEXT _virq(SB), $-4 /* IRQ */ | |
| 264 | + MOVM.IA [R0-R4], (R13) /* free some working space */ | |
| 265 | + MOVW $PsrMirq, R0 /* r0 = type */ | |
| 266 | + B _vswitch | |
| 267 | + | |
| 268 | + /* | |
| 269 | + * come here with type in R0 and R13 pointing above saved [r0-r4] | |
| 270 | + * and type in r0. we'll switch to SVC mode and then call trap. | |
| 271 | + */ | |
| 272 | +_vswitch: | |
| 273 | + MOVW SPSR, R1 /* save SPSR for ureg */ | |
| 274 | + MOVW R14, R2 /* save interrupted pc for ureg */ | |
| 275 | + MOVW R13, R3 /* save pointer to where the original [R0-R3] are */ | |
| 276 | + | |
| 277 | + /* switch to svc mode */ | |
| 278 | + MOVW CPSR, R14 | |
| 279 | + BIC $PsrMask, R14 | |
| 280 | + ORR $(PsrDirq|PsrDfiq|PsrMsvc), R14 | |
| 281 | + MOVW R14, CPSR | |
| 282 | + | |
| 283 | + /* interupted code kernel or user? */ | |
| 284 | + AND.S $0xf, R1, R4 | |
| 285 | + BEQ _userexcep | |
| 286 | + | |
| 287 | + /* here for trap from SVC mode */ | |
| 288 | + MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */ | |
| 289 | + MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */ | |
| 290 | + MOVM.DB.W [R0-R14], (R13) /* save kernel level registers, at end r13 points to ureg */ | |
| 291 | + MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ | |
| 292 | + MOVW R13, R0 /* first arg is pointer to ureg */ | |
| 293 | + SUB $8, R13 /* space for argument+link (for debugger) */ | |
| 294 | + MOVW $0xdeaddead,R11 /* marker */ | |
| 295 | + | |
| 296 | + BL trap(SB) | |
| 297 | + | |
| 298 | + ADD $(8+4*15), R13 /* make r13 point to ureg->type */ | |
| 299 | + MOVW 8(R13), R14 /* restore link */ | |
| 300 | + MOVW 4(R13), R0 /* restore SPSR */ | |
| 301 | + MOVW R0, SPSR /* ... */ | |
| 302 | + MOVM.DB (R13), [R0-R14] /* restore registers */ | |
| 303 | + ADD $8, R13 /* pop past ureg->{type+psr} */ | |
| 304 | + RFE /* MOVM.IA.S.W (R13), [R15] */ | |
| 305 | + | |
| 306 | + /* here for trap from USER mode */ | |
| 307 | +_userexcep: | |
| 308 | + MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */ | |
| 309 | + MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */ | |
| 310 | + MOVM.DB.W.S [R0-R14], (R13) /* save kernel level registers, at end r13 points to ureg */ | |
| 311 | + MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ | |
| 312 | + MOVW R13, R0 /* first arg is pointer to ureg */ | |
| 313 | + SUB $8, R13 /* space for argument+link (for debugger) */ | |
| 314 | + | |
| 315 | + BL trap(SB) | |
| 316 | + | |
| 317 | + ADD $(8+4*15), R13 /* make r13 point to ureg->type */ | |
| 318 | + MOVW 8(R13), R14 /* restore link */ | |
| 319 | + MOVW 4(R13), R0 /* restore SPSR */ | |
| 320 | + MOVW R0, SPSR /* ... */ | |
| 321 | + MOVM.DB.S (R13), [R0-R14] /* restore registers */ | |
| 322 | + ADD $8, R13 /* pop past ureg->{type+psr} */ | |
| 323 | + RFE /* MOVM.IA.S.W (R13), [R15] */ | |
| 324 | + | |
| 325 | +TEXT _vfiq(SB), $-4 /* FIQ */ | |
| 326 | + RFE /* FIQ is special, ignore it for now */ | |
| 327 | + | |
| 328 | +/* | |
| 329 | + * This is the first jump from kernel to user mode. | |
| 330 | + * Fake a return from interrupt. | |
| 331 | + * | |
| 332 | + * Enter with R0 containing the user stack pointer. | |
| 333 | + * UTZERO + 0x20 is always the entry point. | |
| 334 | + * | |
| 335 | + */ | |
| 336 | +TEXT touser(SB),$-4 | |
| 337 | + /* store the user stack pointer into the USR_r13 */ | |
| 338 | + MOVM.DB.W [R0], (R13) | |
| 339 | + MOVM.S.IA.W (R13),[R13] | |
| 340 | + | |
| 341 | + /* set up a PSR for user level */ | |
| 342 | + MOVW $(PsrMusr), R0 | |
| 343 | + MOVW R0,SPSR | |
| 344 | + | |
| 345 | + /* save the PC on the stack */ | |
| 346 | + MOVW $(UTZERO+0x20), R0 | |
| 347 | + MOVM.DB.W [R0],(R13) | |
| 348 | + | |
| 349 | + /* return from interrupt */ | |
| 350 | + RFE /* MOVM.IA.S.W (R13), [R15] */ | |
| 351 | + | |
| 352 | +/* | |
| 353 | + * here to jump to a newly forked process | |
| 354 | + */ | |
| 355 | +TEXT forkret(SB),$-4 | |
| 356 | + ADD $(4*15), R13 /* make r13 point to ureg->type */ | |
| 357 | + MOVW 8(R13), R14 /* restore link */ | |
| 358 | + MOVW 4(R13), R0 /* restore SPSR */ | |
| 359 | + MOVW R0, SPSR /* ... */ | |
| 360 | + MOVM.DB.S (R13), [R0-R14] /* restore registers */ | |
| 361 | + ADD $8, R13 /* pop past ureg->{type+psr} */ | |
| 362 | + RFE /* MOVM.IA.S.W (R13), [R15] */ | |
| 363 | + | |
| 364 | +TEXT splhi(SB), $-4 | |
| 365 | + /* save caller pc in Mach */ | |
| 366 | + MOVW $(MACHADDR+0x04),R2 | |
| 367 | + MOVW R14,0(R2) | |
| 368 | + /* turn off interrupts */ | |
| 369 | + MOVW CPSR, R0 | |
| 370 | + ORR $(PsrDfiq|PsrDirq), R0, R1 | |
| 371 | + MOVW R1, CPSR | |
| 372 | + RET | |
| 373 | + | |
| 374 | +TEXT spllo(SB), $-4 | |
| 375 | + MOVW CPSR, R0 | |
| 376 | + BIC $(PsrDfiq|PsrDirq), R0, R1 | |
| 377 | + MOVW R1, CPSR | |
| 378 | + RET | |
| 379 | + | |
| 380 | +TEXT splx(SB), $-4 | |
| 381 | + /* save caller pc in Mach */ | |
| 382 | + MOVW $(MACHADDR+0x04),R2 | |
| 383 | + MOVW R14,0(R2) | |
| 384 | + /* reset interrupt level */ | |
| 385 | + MOVW R0, R1 | |
| 386 | + MOVW CPSR, R0 | |
| 387 | + MOVW R1, CPSR | |
| 388 | + RET | |
| 389 | + | |
| 390 | +TEXT splxpc(SB), $-4 /* for iunlock */ | |
| 391 | + MOVW R0, R1 | |
| 392 | + MOVW CPSR, R0 | |
| 393 | + MOVW R1, CPSR | |
| 394 | + RET | |
| 395 | + | |
| 396 | +TEXT spldone(SB), $0 | |
| 397 | + RET | |
| 398 | + | |
| 399 | +TEXT islo(SB), $-4 | |
| 400 | + MOVW CPSR, R0 | |
| 401 | + AND $(PsrDfiq|PsrDirq), R0 | |
| 402 | + EOR $(PsrDfiq|PsrDirq), R0 | |
| 403 | + RET | |
| 404 | + | |
| 405 | +TEXT cpsrr(SB), $-4 | |
| 406 | + MOVW CPSR, R0 | |
| 407 | + RET | |
| 408 | + | |
| 409 | +TEXT spsrr(SB), $-4 | |
| 410 | + MOVW SPSR, R0 | |
| 411 | + RET | |
| 412 | + | |
| 413 | +TEXT getcallerpc(SB), $-4 | |
| 414 | + MOVW 0(R13), R0 | |
| 415 | + RET | |
| 416 | + | |
| 417 | +TEXT tas(SB), $-4 | |
| 418 | + MOVW R0, R1 | |
| 419 | + MOVW $0xDEADDEAD, R2 | |
| 420 | + SWPW R2, (R1), R0 | |
| 421 | + RET | |
| 422 | + | |
| 423 | +TEXT setlabel(SB), $-4 | |
| 424 | + MOVW R13, 0(R0) /* sp */ | |
| 425 | + MOVW R14, 4(R0) /* pc */ | |
| 426 | + MOVW $0, R0 | |
| 427 | + RET | |
| 428 | + | |
| 429 | +TEXT gotolabel(SB), $-4 | |
| 430 | + MOVW 0(R0), R13 /* sp */ | |
| 431 | + MOVW 4(R0), R14 /* pc */ | |
| 432 | + MOVW $1, R0 | |
| 433 | + RET | |
| 434 | + | |
| 435 | + | |
| 436 | +/* The first MCR instruction of this function needs to be on a cache-line | |
| 437 | + * boundary; to make this happen, it will be copied (in trap.c). | |
| 438 | + * | |
| 439 | + * Doze puts the machine into idle mode. Any interrupt will get it out | |
| 440 | + * at the next instruction (the RET, to be precise). | |
| 441 | + */ | |
| 442 | +TEXT _doze(SB), $-4 | |
| 443 | + MOVW $UCDRAMZERO, R1 | |
| 444 | + MOVW R0,R0 | |
| 445 | + MOVW R0,R0 | |
| 446 | + MOVW R0,R0 | |
| 447 | + MOVW R0,R0 | |
| 448 | + MOVW R0,R0 | |
| 449 | + MOVW R0,R0 | |
| 450 | + MOVW R0,R0 | |
| 451 | + MCR CpPWR, 0, R0, C(CpTest), C(0x2), 2 | |
| 452 | + MOVW (R1), R0 | |
| 453 | + MCR CpPWR, 0, R0, C(CpTest), C(0x8), 2 | |
| 454 | + RET | |
| @@ -0,0 +1,143 @@ | ||
| 1 | +/* | |
| 2 | + * functions (possibly) linked in, complete, from libc. | |
| 3 | + */ | |
| 4 | + | |
| 5 | +/* | |
| 6 | + * mem routines | |
| 7 | + */ | |
| 8 | +extern void *memccpy(void*, void*, int, long); | |
| 9 | +extern void *memset(void*, int, long); | |
| 10 | +extern int memcmp(void*, void*, long); | |
| 11 | +extern void *memmove(void*, void*, long); | |
| 12 | +extern void *memchr(void*, int, long); | |
| 13 | + | |
| 14 | +/* | |
| 15 | + * string routines | |
| 16 | + */ | |
| 17 | +extern char *strcat(char*, char*); | |
| 18 | +extern char *strchr(char*, char); | |
| 19 | +extern char *strrchr(char*, char); | |
| 20 | +extern int strcmp(char*, char*); | |
| 21 | +extern char *strcpy(char*, char*); | |
| 22 | +extern char *strncat(char*, char*, long); | |
| 23 | +extern char *strncpy(char*, char*, long); | |
| 24 | +extern int strncmp(char*, char*, long); | |
| 25 | +extern long strlen(char*); | |
| 26 | +extern char* strstr(char*, char*); | |
| 27 | +extern int atoi(char*); | |
| 28 | + | |
| 29 | +enum | |
| 30 | +{ | |
| 31 | + UTFmax = 3, /* maximum bytes per rune */ | |
| 32 | + Runesync = 0x80, /* cannot represent part of a UTF sequence */ | |
| 33 | + Runeself = 0x80, /* rune and UTF sequences are the same (<) */ | |
| 34 | + Runeerror = 0x80, /* decoding error in UTF */ | |
| 35 | +}; | |
| 36 | + | |
| 37 | +/* | |
| 38 | + * rune routines | |
| 39 | + */ | |
| 40 | +extern int runetochar(char*, Rune*); | |
| 41 | +extern int chartorune(Rune*, char*); | |
| 42 | +extern char* utfrune(char*, long); | |
| 43 | +extern int utflen(char*); | |
| 44 | +extern int runelen(long); | |
| 45 | + | |
| 46 | +extern int abs(int); | |
| 47 | + | |
| 48 | +/* | |
| 49 | + * print routines | |
| 50 | + */ | |
| 51 | +typedef struct Cconv Fconv; | |
| 52 | +extern char* donprint(char*, char*, char*, void*); | |
| 53 | +extern int sprint(char*, char*, ...); | |
| 54 | +extern char* seprint(char*, char*, char*, ...); | |
| 55 | +extern int snprint(char*, int, char*, ...); | |
| 56 | +extern int print(char*, ...); | |
| 57 | + | |
| 58 | +/* | |
| 59 | + * one-of-a-kind | |
| 60 | + */ | |
| 61 | +extern char* cleanname(char*); | |
| 62 | +extern ulong getcallerpc(void*); | |
| 63 | +extern long strtol(char*, char**, int); | |
| 64 | +extern ulong strtoul(char*, char**, int); | |
| 65 | +extern vlong strtoll(char*, char**, int); | |
| 66 | +extern uvlong strtoull(char*, char**, int); | |
| 67 | +extern char etext[]; | |
| 68 | +extern char edata[]; | |
| 69 | +extern char end[]; | |
| 70 | +extern int getfields(char*, char**, int, int, char*); | |
| 71 | + | |
| 72 | +/* | |
| 73 | + * Syscall data structures | |
| 74 | + */ | |
| 75 | +#define MORDER 0x0003 /* mask for bits defining order of mounting */ | |
| 76 | +#define MREPL 0x0000 /* mount replaces object */ | |
| 77 | +#define MBEFORE 0x0001 /* mount goes before others in union directory */ | |
| 78 | +#define MAFTER 0x0002 /* mount goes after others in union directory */ | |
| 79 | +#define MCREATE 0x0004 /* permit creation in mounted directory */ | |
| 80 | +#define MCACHE 0x0010 /* cache some data */ | |
| 81 | +#define MMASK 0x001F /* all bits on */ | |
| 82 | + | |
| 83 | +#define OREAD 0 /* open for read */ | |
| 84 | +#define OWRITE 1 /* write */ | |
| 85 | +#define ORDWR 2 /* read and write */ | |
| 86 | +#define OEXEC 3 /* execute, == read but check execute permission */ | |
| 87 | +#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ | |
| 88 | +#define OCEXEC 32 /* or'ed in, close on exec */ | |
| 89 | +#define ORCLOSE 64 /* or'ed in, remove on close */ | |
| 90 | + | |
| 91 | +#define NCONT 0 /* continue after note */ | |
| 92 | +#define NDFLT 1 /* terminate after note */ | |
| 93 | +#define NSAVE 2 /* clear note but hold state */ | |
| 94 | +#define NRSTR 3 /* restore saved state */ | |
| 95 | + | |
| 96 | +typedef struct Qid Qid; | |
| 97 | +typedef struct Dir Dir; | |
| 98 | +typedef struct Waitmsg Waitmsg; | |
| 99 | + | |
| 100 | +#define ERRLEN 64 | |
| 101 | +#define DIRLEN 116 | |
| 102 | +#define NAMELEN 28 | |
| 103 | + | |
| 104 | +struct Qid | |
| 105 | +{ | |
| 106 | + ulong path; | |
| 107 | + ulong vers; | |
| 108 | +}; | |
| 109 | + | |
| 110 | +struct Dir | |
| 111 | +{ | |
| 112 | + char name[NAMELEN]; | |
| 113 | + char uid[NAMELEN]; | |
| 114 | + char gid[NAMELEN]; | |
| 115 | + Qid qid; | |
| 116 | + ulong mode; | |
| 117 | + long atime; | |
| 118 | + long mtime; | |
| 119 | + vlong length; | |
| 120 | + short type; | |
| 121 | + short dev; | |
| 122 | +}; | |
| 123 | + | |
| 124 | +struct Waitmsg | |
| 125 | +{ | |
| 126 | + char pid[12]; /* of loved one */ | |
| 127 | + char time[3*12]; /* of loved one and descendants */ | |
| 128 | + char msg[ERRLEN]; | |
| 129 | +}; | |
| 130 | + | |
| 131 | +/* | |
| 132 | + * locks | |
| 133 | + */ | |
| 134 | +typedef | |
| 135 | +struct Lock { | |
| 136 | + int val; | |
| 137 | +} Lock; | |
| 138 | + | |
| 139 | +extern int _tas(int*); | |
| 140 | + | |
| 141 | +extern void lock(Lock*); | |
| 142 | +extern void unlock(Lock*); | |
| 143 | +extern int canlock(Lock*); | |
| @@ -0,0 +1,10 @@ | ||
| 1 | +defn acidmap() | |
| 2 | +{ | |
| 3 | + local dfoffset; | |
| 4 | + | |
| 5 | + dfoffset = map()[1][3]; | |
| 6 | + map({"text", _start, etext, 0x20}); | |
| 7 | + map({"data", etext+1, edata, dfoffset}); | |
| 8 | + print("Set map for plan 9 kernel image\n"); | |
| 9 | + print("btext ", _start, " etext ", etext, "\n"); | |
| 10 | +} | |
| @@ -0,0 +1,215 @@ | ||
| 1 | +/* | |
| 2 | + * Memory and machine-specific definitions. Used in C and assembler. | |
| 3 | + */ | |
| 4 | + | |
| 5 | +/* | |
| 6 | + * Sizes | |
| 7 | + */ | |
| 8 | +#define BI2BY 8 /* bits per byte */ | |
| 9 | +#define BI2WD 32 /* bits per word */ | |
| 10 | +#define BY2WD 4 /* bytes per word */ | |
| 11 | +#define BY2V 8 /* bytes per double word */ | |
| 12 | +#define BY2PG 4096 /* bytes per page */ | |
| 13 | +#define WD2PG (BY2PG/BY2WD) /* words per page */ | |
| 14 | +#define PGSHIFT 12 /* log(BY2PG) */ | |
| 15 | +#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1)) | |
| 16 | +#define PGROUND(s) ROUND(s, BY2PG) | |
| 17 | +#define BLOCKALIGN 8 | |
| 18 | + | |
| 19 | +#define MAXMACH 1 /* max # cpus system can run */ | |
| 20 | + | |
| 21 | +/* | |
| 22 | + * Time | |
| 23 | + */ | |
| 24 | +#define HZ (20) /* clock frequency */ | |
| 25 | +#define MS2HZ (1000/HZ) /* millisec per clock tick */ | |
| 26 | +#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */ | |
| 27 | +#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */ | |
| 28 | +#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */ | |
| 29 | + | |
| 30 | +/* | |
| 31 | + * Virtual addresses: | |
| 32 | + * | |
| 33 | + * We direct map all discovered DRAM and the area twixt 0xe0000000 and | |
| 34 | + * 0xe8000000 used to provide zeros for cache flushing. | |
| 35 | + * | |
| 36 | + * Flash is mapped to 0xb0000000 and special registers are mapped | |
| 37 | + * on demand to areas starting at 0xa0000000. | |
| 38 | + * | |
| 39 | + * The direct mapping is convenient but not necessary. It means | |
| 40 | + * that we don't have to turn on the MMU till well into the | |
| 41 | + * kernel. This can be changed by providing a mapping in l.s | |
| 42 | + * before calling main. | |
| 43 | + */ | |
| 44 | +#define UZERO 0 /* base of user address space */ | |
| 45 | +#define UTZERO (UZERO+BY2PG) /* first address in user text */ | |
| 46 | +#define KZERO 0xC0000000 /* base of kernel address space */ | |
| 47 | +#define KTZERO 0xC0008000 /* first address in kernel text */ | |
| 48 | +#define EMEMZERO 0x90000000 /* 256 meg for add on memory */ | |
| 49 | +#define EMEMTOP 0xA0000000 /* ... */ | |
| 50 | +#define REGZERO 0xA0000000 /* 128 meg for mapspecial regs */ | |
| 51 | +#define REGTOP 0xA8000000 /* ... */ | |
| 52 | +#define FLASHZERO 0xB0000000 /* 128 meg for flash */ | |
| 53 | +#define FLASHTOP 0xB8000000 /* ... */ | |
| 54 | +#define DRAMZERO 0xC0000000 /* 128 meg for dram */ | |
| 55 | +#define DRAMTOP 0xC8000000 /* ... */ | |
| 56 | +#define UCDRAMZERO 0xC8000000 /* 128 meg for dram (uncached/unbuffered) */ | |
| 57 | +#define UCDRAMTOP 0xD0000000 /* ... */ | |
| 58 | +#define NULLZERO 0xE0000000 /* 128 meg for cache flush zeroes */ | |
| 59 | +#define NULLTOP 0xE8000000 /* ... */ | |
| 60 | +#define USTKTOP 0x2000000 /* byte just beyond user stack */ | |
| 61 | +#define USTKSIZE (8*1024*1024) /* size of user stack */ | |
| 62 | +#define TSTKTOP (USTKTOP-USTKSIZE) /* end of new stack in sysexec */ | |
| 63 | +#define TSTKSIZ 100 | |
| 64 | +#define MACHADDR (KZERO+0x00001000) | |
| 65 | +#define EVECTORS 0xFFFF0000 /* virt base of exception vectors */ | |
| 66 | + | |
| 67 | +#define KSTACK (16*1024) /* Size of kernel stack */ | |
| 68 | + | |
| 69 | +#define FLATESIZE (700*1024) /* maximum size of compressed image */ | |
| 70 | + | |
| 71 | +/* | |
| 72 | + * Offsets into flash | |
| 73 | + */ | |
| 74 | +#define Flash_bootldr (FLASHZERO+0x0) /* boot loader */ | |
| 75 | +#define Flash_kernel (FLASHZERO+0x10000) /* boot kernel */ | |
| 76 | +#define Flash_tar (FLASHZERO+0x100000) /* tar file containing fs.sac */ | |
| 77 | + | |
| 78 | +/* | |
| 79 | + * virtual MMU | |
| 80 | + */ | |
| 81 | +#define PTEMAPMEM (1024*1024) | |
| 82 | +#define PTEPERTAB (PTEMAPMEM/BY2PG) | |
| 83 | +#define SEGMAPSIZE 1984 | |
| 84 | +#define SSEGMAPSIZE 16 | |
| 85 | +#define PPN(x) ((x)&~(BY2PG-1)) | |
| 86 | + | |
| 87 | +/* | |
| 88 | + * SA1110 definitions | |
| 89 | + */ | |
| 90 | + | |
| 91 | +/* | |
| 92 | + * memory physical addresses | |
| 93 | + */ | |
| 94 | +#define PHYSFLASH0 0x00000000 | |
| 95 | +#define PHYSDRAM0 0xC0000000 | |
| 96 | +#define PHYSNULL0 0xE0000000 | |
| 97 | + | |
| 98 | +/* | |
| 99 | + * peripheral control module physical addresses | |
| 100 | + */ | |
| 101 | +#define USBREGS 0x80000000 /* serial port 0 - USB */ | |
| 102 | +#define UART1REGS 0x80010000 /* serial port 1 - UART */ | |
| 103 | +#define GPCLKREGS 0x80020060 /* serial port 1 - general purpose clock */ | |
| 104 | +#define UART2REGS 0x80030000 /* serial port 2 - low speed IR */ | |
| 105 | +#define HSSPREGS 0x80040060 /* serial port 2 - high speed IR */ | |
| 106 | +#define UART3REGS 0x80050000 /* serial port 3 - RS232 UART */ | |
| 107 | +#define MCPREGS 0x80060000 /* serial port 4 - multimedia comm port */ | |
| 108 | +#define SSPREGS 0x80070060 /* serial port 4 - synchronous serial port */ | |
| 109 | +#define OSTIMERREGS 0x90000000 /* operating system timer registers */ | |
| 110 | +#define POWERREGS 0x90020000 /* power management */ | |
| 111 | +#define GPIOREGS 0x90040000 /* 28 general purpose IO pins */ | |
| 112 | +#define INTRREGS 0x90050000 /* interrupt registers */ | |
| 113 | +#define PPCREGS 0x90060000 /* peripheral pin controller */ | |
| 114 | +#define MEMCONFREGS 0xA0000000 /* memory configuration */ | |
| 115 | +#define LCDREGS 0xB0100000 /* display */ | |
| 116 | + | |
| 117 | +/* | |
| 118 | + * PCMCIA addresses | |
| 119 | + */ | |
| 120 | +#define PHYSPCM0REGS 0x20000000 | |
| 121 | +#define PYHSPCM0ATTR 0x28000000 | |
| 122 | +#define PYHSPCM0MEM 0x2C000000 | |
| 123 | +#define PHYSPCM1REGS 0x30000000 | |
| 124 | +#define PYHSPCM1ATTR 0x38000000 | |
| 125 | +#define PYHSPCM1MEM 0x3C000000 | |
| 126 | + | |
| 127 | +/* | |
| 128 | + * Program Status Registers | |
| 129 | + */ | |
| 130 | +#define PsrMusr 0x00000010 /* mode */ | |
| 131 | +#define PsrMfiq 0x00000011 | |
| 132 | +#define PsrMirq 0x00000012 | |
| 133 | +#define PsrMsvc 0x00000013 | |
| 134 | +#define PsrMabt 0x00000017 | |
| 135 | +#define PsrMund 0x0000001B | |
| 136 | +#define PsrMask 0x0000001F | |
| 137 | + | |
| 138 | +#define PsrDfiq 0x00000040 /* disable FIQ interrupts */ | |
| 139 | +#define PsrDirq 0x00000080 /* disable IRQ interrupts */ | |
| 140 | + | |
| 141 | +#define PsrV 0x10000000 /* overflow */ | |
| 142 | +#define PsrC 0x20000000 /* carry/borrow/extend */ | |
| 143 | +#define PsrZ 0x40000000 /* zero */ | |
| 144 | +#define PsrN 0x80000000 /* negative/less than */ | |
| 145 | + | |
| 146 | +/* | |
| 147 | + * Coprocessors | |
| 148 | + */ | |
| 149 | +#define CpMMU 15 | |
| 150 | +#define CpPWR 15 | |
| 151 | + | |
| 152 | +/* | |
| 153 | + * Internal MMU coprocessor registers | |
| 154 | + */ | |
| 155 | +#define CpCPUID 0 /* R: */ | |
| 156 | +#define CpControl 1 /* R: */ | |
| 157 | +#define CpTTB 2 /* RW: translation table base */ | |
| 158 | +#define CpDAC 3 /* RW: domain access control */ | |
| 159 | +#define CpFSR 5 /* RW: fault status */ | |
| 160 | +#define CpFAR 6 /* RW: fault address */ | |
| 161 | +#define CpCacheFlush 7 /* W: cache flushing, wb draining*/ | |
| 162 | +#define CpTLBFlush 8 /* W: TLB flushing */ | |
| 163 | +#define CpRBFlush 9 /* W: Read Buffer ops */ | |
| 164 | +#define CpPID 13 /* RW: PID for virtual mapping */ | |
| 165 | +#define CpBpt 14 /* W: Breakpoint register */ | |
| 166 | +#define CpTest 15 /* W: Test, Clock and Idle Control */ | |
| 167 | + | |
| 168 | +/* | |
| 169 | + * CpControl | |
| 170 | + */ | |
| 171 | +#define CpCmmuena 0x00000001 /* M: MMU enable */ | |
| 172 | +#define CpCalign 0x00000002 /* A: alignment fault enable */ | |
| 173 | +#define CpCdcache 0x00000004 /* C: data cache on */ | |
| 174 | +#define CpCwb 0x00000008 /* W: write buffer turned on */ | |
| 175 | +#define CpCi32 0x00000010 /* P: 32-bit program space */ | |
| 176 | +#define CpCd32 0x00000020 /* D: 32-bit data space */ | |
| 177 | +#define CpCbe 0x00000080 /* B: big-endian operation */ | |
| 178 | +#define CpCsystem 0x00000100 /* S: system permission */ | |
| 179 | +#define CpCrom 0x00000200 /* R: ROM permission */ | |
| 180 | +#define CpCicache 0x00001000 /* I: instruction cache on */ | |
| 181 | +#define CpCvivec 0x00002000 /* X: virtual interrupt vector adjust */ | |
| 182 | + | |
| 183 | +/* | |
| 184 | + * fault codes | |
| 185 | + */ | |
| 186 | +#define FCterm 0x2 /* terminal */ | |
| 187 | +#define FCvec 0x0 /* vector */ | |
| 188 | +#define FCalignf 0x1 /* unaligned full word data access */ | |
| 189 | +#define FCalignh 0x3 /* unaligned half word data access */ | |
| 190 | +#define FCl1abort 0xc /* level 1 external abort on translation */ | |
| 191 | +#define FCl2abort 0xe /* level 2 external abort on translation */ | |
| 192 | +#define FCtransSec 0x5 /* section translation */ | |
| 193 | +#define FCtransPage 0x7 /* page translation */ | |
| 194 | +#define FCdomainSec 0x9 /* section domain */ | |
| 195 | +#define FCdomainPage 0x11 /* page domain */ | |
| 196 | +#define FCpermSec 0x9 /* section permissions */ | |
| 197 | +#define FCpermPage 0x11 /* page permissions */ | |
| 198 | +#define FCabortLFSec 0x4 /* external abort on linefetch for section */ | |
| 199 | +#define FCabortLFPage 0x6 /* external abort on linefetch for page */ | |
| 200 | +#define FCabortNLFSec 0x8 /* external abort on non-linefetch for section */ | |
| 201 | +#define FCabortNLFPage 0xa /* external abort on non-linefetch for page */ | |
| 202 | + | |
| 203 | +/* | |
| 204 | + * PTE bits used by fault.h. mmu.c translates them to real values. | |
| 205 | + */ | |
| 206 | +#define PTEVALID (1<<0) | |
| 207 | +#define PTERONLY 0 /* this is implied by the absence of PTEWRITE */ | |
| 208 | +#define PTEWRITE (1<<1) | |
| 209 | +#define PTEUNCACHED (1<<2) | |
| 210 | +#define PTEKERNEL (1<<3) /* no user access */ | |
| 211 | + | |
| 212 | +/* | |
| 213 | + * H3650 specific definitions | |
| 214 | + */ | |
| 215 | +#define EGPIOREGS 0x49000000 /* Additional GPIO register */ | |
| @@ -0,0 +1,86 @@ | ||
| 1 | +<../../../mkconfig | |
| 2 | +objtype=arm | |
| 3 | +SYSTARG=$OSTARG | |
| 4 | +OBJTYPE=arm | |
| 5 | +BIN=$ROOT/Inferno/$OBJTYPE | |
| 6 | +LIBDIR=$ROOT/Inferno/$OBJTYPE/lib | |
| 7 | +LIBDIRS=../libflate $ROOT/libkern | |
| 8 | +LIBS=\ | |
| 9 | + libflate\ | |
| 10 | + libkern\ | |
| 11 | + | |
| 12 | +LIBFILES=${LIBS:%=$LIBDIR/%.a} | |
| 13 | +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE | |
| 14 | + | |
| 15 | +BIN=$ROOT/Inferno/$OBJTYPE | |
| 16 | + | |
| 17 | +TARG=\ | |
| 18 | + inflate\ | |
| 19 | + | |
| 20 | +INFLATE=\ | |
| 21 | + il.$O\ | |
| 22 | + imain.$O\ | |
| 23 | + | |
| 24 | +CORE=\ | |
| 25 | + uart.$O\ | |
| 26 | + inflate.$O\ | |
| 27 | + donprint.$O\ | |
| 28 | + print.$O\ | |
| 29 | + | |
| 30 | +HFILES=\ | |
| 31 | + mem.h\ | |
| 32 | + | |
| 33 | +CFLAGS=-FVw -I. -I$ROOT/Inferno/$OBJTYPE/include -I$ROOT/include | |
| 34 | + | |
| 35 | +all:V: $TARG | |
| 36 | + | |
| 37 | +install:V: $BIN/$TARG | |
| 38 | + | |
| 39 | +$BIN/%: % | |
| 40 | + cp $stem $BIN/$stem | |
| 41 | + | |
| 42 | +inflate: $INFLATE $CORE $LIBFILES | |
| 43 | + $LD -o s$target -R4 -T0xC0200010 -l $prereq | |
| 44 | + $LD -o _$target -H5 -R4 -T0xC0200010 -l $prereq | |
| 45 | + dd -conv sync -ibs 20k -if _$target -of $target | |
| 46 | + | |
| 47 | +%.$O: %.s | |
| 48 | + $AS $stem.s | |
| 49 | + | |
| 50 | +%.$O: %.c | |
| 51 | + $CC $CFLAGS $stem.c | |
| 52 | + | |
| 53 | +%.$O: $HFILES | |
| 54 | + | |
| 55 | +clean: | |
| 56 | + rm -f *.[$OS] [$OS].out y.tab.? y.debug y.output $TARG _$TARG s$TARG | |
| 57 | + | |
| 58 | + | |
| 59 | +# added to cause libflate to be made automatically: | |
| 60 | + | |
| 61 | +$ROOT/Inferno/$OBJTYPE/lib/lib%.a:Q: all-$SHELLTYPE | |
| 62 | + # | |
| 63 | + | |
| 64 | +rc-lib%.a nt-lib%.a:VQ: | |
| 65 | + echo '@{builtin cd ' $ROOT/lib$stem ';mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install}' | |
| 66 | + @{builtin cd $ROOT/lib$stem ;mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE install} | |
| 67 | + | |
| 68 | +sh-lib%.a:VQ: | |
| 69 | + echo "(cd $ROOT/lib$stem ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install)" | |
| 70 | + (cd $ROOT/lib$stem ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install) | |
| 71 | + | |
| 72 | +%-sh:QV: | |
| 73 | + for i in $LIBDIRS | |
| 74 | + do | |
| 75 | + echo "(cd $i ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE $stem)" | |
| 76 | + (cd $i; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE $stem) | |
| 77 | + done | |
| 78 | + | |
| 79 | +%-rc %-nt:QV: | |
| 80 | + for (i in $LIBDIRS) | |
| 81 | + { | |
| 82 | + echo '@{cd $i ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE $stem}' | |
| 83 | + @{cd $i; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE $stem} | |
| 84 | + } | |
| 85 | + | |
| 86 | +nuke:V: clean nuke-$SHELLTYPE | |
| @@ -0,0 +1,56 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "fns.h" | |
| 4 | +#include "dat.h" | |
| 5 | + | |
| 6 | + | |
| 7 | +#define SIZE 1024 | |
| 8 | + | |
| 9 | +int | |
| 10 | +print(char *fmt, ...) | |
| 11 | +{ | |
| 12 | + char buf[SIZE], *out; | |
| 13 | + va_list arg; | |
| 14 | + | |
| 15 | + va_start(arg, fmt); | |
| 16 | + out = donprint(buf, buf+SIZE, fmt, arg); | |
| 17 | + va_end(arg); | |
| 18 | + serialputs(buf, out-buf); | |
| 19 | + return out-buf; | |
| 20 | +} | |
| 21 | + | |
| 22 | +int | |
| 23 | +sprint(char *buf, char *fmt, ...) | |
| 24 | +{ | |
| 25 | + char *out; | |
| 26 | + va_list arg; | |
| 27 | + | |
| 28 | + va_start(arg, fmt); | |
| 29 | + out = donprint(buf, buf+SIZE, fmt, arg); | |
| 30 | + va_end(arg); | |
| 31 | + return out-buf; | |
| 32 | +} | |
| 33 | + | |
| 34 | +int | |
| 35 | +snprint(char *buf, int len, char *fmt, ...) | |
| 36 | +{ | |
| 37 | + char *out; | |
| 38 | + va_list arg; | |
| 39 | + | |
| 40 | + va_start(arg, fmt); | |
| 41 | + out = donprint(buf, buf+len, fmt, arg); | |
| 42 | + va_end(arg); | |
| 43 | + return out-buf; | |
| 44 | +} | |
| 45 | + | |
| 46 | +char* | |
| 47 | +seprint(char *buf, char *e, char *fmt, ...) | |
| 48 | +{ | |
| 49 | + char *out; | |
| 50 | + va_list arg; | |
| 51 | + | |
| 52 | + va_start(arg, fmt); | |
| 53 | + out = donprint(buf, e, fmt, arg); | |
| 54 | + va_end(arg); | |
| 55 | + return out; | |
| 56 | +} | |
| @@ -0,0 +1,69 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +enum | |
| 9 | +{ | |
| 10 | + /* ctl[0] bits */ | |
| 11 | + Parity= 1<<0, | |
| 12 | + Even= 1<<1, | |
| 13 | + Stop2= 1<<2, | |
| 14 | + Bits8= 1<<3, | |
| 15 | + SCE= 1<<4, /* synchronous clock enable */ | |
| 16 | + RCE= 1<<5, /* rx on falling edge of clock */ | |
| 17 | + TCE= 1<<6, /* tx on falling edge of clock */ | |
| 18 | + | |
| 19 | + /* ctl[3] bits */ | |
| 20 | + Rena= 1<<0, /* receiver enable */ | |
| 21 | + Tena= 1<<1, /* transmitter enable */ | |
| 22 | + Break= 1<<2, /* force TXD3 low */ | |
| 23 | + Rintena= 1<<3, /* enable receive interrupt */ | |
| 24 | + Tintena= 1<<4, /* enable transmitter interrupt */ | |
| 25 | + Loopback= 1<<5, /* loop back data */ | |
| 26 | + | |
| 27 | + /* data bits */ | |
| 28 | + DEparity= 1<<8, /* parity error */ | |
| 29 | + DEframe= 1<<9, /* framing error */ | |
| 30 | + DEoverrun= 1<<10, /* overrun error */ | |
| 31 | + | |
| 32 | + /* status[0] bits */ | |
| 33 | + Tint= 1<<0, /* transmit fifo half full interrupt */ | |
| 34 | + Rint0= 1<<1, /* receiver fifo 1/3-2/3 full */ | |
| 35 | + Rint1= 1<<2, /* receiver fifo not empty and receiver idle */ | |
| 36 | + Breakstart= 1<<3, | |
| 37 | + Breakend= 1<<4, | |
| 38 | + Fifoerror= 1<<5, /* fifo error */ | |
| 39 | + | |
| 40 | + /* status[1] bits */ | |
| 41 | + Tbusy= 1<<0, /* transmitting */ | |
| 42 | + Rnotempty= 1<<1, /* receive fifo not empty */ | |
| 43 | + Tnotfull= 1<<2, /* transmit fifo not full */ | |
| 44 | + ParityError= 1<<3, | |
| 45 | + FrameError= 1<<4, | |
| 46 | + Overrun= 1<<5, | |
| 47 | +}; | |
| 48 | + | |
| 49 | +Uartregs *uart3regs = UART3REGS; | |
| 50 | + | |
| 51 | + | |
| 52 | +/* | |
| 53 | + * for iprint, just write it | |
| 54 | + */ | |
| 55 | +void | |
| 56 | +serialputs(char *str, int n) | |
| 57 | +{ | |
| 58 | + Uartregs *ur; | |
| 59 | + | |
| 60 | + ur = uart3regs; | |
| 61 | + while(n-- > 0){ | |
| 62 | + /* wait for output ready */ | |
| 63 | + while((ur->status[1] & Tnotfull) == 0) | |
| 64 | + ; | |
| 65 | + ur->data = *str++; | |
| 66 | + } | |
| 67 | + while((ur->status[1] & Tbusy)) | |
| 68 | + ; | |
| 69 | +} | |
| @@ -0,0 +1,237 @@ | ||
| 1 | +Lucent Public License Version 1.02 | |
| 2 | + | |
| 3 | +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC | |
| 4 | +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE | |
| 5 | +PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. | |
| 6 | + | |
| 7 | +1. DEFINITIONS | |
| 8 | + | |
| 9 | +"Contribution" means: | |
| 10 | + | |
| 11 | + a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original | |
| 12 | + Program, and | |
| 13 | + b. in the case of each Contributor, | |
| 14 | + | |
| 15 | + i. changes to the Program, and | |
| 16 | + ii. additions to the Program; | |
| 17 | + | |
| 18 | + where such changes and/or additions to the Program were added to the | |
| 19 | + Program by such Contributor itself or anyone acting on such | |
| 20 | + Contributor's behalf, and the Contributor explicitly consents, in | |
| 21 | + accordance with Section 3C, to characterization of the changes and/or | |
| 22 | + additions as Contributions. | |
| 23 | + | |
| 24 | +"Contributor" means LUCENT and any other entity that has Contributed a | |
| 25 | +Contribution to the Program. | |
| 26 | + | |
| 27 | +"Distributor" means a Recipient that distributes the Program, | |
| 28 | +modifications to the Program, or any part thereof. | |
| 29 | + | |
| 30 | +"Licensed Patents" mean patent claims licensable by a Contributor | |
| 31 | +which are necessarily infringed by the use or sale of its Contribution | |
| 32 | +alone or when combined with the Program. | |
| 33 | + | |
| 34 | +"Original Program" means the original version of the software | |
| 35 | +accompanying this Agreement as released by LUCENT, including source | |
| 36 | +code, object code and documentation, if any. | |
| 37 | + | |
| 38 | +"Program" means the Original Program and Contributions or any part | |
| 39 | +thereof | |
| 40 | + | |
| 41 | +"Recipient" means anyone who receives the Program under this | |
| 42 | +Agreement, including all Contributors. | |
| 43 | + | |
| 44 | +2. GRANT OF RIGHTS | |
| 45 | + | |
| 46 | + a. Subject to the terms of this Agreement, each Contributor hereby | |
| 47 | + grants Recipient a non-exclusive, worldwide, royalty-free copyright | |
| 48 | + license to reproduce, prepare derivative works of, publicly display, | |
| 49 | + publicly perform, distribute and sublicense the Contribution of such | |
| 50 | + Contributor, if any, and such derivative works, in source code and | |
| 51 | + object code form. | |
| 52 | + | |
| 53 | + b. Subject to the terms of this Agreement, each Contributor hereby | |
| 54 | + grants Recipient a non-exclusive, worldwide, royalty-free patent | |
| 55 | + license under Licensed Patents to make, use, sell, offer to sell, | |
| 56 | + import and otherwise transfer the Contribution of such Contributor, if | |
| 57 | + any, in source code and object code form. The patent license granted | |
| 58 | + by a Contributor shall also apply to the combination of the | |
| 59 | + Contribution of that Contributor and the Program if, at the time the | |
| 60 | + Contribution is added by the Contributor, such addition of the | |
| 61 | + Contribution causes such combination to be covered by the Licensed | |
| 62 | + Patents. The patent license granted by a Contributor shall not apply | |
| 63 | + to (i) any other combinations which include the Contribution, nor to | |
| 64 | + (ii) Contributions of other Contributors. No hardware per se is | |
| 65 | + licensed hereunder. | |
| 66 | + | |
| 67 | + c. Recipient understands that although each Contributor grants the | |
| 68 | + licenses to its Contributions set forth herein, no assurances are | |
| 69 | + provided by any Contributor that the Program does not infringe the | |
| 70 | + patent or other intellectual property rights of any other entity. Each | |
| 71 | + Contributor disclaims any liability to Recipient for claims brought by | |
| 72 | + any other entity based on infringement of intellectual property rights | |
| 73 | + or otherwise. As a condition to exercising the rights and licenses | |
| 74 | + granted hereunder, each Recipient hereby assumes sole responsibility | |
| 75 | + to secure any other intellectual property rights needed, if any. For | |
| 76 | + example, if a third party patent license is required to allow | |
| 77 | + Recipient to distribute the Program, it is Recipient's responsibility | |
| 78 | + to acquire that license before distributing the Program. | |
| 79 | + | |
| 80 | + d. Each Contributor represents that to its knowledge it has sufficient | |
| 81 | + copyright rights in its Contribution, if any, to grant the copyright | |
| 82 | + license set forth in this Agreement. | |
| 83 | + | |
| 84 | +3. REQUIREMENTS | |
| 85 | + | |
| 86 | +A. Distributor may choose to distribute the Program in any form under | |
| 87 | +this Agreement or under its own license agreement, provided that: | |
| 88 | + | |
| 89 | + a. it complies with the terms and conditions of this Agreement; | |
| 90 | + | |
| 91 | + b. if the Program is distributed in source code or other tangible | |
| 92 | + form, a copy of this Agreement or Distributor's own license agreement | |
| 93 | + is included with each copy of the Program; and | |
| 94 | + | |
| 95 | + c. if distributed under Distributor's own license agreement, such | |
| 96 | + license agreement: | |
| 97 | + | |
| 98 | + i. effectively disclaims on behalf of all Contributors all warranties | |
| 99 | + and conditions, express and implied, including warranties or | |
| 100 | + conditions of title and non-infringement, and implied warranties or | |
| 101 | + conditions of merchantability and fitness for a particular purpose; | |
| 102 | + ii. effectively excludes on behalf of all Contributors all liability | |
| 103 | + for damages, including direct, indirect, special, incidental and | |
| 104 | + consequential damages, such as lost profits; and | |
| 105 | + iii. states that any provisions which differ from this Agreement are | |
| 106 | + offered by that Contributor alone and not by any other party. | |
| 107 | + | |
| 108 | +B. Each Distributor must include the following in a conspicuous | |
| 109 | + location in the Program: | |
| 110 | + | |
| 111 | + Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights | |
| 112 | + Reserved. | |
| 113 | + | |
| 114 | +C. In addition, each Contributor must identify itself as the | |
| 115 | +originator of its Contribution in a manner that reasonably allows | |
| 116 | +subsequent Recipients to identify the originator of the Contribution. | |
| 117 | +Also, each Contributor must agree that the additions and/or changes | |
| 118 | +are intended to be a Contribution. Once a Contribution is contributed, | |
| 119 | +it may not thereafter be revoked. | |
| 120 | + | |
| 121 | +4. COMMERCIAL DISTRIBUTION | |
| 122 | + | |
| 123 | +Commercial distributors of software may accept certain | |
| 124 | +responsibilities with respect to end users, business partners and the | |
| 125 | +like. While this license is intended to facilitate the commercial use | |
| 126 | +of the Program, the Distributor who includes the Program in a | |
| 127 | +commercial product offering should do so in a manner which does not | |
| 128 | +create potential liability for Contributors. Therefore, if a | |
| 129 | +Distributor includes the Program in a commercial product offering, | |
| 130 | +such Distributor ("Commercial Distributor") hereby agrees to defend | |
| 131 | +and indemnify every Contributor ("Indemnified Contributor") against | |
| 132 | +any losses, damages and costs (collectively"Losses") arising from | |
| 133 | +claims, lawsuits and other legal actions brought by a third party | |
| 134 | +against the Indemnified Contributor to the extent caused by the acts | |
| 135 | +or omissions of such Commercial Distributor in connection with its | |
| 136 | +distribution of the Program in a commercial product offering. The | |
| 137 | +obligations in this section do not apply to any claims or Losses | |
| 138 | +relating to any actual or alleged intellectual property infringement. | |
| 139 | +In order to qualify, an Indemnified Contributor must: a) promptly | |
| 140 | +notify the Commercial Distributor in writing of such claim, and b) | |
| 141 | +allow the Commercial Distributor to control, and cooperate with the | |
| 142 | +Commercial Distributor in, the defense and any related settlement | |
| 143 | +negotiations. The Indemnified Contributor may participate in any such | |
| 144 | +claim at its own expense. | |
| 145 | + | |
| 146 | +For example, a Distributor might include the Program in a commercial | |
| 147 | +product offering, Product X. That Distributor is then a Commercial | |
| 148 | +Distributor. If that Commercial Distributor then makes performance | |
| 149 | +claims, or offers warranties related to Product X, those performance | |
| 150 | +claims and warranties are such Commercial Distributor's responsibility | |
| 151 | +alone. Under this section, the Commercial Distributor would have to | |
| 152 | +defend claims against the Contributors related to those performance | |
| 153 | +claims and warranties, and if a court requires any Contributor to pay | |
| 154 | +any damages as a result, the Commercial Distributor must pay those | |
| 155 | +damages. | |
| 156 | + | |
| 157 | +5. NO WARRANTY | |
| 158 | + | |
| 159 | +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS | |
| 160 | +PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| 161 | +KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY | |
| 162 | +WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY | |
| 163 | +OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely | |
| 164 | +responsible for determining the appropriateness of using and | |
| 165 | +distributing the Program and assumes all risks associated with its | |
| 166 | +exercise of rights under this Agreement, including but not limited to | |
| 167 | +the risks and costs of program errors, compliance with applicable | |
| 168 | +laws, damage to or loss of data, programs or equipment, and | |
| 169 | +unavailability or interruption of operations. | |
| 170 | + | |
| 171 | +6. DISCLAIMER OF LIABILITY | |
| 172 | + | |
| 173 | +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR | |
| 174 | +ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, | |
| 175 | +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING | |
| 176 | +WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF | |
| 177 | +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| 178 | +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR | |
| 179 | +DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED | |
| 180 | +HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
| 181 | + | |
| 182 | +7. EXPORT CONTROL | |
| 183 | + | |
| 184 | +Recipient agrees that Recipient alone is responsible for compliance | |
| 185 | +with the United States export administration regulations (and the | |
| 186 | +export control laws and regulation of any other countries). | |
| 187 | + | |
| 188 | +8. GENERAL | |
| 189 | + | |
| 190 | +If any provision of this Agreement is invalid or unenforceable under | |
| 191 | +applicable law, it shall not affect the validity or enforceability of | |
| 192 | +the remainder of the terms of this Agreement, and without further | |
| 193 | +action by the parties hereto, such provision shall be reformed to the | |
| 194 | +minimum extent necessary to make such provision valid and enforceable. | |
| 195 | + | |
| 196 | +If Recipient institutes patent litigation against a Contributor with | |
| 197 | +respect to a patent applicable to software (including a cross-claim or | |
| 198 | +counterclaim in a lawsuit), then any patent licenses granted by that | |
| 199 | +Contributor to such Recipient under this Agreement shall terminate as | |
| 200 | +of the date such litigation is filed. In addition, if Recipient | |
| 201 | +institutes patent litigation against any entity (including a | |
| 202 | +cross-claim or counterclaim in a lawsuit) alleging that the Program | |
| 203 | +itself (excluding combinations of the Program with other software or | |
| 204 | +hardware) infringes such Recipient's patent(s), then such Recipient's | |
| 205 | +rights granted under Section 2(b) shall terminate as of the date such | |
| 206 | +litigation is filed. | |
| 207 | + | |
| 208 | +All Recipient's rights under this Agreement shall terminate if it | |
| 209 | +fails to comply with any of the material terms or conditions of this | |
| 210 | +Agreement and does not cure such failure in a reasonable period of | |
| 211 | +time after becoming aware of such noncompliance. If all Recipient's | |
| 212 | +rights under this Agreement terminate, Recipient agrees to cease use | |
| 213 | +and distribution of the Program as soon as reasonably practicable. | |
| 214 | +However, Recipient's obligations under this Agreement and any licenses | |
| 215 | +granted by Recipient relating to the Program shall continue and | |
| 216 | +survive. | |
| 217 | + | |
| 218 | +LUCENT may publish new versions (including revisions) of this | |
| 219 | +Agreement from time to time. Each new version of the Agreement will be | |
| 220 | +given a distinguishing version number. The Program (including | |
| 221 | +Contributions) may always be distributed subject to the version of the | |
| 222 | +Agreement under which it was received. In addition, after a new | |
| 223 | +version of the Agreement is published, Contributor may elect to | |
| 224 | +distribute the Program (including its Contributions) under the new | |
| 225 | +version. No one other than LUCENT has the right to modify this | |
| 226 | +Agreement. Except as expressly stated in Sections 2(a) and 2(b) above, | |
| 227 | +Recipient receives no rights or licenses to the intellectual property | |
| 228 | +of any Contributor under this Agreement, whether expressly, by | |
| 229 | +implication, estoppel or otherwise. All rights in the Program not | |
| 230 | +expressly granted under this Agreement are reserved. | |
| 231 | + | |
| 232 | +This Agreement is governed by the laws of the State of New York and | |
| 233 | +the intellectual property laws of the United States of America. No | |
| 234 | +party to this Agreement will bring a legal action under this Agreement | |
| 235 | +more than one year after the cause of action arose. Each party waives | |
| 236 | +its rights to a jury trial in any resulting litigation. | |
| 237 | + | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +Copyright © 2002 Lucent Technologies Inc. | |
| 2 | +All Rights Reserved | |
| 3 | + | |
| 4 | +This software was originally developed for Plan 9. | |
| 5 | +It is provided under the terms of the Lucent Public License, Version 1.02. | |
| 6 | + | |
| 7 | +Trivial modifications have been made to make it compile for Inferno. | |
| 8 | + Vita Nuova Holdings Limited. | |
| @@ -0,0 +1,71 @@ | ||
| 1 | +#include "lib9.h" | |
| 2 | +#include <flate.h> | |
| 3 | + | |
| 4 | +enum | |
| 5 | +{ | |
| 6 | + ADLERITERS = 5552, /* max iters before can overflow 32 bits */ | |
| 7 | + ADLERBASE = 65521 /* largest prime smaller than 65536 */ | |
| 8 | +}; | |
| 9 | + | |
| 10 | +ulong | |
| 11 | +adler32(ulong adler, void *vbuf, int n) | |
| 12 | +{ | |
| 13 | + ulong s1, s2; | |
| 14 | + uchar *buf, *ebuf; | |
| 15 | + int m; | |
| 16 | + | |
| 17 | + buf = vbuf; | |
| 18 | + s1 = adler & 0xffff; | |
| 19 | + s2 = (adler >> 16) & 0xffff; | |
| 20 | + for(; n >= 16; n -= m){ | |
| 21 | + m = n; | |
| 22 | + if(m > ADLERITERS) | |
| 23 | + m = ADLERITERS; | |
| 24 | + m &= ~15; | |
| 25 | + for(ebuf = buf + m; buf < ebuf; buf += 16){ | |
| 26 | + s1 += buf[0]; | |
| 27 | + s2 += s1; | |
| 28 | + s1 += buf[1]; | |
| 29 | + s2 += s1; | |
| 30 | + s1 += buf[2]; | |
| 31 | + s2 += s1; | |
| 32 | + s1 += buf[3]; | |
| 33 | + s2 += s1; | |
| 34 | + s1 += buf[4]; | |
| 35 | + s2 += s1; | |
| 36 | + s1 += buf[5]; | |
| 37 | + s2 += s1; | |
| 38 | + s1 += buf[6]; | |
| 39 | + s2 += s1; | |
| 40 | + s1 += buf[7]; | |
| 41 | + s2 += s1; | |
| 42 | + s1 += buf[8]; | |
| 43 | + s2 += s1; | |
| 44 | + s1 += buf[9]; | |
| 45 | + s2 += s1; | |
| 46 | + s1 += buf[10]; | |
| 47 | + s2 += s1; | |
| 48 | + s1 += buf[11]; | |
| 49 | + s2 += s1; | |
| 50 | + s1 += buf[12]; | |
| 51 | + s2 += s1; | |
| 52 | + s1 += buf[13]; | |
| 53 | + s2 += s1; | |
| 54 | + s1 += buf[14]; | |
| 55 | + s2 += s1; | |
| 56 | + s1 += buf[15]; | |
| 57 | + s2 += s1; | |
| 58 | + } | |
| 59 | + s1 %= ADLERBASE; | |
| 60 | + s2 %= ADLERBASE; | |
| 61 | + } | |
| 62 | + if(n){ | |
| 63 | + for(ebuf = buf + n; buf < ebuf; buf++){ | |
| 64 | + s1 += buf[0]; | |
| 65 | + s2 += s1; | |
| 66 | + } | |
| 67 | + s1 %= ADLERBASE; | |
| 68 | + s2 %= ADLERBASE; | |
| 69 | + } | |
| 70 | + return (s2 << 16) + s1; | |
| 71 | +} | |
| @@ -0,0 +1,39 @@ | ||
| 1 | +#include "lib9.h" | |
| 2 | +#include <flate.h> | |
| 3 | + | |
| 4 | +ulong* | |
| 5 | +mkcrctab(ulong poly) | |
| 6 | +{ | |
| 7 | + ulong *crctab; | |
| 8 | + ulong crc; | |
| 9 | + int i, j; | |
| 10 | + | |
| 11 | + crctab = malloc(256 * sizeof(ulong)); | |
| 12 | + if(crctab == nil) | |
| 13 | + return nil; | |
| 14 | + | |
| 15 | + for(i = 0; i < 256; i++){ | |
| 16 | + crc = i; | |
| 17 | + for(j = 0; j < 8; j++){ | |
| 18 | + if(crc & 1) | |
| 19 | + crc = (crc >> 1) ^ poly; | |
| 20 | + else | |
| 21 | + crc >>= 1; | |
| 22 | + } | |
| 23 | + crctab[i] = crc; | |
| 24 | + } | |
| 25 | + return crctab; | |
| 26 | +} | |
| 27 | + | |
| 28 | +ulong | |
| 29 | +blockcrc(ulong *crctab, ulong crc, void *vbuf, int n) | |
| 30 | +{ | |
| 31 | + uchar *buf, *ebuf; | |
| 32 | + | |
| 33 | + crc ^= 0xffffffff; | |
| 34 | + buf = vbuf; | |
| 35 | + ebuf = buf + n; | |
| 36 | + while(buf < ebuf) | |
| 37 | + crc = crctab[(crc & 0xff) ^ *buf++] ^ (crc >> 8); | |
| 38 | + return crc ^ 0xffffffff; | |
| 39 | +} | |
| @@ -0,0 +1,1358 @@ | ||
| 1 | +#include "lib9.h" | |
| 2 | +#include <flate.h> | |
| 3 | + | |
| 4 | +typedef struct Chain Chain; | |
| 5 | +typedef struct Chains Chains; | |
| 6 | +typedef struct Dyncode Dyncode; | |
| 7 | +typedef struct Huff Huff; | |
| 8 | +typedef struct LZblock LZblock; | |
| 9 | +typedef struct LZstate LZstate; | |
| 10 | + | |
| 11 | +enum | |
| 12 | +{ | |
| 13 | + /* | |
| 14 | + * deflate format paramaters | |
| 15 | + */ | |
| 16 | + DeflateUnc = 0, /* uncompressed block */ | |
| 17 | + DeflateFix = 1, /* fixed huffman codes */ | |
| 18 | + DeflateDyn = 2, /* dynamic huffman codes */ | |
| 19 | + | |
| 20 | + DeflateEob = 256, /* end of block code in lit/len book */ | |
| 21 | + DeflateMaxBlock = 64*1024-1, /* maximum size of uncompressed block */ | |
| 22 | + | |
| 23 | + DeflateMaxExp = 10, /* maximum expansion for a block */ | |
| 24 | + | |
| 25 | + LenStart = 257, /* start of length codes in litlen */ | |
| 26 | + Nlitlen = 288, /* number of litlen codes */ | |
| 27 | + Noff = 30, /* number of offset codes */ | |
| 28 | + Nclen = 19, /* number of codelen codes */ | |
| 29 | + | |
| 30 | + MaxOff = 32*1024, | |
| 31 | + MinMatch = 3, /* shortest match possible */ | |
| 32 | + MaxMatch = 258, /* longest match possible */ | |
| 33 | + | |
| 34 | + /* | |
| 35 | + * huffman code paramaters | |
| 36 | + */ | |
| 37 | + MaxLeaf = Nlitlen, | |
| 38 | + MaxHuffBits = 16, /* max bits in a huffman code */ | |
| 39 | + ChainMem = 2 * (MaxHuffBits - 1) * MaxHuffBits, | |
| 40 | + | |
| 41 | + /* | |
| 42 | + * coding of the lz parse | |
| 43 | + */ | |
| 44 | + LenFlag = 1 << 3, | |
| 45 | + LenShift = 4, /* leaves enough space for MinMatchMaxOff */ | |
| 46 | + MaxLitRun = LenFlag - 1, | |
| 47 | + | |
| 48 | + /* | |
| 49 | + * internal lz paramaters | |
| 50 | + */ | |
| 51 | + DeflateOut = 4096, /* output buffer size */ | |
| 52 | + BlockSize = 8192, /* attempted input read quanta */ | |
| 53 | + DeflateBlock = DeflateMaxBlock & ~(BlockSize - 1), | |
| 54 | + MinMatchMaxOff = 4096, /* max profitable offset for small match; | |
| 55 | + * assumes 8 bits for len, 5+10 for offset | |
| 56 | + * DONT CHANGE WITHOUT CHANGING LZPARSE CONSTANTS | |
| 57 | + */ | |
| 58 | + HistSlop = 512, /* must be at lead MaxMatch */ | |
| 59 | + HistBlock = 64*1024, | |
| 60 | + HistSize = HistBlock + HistSlop, | |
| 61 | + | |
| 62 | + HashLog = 13, | |
| 63 | + HashSize = 1<<HashLog, | |
| 64 | + | |
| 65 | + MaxOffCode = 256, /* biggest offset looked up in direct table */ | |
| 66 | + | |
| 67 | + EstLitBits = 8, | |
| 68 | + EstLenBits = 4, | |
| 69 | + EstOffBits = 5, | |
| 70 | +}; | |
| 71 | + | |
| 72 | +/* | |
| 73 | + * knuth vol. 3 multiplicative hashing | |
| 74 | + * each byte x chosen according to rules | |
| 75 | + * 1/4 < x < 3/10, 1/3 x < < 3/7, 4/7 < x < 2/3, 7/10 < x < 3/4 | |
| 76 | + * with reasonable spread between the bytes & their complements | |
| 77 | + * | |
| 78 | + * the 3 byte value appears to be as almost good as the 4 byte value, | |
| 79 | + * and might be faster on some machines | |
| 80 | + */ | |
| 81 | +/* | |
| 82 | +#define hashit(c) (((ulong)(c) * 0x6b43a9) >> (24 - HashLog)) | |
| 83 | +*/ | |
| 84 | +#define hashit(c) ((((ulong)(c) & 0xffffff) * 0x6b43a9b5) >> (32 - HashLog)) | |
| 85 | + | |
| 86 | +/* | |
| 87 | + * lempel-ziv style compression state | |
| 88 | + */ | |
| 89 | +struct LZstate | |
| 90 | +{ | |
| 91 | + uchar hist[HistSize]; | |
| 92 | + ulong pos; /* current location in history buffer */ | |
| 93 | + ulong avail; /* data available after pos */ | |
| 94 | + int eof; | |
| 95 | + ushort hash[HashSize]; /* hash chains */ | |
| 96 | + ushort nexts[MaxOff]; | |
| 97 | + int now; /* pos in hash chains */ | |
| 98 | + int dot; /* dawn of time in history */ | |
| 99 | + int prevlen; /* lazy matching state */ | |
| 100 | + int prevoff; | |
| 101 | + int maxcheck; /* compressor tuning */ | |
| 102 | + | |
| 103 | + uchar obuf[DeflateOut]; | |
| 104 | + uchar *out; /* current position in the output buffer */ | |
| 105 | + uchar *eout; | |
| 106 | + ulong bits; /* bit shift register */ | |
| 107 | + int nbits; | |
| 108 | + int rbad; /* got an error reading the buffer */ | |
| 109 | + int wbad; /* got an error writing the buffer */ | |
| 110 | + int (*w)(void*, void*, int); | |
| 111 | + void *wr; | |
| 112 | + | |
| 113 | + ulong totr; /* total input size */ | |
| 114 | + ulong totw; /* total output size */ | |
| 115 | + int debug; | |
| 116 | +}; | |
| 117 | + | |
| 118 | +struct LZblock | |
| 119 | +{ | |
| 120 | + ushort parse[DeflateMaxBlock / 2 + 1]; | |
| 121 | + int lastv; /* value being constucted for parse */ | |
| 122 | + ulong litlencount[Nlitlen]; | |
| 123 | + ulong offcount[Noff]; | |
| 124 | + ushort *eparse; /* limit for parse table */ | |
| 125 | + int bytes; /* consumed from the input */ | |
| 126 | + int excost; /* cost of encoding extra len & off bits */ | |
| 127 | +}; | |
| 128 | + | |
| 129 | +/* | |
| 130 | + * huffman code table | |
| 131 | + */ | |
| 132 | +struct Huff | |
| 133 | +{ | |
| 134 | + short bits; /* length of the code */ | |
| 135 | + ushort encode; /* the code */ | |
| 136 | +}; | |
| 137 | + | |
| 138 | +/* | |
| 139 | + * encoding of dynamic huffman trees | |
| 140 | + */ | |
| 141 | +struct Dyncode | |
| 142 | +{ | |
| 143 | + int nlit; | |
| 144 | + int noff; | |
| 145 | + int nclen; | |
| 146 | + int ncode; | |
| 147 | + Huff codetab[Nclen]; | |
| 148 | + uchar codes[Nlitlen+Noff]; | |
| 149 | + uchar codeaux[Nlitlen+Noff]; | |
| 150 | +}; | |
| 151 | + | |
| 152 | +static int deflateb(LZstate *lz, LZblock *lzb, void *rr, int (*r)(void*, void*, int)); | |
| 153 | +static int lzcomp(LZstate*, LZblock*, uchar*, ushort*, int finish); | |
| 154 | +static void wrblock(LZstate*, int, ushort*, ushort*, Huff*, Huff*); | |
| 155 | +static int bitcost(Huff*, ulong*, int); | |
| 156 | +static int huffcodes(Dyncode*, Huff*, Huff*); | |
| 157 | +static void wrdyncode(LZstate*, Dyncode*); | |
| 158 | +static void lzput(LZstate*, ulong bits, int nbits); | |
| 159 | +static void lzflushbits(LZstate*); | |
| 160 | +static void lzflush(LZstate *lz); | |
| 161 | +static void lzwrite(LZstate *lz, void *buf, int n); | |
| 162 | + | |
| 163 | +static int hufftabinit(Huff*, int, ulong*, int); | |
| 164 | +static int mkgzprecode(Huff*, ulong *, int, int); | |
| 165 | + | |
| 166 | +static int mkprecode(Huff*, ulong *, int, int, ulong*); | |
| 167 | +static void nextchain(Chains*, int); | |
| 168 | +static void leafsort(ulong*, ushort*, int, int); | |
| 169 | + | |
| 170 | +/* conversion from len to code word */ | |
| 171 | +static int lencode[MaxMatch]; | |
| 172 | + | |
| 173 | +/* | |
| 174 | + * conversion from off to code word | |
| 175 | + * off <= MaxOffCode ? offcode[off] : bigoffcode[off >> 7] | |
| 176 | +*/ | |
| 177 | +static int offcode[MaxOffCode]; | |
| 178 | +static int bigoffcode[256]; | |
| 179 | + | |
| 180 | +/* litlen code words LenStart-285 extra bits */ | |
| 181 | +static int litlenbase[Nlitlen-LenStart]; | |
| 182 | +static int litlenextra[Nlitlen-LenStart] = | |
| 183 | +{ | |
| 184 | +/* 257 */ 0, 0, 0, | |
| 185 | +/* 260 */ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, | |
| 186 | +/* 270 */ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, | |
| 187 | +/* 280 */ 4, 5, 5, 5, 5, 0, 0, 0 | |
| 188 | +}; | |
| 189 | + | |
| 190 | +/* offset code word extra bits */ | |
| 191 | +static int offbase[Noff]; | |
| 192 | +static int offextra[] = | |
| 193 | +{ | |
| 194 | + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, | |
| 195 | + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, | |
| 196 | + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, | |
| 197 | + 0, 0, | |
| 198 | +}; | |
| 199 | + | |
| 200 | +/* order code lengths */ | |
| 201 | +static int clenorder[Nclen] = | |
| 202 | +{ | |
| 203 | + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 | |
| 204 | +}; | |
| 205 | + | |
| 206 | +/* static huffman tables */ | |
| 207 | +static Huff litlentab[Nlitlen]; | |
| 208 | +static Huff offtab[Noff]; | |
| 209 | +static Huff hofftab[Noff]; | |
| 210 | + | |
| 211 | +/* bit reversal for brain dead endian swap in huffman codes */ | |
| 212 | +static uchar revtab[256]; | |
| 213 | +static ulong nlits; | |
| 214 | +static ulong nmatches; | |
| 215 | + | |
| 216 | +int | |
| 217 | +deflateinit(void) | |
| 218 | +{ | |
| 219 | + ulong bitcount[MaxHuffBits]; | |
| 220 | + int i, j, ci, n; | |
| 221 | + | |
| 222 | + /* byte reverse table */ | |
| 223 | + for(i=0; i<256; i++) | |
| 224 | + for(j=0; j<8; j++) | |
| 225 | + if(i & (1<<j)) | |
| 226 | + revtab[i] |= 0x80 >> j; | |
| 227 | + | |
| 228 | + /* static Litlen bit lengths */ | |
| 229 | + for(i=0; i<144; i++) | |
| 230 | + litlentab[i].bits = 8; | |
| 231 | + for(i=144; i<256; i++) | |
| 232 | + litlentab[i].bits = 9; | |
| 233 | + for(i=256; i<280; i++) | |
| 234 | + litlentab[i].bits = 7; | |
| 235 | + for(i=280; i<Nlitlen; i++) | |
| 236 | + litlentab[i].bits = 8; | |
| 237 | + | |
| 238 | + memset(bitcount, 0, sizeof(bitcount)); | |
| 239 | + bitcount[8] += 144 - 0; | |
| 240 | + bitcount[9] += 256 - 144; | |
| 241 | + bitcount[7] += 280 - 256; | |
| 242 | + bitcount[8] += Nlitlen - 280; | |
| 243 | + | |
| 244 | + if(!hufftabinit(litlentab, Nlitlen, bitcount, 9)) | |
| 245 | + return FlateInternal; | |
| 246 | + | |
| 247 | + /* static offset bit lengths */ | |
| 248 | + for(i = 0; i < Noff; i++) | |
| 249 | + offtab[i].bits = 5; | |
| 250 | + | |
| 251 | + memset(bitcount, 0, sizeof(bitcount)); | |
| 252 | + bitcount[5] = Noff; | |
| 253 | + | |
| 254 | + if(!hufftabinit(offtab, Noff, bitcount, 5)) | |
| 255 | + return FlateInternal; | |
| 256 | + | |
| 257 | + bitcount[0] = 0; | |
| 258 | + bitcount[1] = 0; | |
| 259 | + if(!mkgzprecode(hofftab, bitcount, 2, MaxHuffBits)) | |
| 260 | + return FlateInternal; | |
| 261 | + | |
| 262 | + /* conversion tables for lens & offs to codes */ | |
| 263 | + ci = 0; | |
| 264 | + for(i = LenStart; i < 286; i++){ | |
| 265 | + n = ci + (1 << litlenextra[i - LenStart]); | |
| 266 | + litlenbase[i - LenStart] = ci; | |
| 267 | + for(; ci < n; ci++) | |
| 268 | + lencode[ci] = i; | |
| 269 | + } | |
| 270 | + /* patch up special case for len MaxMatch */ | |
| 271 | + lencode[MaxMatch-MinMatch] = 285; | |
| 272 | + litlenbase[285-LenStart] = MaxMatch-MinMatch; | |
| 273 | + | |
| 274 | + ci = 0; | |
| 275 | + for(i = 0; i < 16; i++){ | |
| 276 | + n = ci + (1 << offextra[i]); | |
| 277 | + offbase[i] = ci; | |
| 278 | + for(; ci < n; ci++) | |
| 279 | + offcode[ci] = i; | |
| 280 | + } | |
| 281 | + | |
| 282 | + ci = ci >> 7; | |
| 283 | + for(; i < 30; i++){ | |
| 284 | + n = ci + (1 << (offextra[i] - 7)); | |
| 285 | + offbase[i] = ci << 7; | |
| 286 | + for(; ci < n; ci++) | |
| 287 | + bigoffcode[ci] = i; | |
| 288 | + } | |
| 289 | + return FlateOk; | |
| 290 | +} | |
| 291 | + | |
| 292 | +static void | |
| 293 | +deflatereset(LZstate *lz, int level, int debug) | |
| 294 | +{ | |
| 295 | + memset(lz->nexts, 0, sizeof lz->nexts); | |
| 296 | + memset(lz->hash, 0, sizeof lz->hash); | |
| 297 | + lz->totr = 0; | |
| 298 | + lz->totw = 0; | |
| 299 | + lz->pos = 0; | |
| 300 | + lz->avail = 0; | |
| 301 | + lz->out = lz->obuf; | |
| 302 | + lz->eout = &lz->obuf[DeflateOut]; | |
| 303 | + lz->prevlen = MinMatch - 1; | |
| 304 | + lz->prevoff = 0; | |
| 305 | + lz->now = MaxOff + 1; | |
| 306 | + lz->dot = lz->now; | |
| 307 | + lz->bits = 0; | |
| 308 | + lz->nbits = 0; | |
| 309 | + lz->maxcheck = (1 << level); | |
| 310 | + lz->maxcheck -= lz->maxcheck >> 2; | |
| 311 | + if(lz->maxcheck < 2) | |
| 312 | + lz->maxcheck = 2; | |
| 313 | + else if(lz->maxcheck > 1024) | |
| 314 | + lz->maxcheck = 1024; | |
| 315 | + | |
| 316 | + lz->debug = debug; | |
| 317 | +} | |
| 318 | + | |
| 319 | +int | |
| 320 | +deflate(void *wr, int (*w)(void*, void*, int), void *rr, int (*r)(void*, void*, int), int level, int debug) | |
| 321 | +{ | |
| 322 | + LZstate *lz; | |
| 323 | + LZblock *lzb; | |
| 324 | + int ok; | |
| 325 | + | |
| 326 | + lz = malloc(sizeof *lz + sizeof *lzb); | |
| 327 | + if(lz == nil) | |
| 328 | + return FlateNoMem; | |
| 329 | + lzb = (LZblock*)&lz[1]; | |
| 330 | + | |
| 331 | + deflatereset(lz, level, debug); | |
| 332 | + lz->w = w; | |
| 333 | + lz->wr = wr; | |
| 334 | + lz->wbad = 0; | |
| 335 | + lz->rbad = 0; | |
| 336 | + lz->eof = 0; | |
| 337 | + ok = FlateOk; | |
| 338 | + while(!lz->eof || lz->avail){ | |
| 339 | + ok = deflateb(lz, lzb, rr, r); | |
| 340 | + if(ok != FlateOk) | |
| 341 | + break; | |
| 342 | + } | |
| 343 | + if(ok == FlateOk && lz->rbad) | |
| 344 | + ok = FlateInputFail; | |
| 345 | + if(ok == FlateOk && lz->wbad) | |
| 346 | + ok = FlateOutputFail; | |
| 347 | + free(lz); | |
| 348 | + return ok; | |
| 349 | +} | |
| 350 | + | |
| 351 | +static int | |
| 352 | +deflateb(LZstate *lz, LZblock *lzb, void *rr, int (*r)(void*, void*, int)) | |
| 353 | +{ | |
| 354 | + Dyncode dyncode, hdyncode; | |
| 355 | + Huff dlitlentab[Nlitlen], dofftab[Noff], hlitlentab[Nlitlen]; | |
| 356 | + ulong litcount[Nlitlen]; | |
| 357 | + long nunc, ndyn, nfix, nhuff; | |
| 358 | + uchar *slop, *hslop; | |
| 359 | + ulong ep; | |
| 360 | + int i, n, m, mm, nslop; | |
| 361 | + | |
| 362 | + memset(lzb->litlencount, 0, sizeof lzb->litlencount); | |
| 363 | + memset(lzb->offcount, 0, sizeof lzb->offcount); | |
| 364 | + lzb->litlencount[DeflateEob]++; | |
| 365 | + | |
| 366 | + lzb->bytes = 0; | |
| 367 | + lzb->eparse = lzb->parse; | |
| 368 | + lzb->lastv = 0; | |
| 369 | + lzb->excost = 0; | |
| 370 | + | |
| 371 | + slop = &lz->hist[lz->pos]; | |
| 372 | + n = lz->avail; | |
| 373 | + while(n < DeflateBlock && (!lz->eof || lz->avail)){ | |
| 374 | + /* | |
| 375 | + * fill the buffer as much as possible, | |
| 376 | + * while leaving room for MaxOff history behind lz->pos, | |
| 377 | + * and not reading more than we can handle. | |
| 378 | + * | |
| 379 | + * make sure we read at least HistSlop bytes. | |
| 380 | + */ | |
| 381 | + if(!lz->eof){ | |
| 382 | + ep = lz->pos + lz->avail; | |
| 383 | + if(ep >= HistBlock) | |
| 384 | + ep -= HistBlock; | |
| 385 | + m = HistBlock - MaxOff - lz->avail; | |
| 386 | + if(m > HistBlock - n) | |
| 387 | + m = HistBlock - n; | |
| 388 | + if(m > (HistBlock + HistSlop) - ep) | |
| 389 | + m = (HistBlock + HistSlop) - ep; | |
| 390 | + if(m & ~(BlockSize - 1)) | |
| 391 | + m &= ~(BlockSize - 1); | |
| 392 | + | |
| 393 | + /* | |
| 394 | + * be nice to the caller: stop reads that are too small. | |
| 395 | + * can only get here when we've already filled the buffer some | |
| 396 | + */ | |
| 397 | + if(m < HistSlop){ | |
| 398 | + if(!m || !lzb->bytes) | |
| 399 | + return FlateInternal; | |
| 400 | + break; | |
| 401 | + } | |
| 402 | + | |
| 403 | + mm = (*r)(rr, &lz->hist[ep], m); | |
| 404 | + if(mm > 0){ | |
| 405 | + /* | |
| 406 | + * wrap data to end if we're read it from the beginning | |
| 407 | + * this way, we don't have to wrap searches. | |
| 408 | + * | |
| 409 | + * wrap reads past the end to the beginning. | |
| 410 | + * this way, we can guarantee minimum size reads. | |
| 411 | + */ | |
| 412 | + if(ep < HistSlop) | |
| 413 | + memmove(&lz->hist[ep + HistBlock], &lz->hist[ep], HistSlop - ep); | |
| 414 | + else if(ep + mm > HistBlock) | |
| 415 | + memmove(&lz->hist[0], &lz->hist[HistBlock], ep + mm - HistBlock); | |
| 416 | + | |
| 417 | + lz->totr += mm; | |
| 418 | + n += mm; | |
| 419 | + lz->avail += mm; | |
| 420 | + }else{ | |
| 421 | + if(mm < 0) | |
| 422 | + lz->rbad = 1; | |
| 423 | + lz->eof = 1; | |
| 424 | + } | |
| 425 | + } | |
| 426 | + ep = lz->pos + lz->avail; | |
| 427 | + if(ep > HistSize) | |
| 428 | + ep = HistSize; | |
| 429 | + if(lzb->bytes + ep - lz->pos > DeflateMaxBlock) | |
| 430 | + ep = lz->pos + DeflateMaxBlock - lzb->bytes; | |
| 431 | + m = lzcomp(lz, lzb, &lz->hist[ep], lzb->eparse, lz->eof); | |
| 432 | + lzb->bytes += m; | |
| 433 | + lz->pos = (lz->pos + m) & (HistBlock - 1); | |
| 434 | + lz->avail -= m; | |
| 435 | + } | |
| 436 | + if(lzb->lastv) | |
| 437 | + *lzb->eparse++ = lzb->lastv; | |
| 438 | + if(lzb->eparse > lzb->parse + nelem(lzb->parse)) | |
| 439 | + return FlateInternal; | |
| 440 | + nunc = lzb->bytes; | |
| 441 | + | |
| 442 | + if(!mkgzprecode(dlitlentab, lzb->litlencount, Nlitlen, MaxHuffBits) | |
| 443 | + || !mkgzprecode(dofftab, lzb->offcount, Noff, MaxHuffBits)) | |
| 444 | + return FlateInternal; | |
| 445 | + | |
| 446 | + ndyn = huffcodes(&dyncode, dlitlentab, dofftab); | |
| 447 | + if(ndyn < 0) | |
| 448 | + return FlateInternal; | |
| 449 | + ndyn += bitcost(dlitlentab, lzb->litlencount, Nlitlen) | |
| 450 | + + bitcost(dofftab, lzb->offcount, Noff) | |
| 451 | + + lzb->excost; | |
| 452 | + | |
| 453 | + memset(litcount, 0, sizeof litcount); | |
| 454 | + | |
| 455 | + nslop = nunc; | |
| 456 | + if(nslop > &lz->hist[HistSize] - slop) | |
| 457 | + nslop = &lz->hist[HistSize] - slop; | |
| 458 | + | |
| 459 | + for(i = 0; i < nslop; i++) | |
| 460 | + litcount[slop[i]]++; | |
| 461 | + hslop = &lz->hist[HistSlop - nslop]; | |
| 462 | + for(; i < nunc; i++) | |
| 463 | + litcount[hslop[i]]++; | |
| 464 | + litcount[DeflateEob]++; | |
| 465 | + | |
| 466 | + if(!mkgzprecode(hlitlentab, litcount, Nlitlen, MaxHuffBits)) | |
| 467 | + return FlateInternal; | |
| 468 | + nhuff = huffcodes(&hdyncode, hlitlentab, hofftab); | |
| 469 | + if(nhuff < 0) | |
| 470 | + return FlateInternal; | |
| 471 | + nhuff += bitcost(hlitlentab, litcount, Nlitlen); | |
| 472 | + | |
| 473 | + nfix = bitcost(litlentab, lzb->litlencount, Nlitlen) | |
| 474 | + + bitcost(offtab, lzb->offcount, Noff) | |
| 475 | + + lzb->excost; | |
| 476 | + | |
| 477 | + lzput(lz, lz->eof && !lz->avail, 1); | |
| 478 | + | |
| 479 | + if(lz->debug){ | |
| 480 | + fprint(2, "block: bytes=%lud entries=%ld extra bits=%d\n\tuncompressed=%lud fixed=%lud dynamic=%lud huffman=%lud\n", | |
| 481 | + nunc, lzb->eparse - lzb->parse, lzb->excost, (nunc + 4) * 8, nfix, ndyn, nhuff); | |
| 482 | + fprint(2, "\tnlit=%lud matches=%lud eof=%d\n", nlits, nmatches, lz->eof && !lz->avail); | |
| 483 | + } | |
| 484 | + | |
| 485 | + if((nunc + 4) * 8 < ndyn && (nunc + 4) * 8 < nfix && (nunc + 4) * 8 < nhuff){ | |
| 486 | + lzput(lz, DeflateUnc, 2); | |
| 487 | + lzflushbits(lz); | |
| 488 | + | |
| 489 | + lzput(lz, nunc & 0xff, 8); | |
| 490 | + lzput(lz, (nunc >> 8) & 0xff, 8); | |
| 491 | + lzput(lz, ~nunc & 0xff, 8); | |
| 492 | + lzput(lz, (~nunc >> 8) & 0xff, 8); | |
| 493 | + lzflush(lz); | |
| 494 | + | |
| 495 | + lzwrite(lz, slop, nslop); | |
| 496 | + lzwrite(lz, &lz->hist[HistSlop], nunc - nslop); | |
| 497 | + }else if(ndyn < nfix && ndyn < nhuff){ | |
| 498 | + lzput(lz, DeflateDyn, 2); | |
| 499 | + | |
| 500 | + wrdyncode(lz, &dyncode); | |
| 501 | + wrblock(lz, slop - lz->hist, lzb->parse, lzb->eparse, dlitlentab, dofftab); | |
| 502 | + lzput(lz, dlitlentab[DeflateEob].encode, dlitlentab[DeflateEob].bits); | |
| 503 | + }else if(nhuff < nfix){ | |
| 504 | + lzput(lz, DeflateDyn, 2); | |
| 505 | + | |
| 506 | + wrdyncode(lz, &hdyncode); | |
| 507 | + | |
| 508 | + m = 0; | |
| 509 | + for(i = nunc; i > MaxLitRun; i -= MaxLitRun) | |
| 510 | + lzb->parse[m++] = MaxLitRun; | |
| 511 | + lzb->parse[m++] = i; | |
| 512 | + | |
| 513 | + wrblock(lz, slop - lz->hist, lzb->parse, lzb->parse + m, hlitlentab, hofftab); | |
| 514 | + lzput(lz, hlitlentab[DeflateEob].encode, hlitlentab[DeflateEob].bits); | |
| 515 | + }else{ | |
| 516 | + lzput(lz, DeflateFix, 2); | |
| 517 | + | |
| 518 | + wrblock(lz, slop - lz->hist, lzb->parse, lzb->eparse, litlentab, offtab); | |
| 519 | + lzput(lz, litlentab[DeflateEob].encode, litlentab[DeflateEob].bits); | |
| 520 | + } | |
| 521 | + | |
| 522 | + if(lz->eof && !lz->avail){ | |
| 523 | + lzflushbits(lz); | |
| 524 | + lzflush(lz); | |
| 525 | + } | |
| 526 | + return FlateOk; | |
| 527 | +} | |
| 528 | + | |
| 529 | +static void | |
| 530 | +lzwrite(LZstate *lz, void *buf, int n) | |
| 531 | +{ | |
| 532 | + int nw; | |
| 533 | + | |
| 534 | + if(n && lz->w){ | |
| 535 | + nw = (*lz->w)(lz->wr, buf, n); | |
| 536 | + if(nw != n){ | |
| 537 | + lz->w = nil; | |
| 538 | + lz->wbad = 1; | |
| 539 | + }else | |
| 540 | + lz->totw += n; | |
| 541 | + } | |
| 542 | +} | |
| 543 | + | |
| 544 | +static void | |
| 545 | +lzflush(LZstate *lz) | |
| 546 | +{ | |
| 547 | + lzwrite(lz, lz->obuf, lz->out - lz->obuf); | |
| 548 | + lz->out = lz->obuf; | |
| 549 | +} | |
| 550 | + | |
| 551 | +static void | |
| 552 | +lzput(LZstate *lz, ulong bits, int nbits) | |
| 553 | +{ | |
| 554 | + bits = (bits << lz->nbits) | lz->bits; | |
| 555 | + for(nbits += lz->nbits; nbits >= 8; nbits -= 8){ | |
| 556 | + *lz->out++ = bits; | |
| 557 | + if(lz->out == lz->eout) | |
| 558 | + lzflush(lz); | |
| 559 | + bits >>= 8; | |
| 560 | + } | |
| 561 | + lz->bits = bits; | |
| 562 | + lz->nbits = nbits; | |
| 563 | +} | |
| 564 | + | |
| 565 | +static void | |
| 566 | +lzflushbits(LZstate *lz) | |
| 567 | +{ | |
| 568 | + if(lz->nbits) | |
| 569 | + lzput(lz, 0, 8 - (lz->nbits & 7)); | |
| 570 | +} | |
| 571 | + | |
| 572 | +/* | |
| 573 | + * write out a block of n samples, | |
| 574 | + * given lz encoding and counts for huffman tables | |
| 575 | + */ | |
| 576 | +static void | |
| 577 | +wrblock(LZstate *out, int litoff, ushort *soff, ushort *eoff, Huff *litlentab, Huff *offtab) | |
| 578 | +{ | |
| 579 | + ushort *off; | |
| 580 | + int i, run, offset, lit, len, c; | |
| 581 | + | |
| 582 | + if(out->debug > 2){ | |
| 583 | + for(off = soff; off < eoff; ){ | |
| 584 | + offset = *off++; | |
| 585 | + run = offset & MaxLitRun; | |
| 586 | + if(run){ | |
| 587 | + for(i = 0; i < run; i++){ | |
| 588 | + lit = out->hist[litoff & (HistBlock - 1)]; | |
| 589 | + litoff++; | |
| 590 | + fprint(2, "\tlit %.2ux %c\n", lit, lit); | |
| 591 | + } | |
| 592 | + if(!(offset & LenFlag)) | |
| 593 | + continue; | |
| 594 | + len = offset >> LenShift; | |
| 595 | + offset = *off++; | |
| 596 | + }else if(offset & LenFlag){ | |
| 597 | + len = offset >> LenShift; | |
| 598 | + offset = *off++; | |
| 599 | + }else{ | |
| 600 | + len = 0; | |
| 601 | + offset >>= LenShift; | |
| 602 | + } | |
| 603 | + litoff += len + MinMatch; | |
| 604 | + fprint(2, "\t<%d, %d>\n", offset + 1, len + MinMatch); | |
| 605 | + } | |
| 606 | + } | |
| 607 | + | |
| 608 | + for(off = soff; off < eoff; ){ | |
| 609 | + offset = *off++; | |
| 610 | + run = offset & MaxLitRun; | |
| 611 | + if(run){ | |
| 612 | + for(i = 0; i < run; i++){ | |
| 613 | + lit = out->hist[litoff & (HistBlock - 1)]; | |
| 614 | + litoff++; | |
| 615 | + lzput(out, litlentab[lit].encode, litlentab[lit].bits); | |
| 616 | + } | |
| 617 | + if(!(offset & LenFlag)) | |
| 618 | + continue; | |
| 619 | + len = offset >> LenShift; | |
| 620 | + offset = *off++; | |
| 621 | + }else if(offset & LenFlag){ | |
| 622 | + len = offset >> LenShift; | |
| 623 | + offset = *off++; | |
| 624 | + }else{ | |
| 625 | + len = 0; | |
| 626 | + offset >>= LenShift; | |
| 627 | + } | |
| 628 | + litoff += len + MinMatch; | |
| 629 | + c = lencode[len]; | |
| 630 | + lzput(out, litlentab[c].encode, litlentab[c].bits); | |
| 631 | + c -= LenStart; | |
| 632 | + if(litlenextra[c]) | |
| 633 | + lzput(out, len - litlenbase[c], litlenextra[c]); | |
| 634 | + | |
| 635 | + if(offset < MaxOffCode) | |
| 636 | + c = offcode[offset]; | |
| 637 | + else | |
| 638 | + c = bigoffcode[offset >> 7]; | |
| 639 | + lzput(out, offtab[c].encode, offtab[c].bits); | |
| 640 | + if(offextra[c]) | |
| 641 | + lzput(out, offset - offbase[c], offextra[c]); | |
| 642 | + } | |
| 643 | +} | |
| 644 | + | |
| 645 | +/* | |
| 646 | + * look for the longest, closest string which matches | |
| 647 | + * the next prefix. the clever part here is looking for | |
| 648 | + * a string 1 longer than the previous best match. | |
| 649 | + * | |
| 650 | + * follows the recommendation of limiting number of chains | |
| 651 | + * which are checked. this appears to be the best heuristic. | |
| 652 | + */ | |
| 653 | +static int | |
| 654 | +lzmatch(int now, int then, uchar *p, uchar *es, ushort *nexts, uchar *hist, int runlen, int check, int *m) | |
| 655 | +{ | |
| 656 | + uchar *s, *t; | |
| 657 | + int ml, off, last; | |
| 658 | + | |
| 659 | + ml = check; | |
| 660 | + if(runlen >= 8) | |
| 661 | + check >>= 2; | |
| 662 | + *m = 0; | |
| 663 | + if(p + runlen >= es) | |
| 664 | + return runlen; | |
| 665 | + last = 0; | |
| 666 | + for(; check-- > 0; then = nexts[then & (MaxOff-1)]){ | |
| 667 | + off = (ushort)(now - then); | |
| 668 | + if(off <= last || off > MaxOff) | |
| 669 | + break; | |
| 670 | + s = p + runlen; | |
| 671 | + t = hist + (((p - hist) - off) & (HistBlock-1)); | |
| 672 | + t += runlen; | |
| 673 | + for(; s >= p; s--){ | |
| 674 | + if(*s != *t) | |
| 675 | + goto matchloop; | |
| 676 | + t--; | |
| 677 | + } | |
| 678 | + | |
| 679 | + /* | |
| 680 | + * we have a new best match. | |
| 681 | + * extend it to it's maximum length | |
| 682 | + */ | |
| 683 | + t += runlen + 2; | |
| 684 | + s += runlen + 2; | |
| 685 | + for(; s < es; s++){ | |
| 686 | + if(*s != *t) | |
| 687 | + break; | |
| 688 | + t++; | |
| 689 | + } | |
| 690 | + runlen = s - p; | |
| 691 | + *m = off - 1; | |
| 692 | + if(s == es || runlen > ml) | |
| 693 | + break; | |
| 694 | +matchloop:; | |
| 695 | + last = off; | |
| 696 | + } | |
| 697 | + return runlen; | |
| 698 | +} | |
| 699 | + | |
| 700 | +static int | |
| 701 | +lzcomp(LZstate *lz, LZblock *lzb, uchar *ep, ushort *parse, int finish) | |
| 702 | +{ | |
| 703 | + ulong cont, excost, *litlencount, *offcount; | |
| 704 | + uchar *p, *q, *s, *es; | |
| 705 | + ushort *nexts, *hash; | |
| 706 | + int v, i, h, runlen, n, now, then, m, prevlen, prevoff, maxdefer; | |
| 707 | + | |
| 708 | + litlencount = lzb->litlencount; | |
| 709 | + offcount = lzb->offcount; | |
| 710 | + nexts = lz->nexts; | |
| 711 | + hash = lz->hash; | |
| 712 | + now = lz->now; | |
| 713 | + | |
| 714 | + p = &lz->hist[lz->pos]; | |
| 715 | + if(lz->prevlen != MinMatch - 1) | |
| 716 | + p++; | |
| 717 | + | |
| 718 | + /* | |
| 719 | + * hash in the links for any hanging link positions, | |
| 720 | + * and calculate the hash for the current position. | |
| 721 | + */ | |
| 722 | + n = MinMatch; | |
| 723 | + if(n > ep - p) | |
| 724 | + n = ep - p; | |
| 725 | + cont = 0; | |
| 726 | + for(i = 0; i < n - 1; i++){ | |
| 727 | + m = now - ((MinMatch-1) - i); | |
| 728 | + if(m < lz->dot) | |
| 729 | + continue; | |
| 730 | + s = lz->hist + (((p - lz->hist) - (now - m)) & (HistBlock-1)); | |
| 731 | + | |
| 732 | + cont = (s[0] << 16) | (s[1] << 8) | s[2]; | |
| 733 | + h = hashit(cont); | |
| 734 | + prevoff = 0; | |
| 735 | + for(then = hash[h]; ; then = nexts[then & (MaxOff-1)]){ | |
| 736 | + v = (ushort)(now - then); | |
| 737 | + if(v <= prevoff || v >= (MinMatch-1) - i) | |
| 738 | + break; | |
| 739 | + prevoff = v; | |
| 740 | + } | |
| 741 | + if(then == (ushort)m) | |
| 742 | + continue; | |
| 743 | + nexts[m & (MaxOff-1)] = hash[h]; | |
| 744 | + hash[h] = m; | |
| 745 | + } | |
| 746 | + for(i = 0; i < n; i++) | |
| 747 | + cont = (cont << 8) | p[i]; | |
| 748 | + | |
| 749 | + /* | |
| 750 | + * now must point to the index in the nexts array | |
| 751 | + * corresponding to p's position in the history | |
| 752 | + */ | |
| 753 | + prevlen = lz->prevlen; | |
| 754 | + prevoff = lz->prevoff; | |
| 755 | + maxdefer = lz->maxcheck >> 2; | |
| 756 | + excost = 0; | |
| 757 | + v = lzb->lastv; | |
| 758 | + for(;;){ | |
| 759 | + es = p + MaxMatch; | |
| 760 | + if(es > ep){ | |
| 761 | + if(!finish || p >= ep) | |
| 762 | + break; | |
| 763 | + es = ep; | |
| 764 | + } | |
| 765 | + | |
| 766 | + h = hashit(cont); | |
| 767 | + runlen = lzmatch(now, hash[h], p, es, nexts, lz->hist, prevlen, lz->maxcheck, &m); | |
| 768 | + | |
| 769 | + /* | |
| 770 | + * back out of small matches too far in the past | |
| 771 | + */ | |
| 772 | + if(runlen == MinMatch && m >= MinMatchMaxOff){ | |
| 773 | + runlen = MinMatch - 1; | |
| 774 | + m = 0; | |
| 775 | + } | |
| 776 | + | |
| 777 | + /* | |
| 778 | + * record the encoding and increment counts for huffman trees | |
| 779 | + * if we get a match, defer selecting it until we check for | |
| 780 | + * a longer match at the next position. | |
| 781 | + */ | |
| 782 | + if(prevlen >= runlen && prevlen != MinMatch - 1){ | |
| 783 | + /* | |
| 784 | + * old match at least as good; use that one | |
| 785 | + */ | |
| 786 | + n = prevlen - MinMatch; | |
| 787 | + if(v || n){ | |
| 788 | + *parse++ = v | LenFlag | (n << LenShift); | |
| 789 | + *parse++ = prevoff; | |
| 790 | + }else | |
| 791 | + *parse++ = prevoff << LenShift; | |
| 792 | + v = 0; | |
| 793 | + | |
| 794 | + n = lencode[n]; | |
| 795 | + litlencount[n]++; | |
| 796 | + excost += litlenextra[n - LenStart]; | |
| 797 | + | |
| 798 | + if(prevoff < MaxOffCode) | |
| 799 | + n = offcode[prevoff]; | |
| 800 | + else | |
| 801 | + n = bigoffcode[prevoff >> 7]; | |
| 802 | + offcount[n]++; | |
| 803 | + excost += offextra[n]; | |
| 804 | + | |
| 805 | + runlen = prevlen - 1; | |
| 806 | + prevlen = MinMatch - 1; | |
| 807 | + nmatches++; | |
| 808 | + }else if(runlen == MinMatch - 1){ | |
| 809 | + /* | |
| 810 | + * no match; just put out the literal | |
| 811 | + */ | |
| 812 | + if(++v == MaxLitRun){ | |
| 813 | + *parse++ = v; | |
| 814 | + v = 0; | |
| 815 | + } | |
| 816 | + litlencount[*p]++; | |
| 817 | + nlits++; | |
| 818 | + runlen = 1; | |
| 819 | + }else{ | |
| 820 | + if(prevlen != MinMatch - 1){ | |
| 821 | + /* | |
| 822 | + * longer match now. output previous literal, | |
| 823 | + * update current match, and try again | |
| 824 | + */ | |
| 825 | + if(++v == MaxLitRun){ | |
| 826 | + *parse++ = v; | |
| 827 | + v = 0; | |
| 828 | + } | |
| 829 | + litlencount[p[-1]]++; | |
| 830 | + nlits++; | |
| 831 | + } | |
| 832 | + | |
| 833 | + prevoff = m; | |
| 834 | + | |
| 835 | + if(runlen < maxdefer){ | |
| 836 | + prevlen = runlen; | |
| 837 | + runlen = 1; | |
| 838 | + }else{ | |
| 839 | + n = runlen - MinMatch; | |
| 840 | + if(v || n){ | |
| 841 | + *parse++ = v | LenFlag | (n << LenShift); | |
| 842 | + *parse++ = prevoff; | |
| 843 | + }else | |
| 844 | + *parse++ = prevoff << LenShift; | |
| 845 | + v = 0; | |
| 846 | + | |
| 847 | + n = lencode[n]; | |
| 848 | + litlencount[n]++; | |
| 849 | + excost += litlenextra[n - LenStart]; | |
| 850 | + | |
| 851 | + if(prevoff < MaxOffCode) | |
| 852 | + n = offcode[prevoff]; | |
| 853 | + else | |
| 854 | + n = bigoffcode[prevoff >> 7]; | |
| 855 | + offcount[n]++; | |
| 856 | + excost += offextra[n]; | |
| 857 | + | |
| 858 | + prevlen = MinMatch - 1; | |
| 859 | + nmatches++; | |
| 860 | + } | |
| 861 | + } | |
| 862 | + | |
| 863 | + /* | |
| 864 | + * update the hash for the newly matched data | |
| 865 | + * this is constructed so the link for the old | |
| 866 | + * match in this position must be at the end of a chain, | |
| 867 | + * and will expire when this match is added, ie it will | |
| 868 | + * never be examined by the match loop. | |
| 869 | + * add to the hash chain only if we have the real hash data. | |
| 870 | + */ | |
| 871 | + for(q = p + runlen; p != q; p++){ | |
| 872 | + if(p + MinMatch <= ep){ | |
| 873 | + h = hashit(cont); | |
| 874 | + nexts[now & (MaxOff-1)] = hash[h]; | |
| 875 | + hash[h] = now; | |
| 876 | + if(p + MinMatch < ep) | |
| 877 | + cont = (cont << 8) | p[MinMatch]; | |
| 878 | + } | |
| 879 | + now++; | |
| 880 | + } | |
| 881 | + } | |
| 882 | + | |
| 883 | + /* | |
| 884 | + * we can just store away the lazy state and | |
| 885 | + * pick it up next time. the last block will have finish set | |
| 886 | + * so we won't have any pending matches | |
| 887 | + * however, we need to correct for how much we've encoded | |
| 888 | + */ | |
| 889 | + if(prevlen != MinMatch - 1) | |
| 890 | + p--; | |
| 891 | + | |
| 892 | + lzb->excost += excost; | |
| 893 | + lzb->eparse = parse; | |
| 894 | + lzb->lastv = v; | |
| 895 | + | |
| 896 | + lz->now = now; | |
| 897 | + lz->prevlen = prevlen; | |
| 898 | + lz->prevoff = prevoff; | |
| 899 | + | |
| 900 | + return p - &lz->hist[lz->pos]; | |
| 901 | +} | |
| 902 | + | |
| 903 | +/* | |
| 904 | + * make up the dynamic code tables, and return the number of bits | |
| 905 | + * needed to transmit them. | |
| 906 | + */ | |
| 907 | +static int | |
| 908 | +huffcodes(Dyncode *dc, Huff *littab, Huff *offtab) | |
| 909 | +{ | |
| 910 | + Huff *codetab; | |
| 911 | + uchar *codes, *codeaux; | |
| 912 | + ulong codecount[Nclen], excost; | |
| 913 | + int i, n, m, v, c, nlit, noff, ncode, nclen; | |
| 914 | + | |
| 915 | + codetab = dc->codetab; | |
| 916 | + codes = dc->codes; | |
| 917 | + codeaux = dc->codeaux; | |
| 918 | + | |
| 919 | + /* | |
| 920 | + * trim the sizes of the tables | |
| 921 | + */ | |
| 922 | + for(nlit = Nlitlen; nlit > 257 && littab[nlit-1].bits == 0; nlit--) | |
| 923 | + ; | |
| 924 | + for(noff = Noff; noff > 1 && offtab[noff-1].bits == 0; noff--) | |
| 925 | + ; | |
| 926 | + | |
| 927 | + /* | |
| 928 | + * make the code-length code | |
| 929 | + */ | |
| 930 | + for(i = 0; i < nlit; i++) | |
| 931 | + codes[i] = littab[i].bits; | |
| 932 | + for(i = 0; i < noff; i++) | |
| 933 | + codes[i + nlit] = offtab[i].bits; | |
| 934 | + | |
| 935 | + /* | |
| 936 | + * run-length compress the code-length code | |
| 937 | + */ | |
| 938 | + excost = 0; | |
| 939 | + c = 0; | |
| 940 | + ncode = nlit+noff; | |
| 941 | + for(i = 0; i < ncode; ){ | |
| 942 | + n = i + 1; | |
| 943 | + v = codes[i]; | |
| 944 | + while(n < ncode && v == codes[n]) | |
| 945 | + n++; | |
| 946 | + n -= i; | |
| 947 | + i += n; | |
| 948 | + if(v == 0){ | |
| 949 | + while(n >= 11){ | |
| 950 | + m = n; | |
| 951 | + if(m > 138) | |
| 952 | + m = 138; | |
| 953 | + codes[c] = 18; | |
| 954 | + codeaux[c++] = m - 11; | |
| 955 | + n -= m; | |
| 956 | + excost += 7; | |
| 957 | + } | |
| 958 | + if(n >= 3){ | |
| 959 | + codes[c] = 17; | |
| 960 | + codeaux[c++] = n - 3; | |
| 961 | + n = 0; | |
| 962 | + excost += 3; | |
| 963 | + } | |
| 964 | + } | |
| 965 | + while(n--){ | |
| 966 | + codes[c++] = v; | |
| 967 | + while(n >= 3){ | |
| 968 | + m = n; | |
| 969 | + if(m > 6) | |
| 970 | + m = 6; | |
| 971 | + codes[c] = 16; | |
| 972 | + codeaux[c++] = m - 3; | |
| 973 | + n -= m; | |
| 974 | + excost += 3; | |
| 975 | + } | |
| 976 | + } | |
| 977 | + } | |
| 978 | + | |
| 979 | + memset(codecount, 0, sizeof codecount); | |
| 980 | + for(i = 0; i < c; i++) | |
| 981 | + codecount[codes[i]]++; | |
| 982 | + if(!mkgzprecode(codetab, codecount, Nclen, 8)) | |
| 983 | + return -1; | |
| 984 | + | |
| 985 | + for(nclen = Nclen; nclen > 4 && codetab[clenorder[nclen-1]].bits == 0; nclen--) | |
| 986 | + ; | |
| 987 | + | |
| 988 | + dc->nlit = nlit; | |
| 989 | + dc->noff = noff; | |
| 990 | + dc->nclen = nclen; | |
| 991 | + dc->ncode = c; | |
| 992 | + | |
| 993 | + return 5 + 5 + 4 + nclen * 3 + bitcost(codetab, codecount, Nclen) + excost; | |
| 994 | +} | |
| 995 | + | |
| 996 | +static void | |
| 997 | +wrdyncode(LZstate *out, Dyncode *dc) | |
| 998 | +{ | |
| 999 | + Huff *codetab; | |
| 1000 | + uchar *codes, *codeaux; | |
| 1001 | + int i, v, c; | |
| 1002 | + | |
| 1003 | + /* | |
| 1004 | + * write out header, then code length code lengths, | |
| 1005 | + * and code lengths | |
| 1006 | + */ | |
| 1007 | + lzput(out, dc->nlit-257, 5); | |
| 1008 | + lzput(out, dc->noff-1, 5); | |
| 1009 | + lzput(out, dc->nclen-4, 4); | |
| 1010 | + | |
| 1011 | + codetab = dc->codetab; | |
| 1012 | + for(i = 0; i < dc->nclen; i++) | |
| 1013 | + lzput(out, codetab[clenorder[i]].bits, 3); | |
| 1014 | + | |
| 1015 | + codes = dc->codes; | |
| 1016 | + codeaux = dc->codeaux; | |
| 1017 | + c = dc->ncode; | |
| 1018 | + for(i = 0; i < c; i++){ | |
| 1019 | + v = codes[i]; | |
| 1020 | + lzput(out, codetab[v].encode, codetab[v].bits); | |
| 1021 | + if(v >= 16){ | |
| 1022 | + if(v == 16) | |
| 1023 | + lzput(out, codeaux[i], 2); | |
| 1024 | + else if(v == 17) | |
| 1025 | + lzput(out, codeaux[i], 3); | |
| 1026 | + else /* v == 18 */ | |
| 1027 | + lzput(out, codeaux[i], 7); | |
| 1028 | + } | |
| 1029 | + } | |
| 1030 | +} | |
| 1031 | + | |
| 1032 | +static int | |
| 1033 | +bitcost(Huff *tab, ulong *count, int n) | |
| 1034 | +{ | |
| 1035 | + ulong tot; | |
| 1036 | + int i; | |
| 1037 | + | |
| 1038 | + tot = 0; | |
| 1039 | + for(i = 0; i < n; i++) | |
| 1040 | + tot += count[i] * tab[i].bits; | |
| 1041 | + return tot; | |
| 1042 | +} | |
| 1043 | + | |
| 1044 | +static int | |
| 1045 | +mkgzprecode(Huff *tab, ulong *count, int n, int maxbits) | |
| 1046 | +{ | |
| 1047 | + ulong bitcount[MaxHuffBits]; | |
| 1048 | + int i, nbits; | |
| 1049 | + | |
| 1050 | + nbits = mkprecode(tab, count, n, maxbits, bitcount); | |
| 1051 | + for(i = 0; i < n; i++){ | |
| 1052 | + if(tab[i].bits == -1) | |
| 1053 | + tab[i].bits = 0; | |
| 1054 | + else if(tab[i].bits == 0){ | |
| 1055 | + if(nbits != 0 || bitcount[0] != 1) | |
| 1056 | + return 0; | |
| 1057 | + bitcount[1] = 1; | |
| 1058 | + bitcount[0] = 0; | |
| 1059 | + nbits = 1; | |
| 1060 | + tab[i].bits = 1; | |
| 1061 | + } | |
| 1062 | + } | |
| 1063 | + if(bitcount[0] != 0) | |
| 1064 | + return 0; | |
| 1065 | + return hufftabinit(tab, n, bitcount, nbits); | |
| 1066 | +} | |
| 1067 | + | |
| 1068 | +static int | |
| 1069 | +hufftabinit(Huff *tab, int n, ulong *bitcount, int nbits) | |
| 1070 | +{ | |
| 1071 | + ulong code, nc[MaxHuffBits]; | |
| 1072 | + int i, bits; | |
| 1073 | + | |
| 1074 | + code = 0; | |
| 1075 | + for(bits = 1; bits <= nbits; bits++){ | |
| 1076 | + code = (code + bitcount[bits-1]) << 1; | |
| 1077 | + nc[bits] = code; | |
| 1078 | + } | |
| 1079 | + | |
| 1080 | + for(i = 0; i < n; i++){ | |
| 1081 | + bits = tab[i].bits; | |
| 1082 | + if(bits){ | |
| 1083 | + code = nc[bits]++ << (16 - bits); | |
| 1084 | + if(code & ~0xffff) | |
| 1085 | + return 0; | |
| 1086 | + tab[i].encode = revtab[code >> 8] | (revtab[code & 0xff] << 8); | |
| 1087 | + } | |
| 1088 | + } | |
| 1089 | + return 1; | |
| 1090 | +} | |
| 1091 | + | |
| 1092 | + | |
| 1093 | +/* | |
| 1094 | + * this should be in a library | |
| 1095 | + */ | |
| 1096 | +struct Chain | |
| 1097 | +{ | |
| 1098 | + ulong count; /* occurances of everything in the chain */ | |
| 1099 | + ushort leaf; /* leaves to the left of chain, or leaf value */ | |
| 1100 | + char col; /* ref count for collecting unused chains */ | |
| 1101 | + char gen; /* need to generate chains for next lower level */ | |
| 1102 | + Chain *up; /* Chain up in the lists */ | |
| 1103 | +}; | |
| 1104 | + | |
| 1105 | +struct Chains | |
| 1106 | +{ | |
| 1107 | + Chain *lists[(MaxHuffBits - 1) * 2]; | |
| 1108 | + ulong leafcount[MaxLeaf]; /* sorted list of leaf counts */ | |
| 1109 | + ushort leafmap[MaxLeaf]; /* map to actual leaf number */ | |
| 1110 | + int nleaf; /* number of leaves */ | |
| 1111 | + Chain chains[ChainMem]; | |
| 1112 | + Chain *echains; | |
| 1113 | + Chain *free; | |
| 1114 | + char col; | |
| 1115 | + int nlists; | |
| 1116 | +}; | |
| 1117 | + | |
| 1118 | +/* | |
| 1119 | + * fast, low space overhead algorithm for max depth huffman type codes | |
| 1120 | + * | |
| 1121 | + * J. Katajainen, A. Moffat and A. Turpin, "A fast and space-economical | |
| 1122 | + * algorithm for length-limited coding," Proc. Intl. Symp. on Algorithms | |
| 1123 | + * and Computation, Cairns, Australia, Dec. 1995, Lecture Notes in Computer | |
| 1124 | + * Science, Vol 1004, J. Staples, P. Eades, N. Katoh, and A. Moffat, eds., | |
| 1125 | + * pp 12-21, Springer Verlag, New York, 1995. | |
| 1126 | + */ | |
| 1127 | +static int | |
| 1128 | +mkprecode(Huff *tab, ulong *count, int n, int maxbits, ulong *bitcount) | |
| 1129 | +{ | |
| 1130 | + Chains cs; | |
| 1131 | + Chain *c; | |
| 1132 | + int i, m, em, bits; | |
| 1133 | + | |
| 1134 | + /* | |
| 1135 | + * set up the sorted list of leaves | |
| 1136 | + */ | |
| 1137 | + m = 0; | |
| 1138 | + for(i = 0; i < n; i++){ | |
| 1139 | + tab[i].bits = -1; | |
| 1140 | + tab[i].encode = 0; | |
| 1141 | + if(count[i] != 0){ | |
| 1142 | + cs.leafcount[m] = count[i]; | |
| 1143 | + cs.leafmap[m] = i; | |
| 1144 | + m++; | |
| 1145 | + } | |
| 1146 | + } | |
| 1147 | + if(m < 2){ | |
| 1148 | + if(m != 0){ | |
| 1149 | + tab[cs.leafmap[0]].bits = 0; | |
| 1150 | + bitcount[0] = 1; | |
| 1151 | + }else | |
| 1152 | + bitcount[0] = 0; | |
| 1153 | + return 0; | |
| 1154 | + } | |
| 1155 | + cs.nleaf = m; | |
| 1156 | + leafsort(cs.leafcount, cs.leafmap, 0, m); | |
| 1157 | + | |
| 1158 | + for(i = 0; i < m; i++) | |
| 1159 | + cs.leafcount[i] = count[cs.leafmap[i]]; | |
| 1160 | + | |
| 1161 | + /* | |
| 1162 | + * set up free list | |
| 1163 | + */ | |
| 1164 | + cs.free = &cs.chains[2]; | |
| 1165 | + cs.echains = &cs.chains[ChainMem]; | |
| 1166 | + cs.col = 1; | |
| 1167 | + | |
| 1168 | + /* | |
| 1169 | + * initialize chains for each list | |
| 1170 | + */ | |
| 1171 | + c = &cs.chains[0]; | |
| 1172 | + c->count = cs.leafcount[0]; | |
| 1173 | + c->leaf = 1; | |
| 1174 | + c->col = cs.col; | |
| 1175 | + c->up = nil; | |
| 1176 | + c->gen = 0; | |
| 1177 | + cs.chains[1] = cs.chains[0]; | |
| 1178 | + cs.chains[1].leaf = 2; | |
| 1179 | + cs.chains[1].count = cs.leafcount[1]; | |
| 1180 | + for(i = 0; i < maxbits-1; i++){ | |
| 1181 | + cs.lists[i * 2] = &cs.chains[0]; | |
| 1182 | + cs.lists[i * 2 + 1] = &cs.chains[1]; | |
| 1183 | + } | |
| 1184 | + | |
| 1185 | + cs.nlists = 2 * (maxbits - 1); | |
| 1186 | + m = 2 * m - 2; | |
| 1187 | + for(i = 2; i < m; i++) | |
| 1188 | + nextchain(&cs, cs.nlists - 2); | |
| 1189 | + | |
| 1190 | + bits = 0; | |
| 1191 | + bitcount[0] = cs.nleaf; | |
| 1192 | + for(c = cs.lists[cs.nlists - 1]; c != nil; c = c->up){ | |
| 1193 | + m = c->leaf; | |
| 1194 | + bitcount[bits++] -= m; | |
| 1195 | + bitcount[bits] = m; | |
| 1196 | + } | |
| 1197 | + m = 0; | |
| 1198 | + for(i = bits; i >= 0; i--) | |
| 1199 | + for(em = m + bitcount[i]; m < em; m++) | |
| 1200 | + tab[cs.leafmap[m]].bits = i; | |
| 1201 | + | |
| 1202 | + return bits; | |
| 1203 | +} | |
| 1204 | + | |
| 1205 | +/* | |
| 1206 | + * calculate the next chain on the list | |
| 1207 | + * we can always toss out the old chain | |
| 1208 | + */ | |
| 1209 | +static void | |
| 1210 | +nextchain(Chains *cs, int list) | |
| 1211 | +{ | |
| 1212 | + Chain *c, *oc; | |
| 1213 | + int i, nleaf, sumc; | |
| 1214 | + | |
| 1215 | + oc = cs->lists[list + 1]; | |
| 1216 | + cs->lists[list] = oc; | |
| 1217 | + if(oc == nil) | |
| 1218 | + return; | |
| 1219 | + | |
| 1220 | + /* | |
| 1221 | + * make sure we have all chains needed to make sumc | |
| 1222 | + * note it is possible to generate only one of these, | |
| 1223 | + * use twice that value for sumc, and then generate | |
| 1224 | + * the second if that preliminary sumc would be chosen. | |
| 1225 | + * however, this appears to be slower on current tests | |
| 1226 | + */ | |
| 1227 | + if(oc->gen){ | |
| 1228 | + nextchain(cs, list - 2); | |
| 1229 | + nextchain(cs, list - 2); | |
| 1230 | + oc->gen = 0; | |
| 1231 | + } | |
| 1232 | + | |
| 1233 | + /* | |
| 1234 | + * pick up the chain we're going to add; | |
| 1235 | + * collect unused chains no free ones are left | |
| 1236 | + */ | |
| 1237 | + for(c = cs->free; ; c++){ | |
| 1238 | + if(c >= cs->echains){ | |
| 1239 | + cs->col++; | |
| 1240 | + for(i = 0; i < cs->nlists; i++) | |
| 1241 | + for(c = cs->lists[i]; c != nil; c = c->up) | |
| 1242 | + c->col = cs->col; | |
| 1243 | + c = cs->chains; | |
| 1244 | + } | |
| 1245 | + if(c->col != cs->col) | |
| 1246 | + break; | |
| 1247 | + } | |
| 1248 | + | |
| 1249 | + /* | |
| 1250 | + * pick the cheapest of | |
| 1251 | + * 1) the next package from the previous list | |
| 1252 | + * 2) the next leaf | |
| 1253 | + */ | |
| 1254 | + nleaf = oc->leaf; | |
| 1255 | + sumc = 0; | |
| 1256 | + if(list > 0 && cs->lists[list-1] != nil) | |
| 1257 | + sumc = cs->lists[list-2]->count + cs->lists[list-1]->count; | |
| 1258 | + if(sumc != 0 && (nleaf >= cs->nleaf || cs->leafcount[nleaf] > sumc)){ | |
| 1259 | + c->count = sumc; | |
| 1260 | + c->leaf = oc->leaf; | |
| 1261 | + c->up = cs->lists[list-1]; | |
| 1262 | + c->gen = 1; | |
| 1263 | + }else if(nleaf >= cs->nleaf){ | |
| 1264 | + cs->lists[list + 1] = nil; | |
| 1265 | + return; | |
| 1266 | + }else{ | |
| 1267 | + c->leaf = nleaf + 1; | |
| 1268 | + c->count = cs->leafcount[nleaf]; | |
| 1269 | + c->up = oc->up; | |
| 1270 | + c->gen = 0; | |
| 1271 | + } | |
| 1272 | + cs->free = c + 1; | |
| 1273 | + | |
| 1274 | + cs->lists[list + 1] = c; | |
| 1275 | + c->col = cs->col; | |
| 1276 | +} | |
| 1277 | + | |
| 1278 | +static int | |
| 1279 | +pivot(ulong *c, int a, int n) | |
| 1280 | +{ | |
| 1281 | + int j, pi, pj, pk; | |
| 1282 | + | |
| 1283 | + j = n/6; | |
| 1284 | + pi = a + j; /* 1/6 */ | |
| 1285 | + j += j; | |
| 1286 | + pj = pi + j; /* 1/2 */ | |
| 1287 | + pk = pj + j; /* 5/6 */ | |
| 1288 | + if(c[pi] < c[pj]){ | |
| 1289 | + if(c[pi] < c[pk]){ | |
| 1290 | + if(c[pj] < c[pk]) | |
| 1291 | + return pj; | |
| 1292 | + return pk; | |
| 1293 | + } | |
| 1294 | + return pi; | |
| 1295 | + } | |
| 1296 | + if(c[pj] < c[pk]){ | |
| 1297 | + if(c[pi] < c[pk]) | |
| 1298 | + return pi; | |
| 1299 | + return pk; | |
| 1300 | + } | |
| 1301 | + return pj; | |
| 1302 | +} | |
| 1303 | + | |
| 1304 | +static void | |
| 1305 | +leafsort(ulong *leafcount, ushort *leafmap, int a, int n) | |
| 1306 | +{ | |
| 1307 | + ulong t; | |
| 1308 | + int j, pi, pj, pn; | |
| 1309 | + | |
| 1310 | + while(n > 1){ | |
| 1311 | + if(n > 10){ | |
| 1312 | + pi = pivot(leafcount, a, n); | |
| 1313 | + }else | |
| 1314 | + pi = a + (n>>1); | |
| 1315 | + | |
| 1316 | + t = leafcount[pi]; | |
| 1317 | + leafcount[pi] = leafcount[a]; | |
| 1318 | + leafcount[a] = t; | |
| 1319 | + t = leafmap[pi]; | |
| 1320 | + leafmap[pi] = leafmap[a]; | |
| 1321 | + leafmap[a] = t; | |
| 1322 | + pi = a; | |
| 1323 | + pn = a + n; | |
| 1324 | + pj = pn; | |
| 1325 | + for(;;){ | |
| 1326 | + do | |
| 1327 | + pi++; | |
| 1328 | + while(pi < pn && (leafcount[pi] < leafcount[a] || leafcount[pi] == leafcount[a] && leafmap[pi] > leafmap[a])); | |
| 1329 | + do | |
| 1330 | + pj--; | |
| 1331 | + while(pj > a && (leafcount[pj] > leafcount[a] || leafcount[pj] == leafcount[a] && leafmap[pj] < leafmap[a])); | |
| 1332 | + if(pj < pi) | |
| 1333 | + break; | |
| 1334 | + t = leafcount[pi]; | |
| 1335 | + leafcount[pi] = leafcount[pj]; | |
| 1336 | + leafcount[pj] = t; | |
| 1337 | + t = leafmap[pi]; | |
| 1338 | + leafmap[pi] = leafmap[pj]; | |
| 1339 | + leafmap[pj] = t; | |
| 1340 | + } | |
| 1341 | + t = leafcount[a]; | |
| 1342 | + leafcount[a] = leafcount[pj]; | |
| 1343 | + leafcount[pj] = t; | |
| 1344 | + t = leafmap[a]; | |
| 1345 | + leafmap[a] = leafmap[pj]; | |
| 1346 | + leafmap[pj] = t; | |
| 1347 | + j = pj - a; | |
| 1348 | + | |
| 1349 | + n = n-j-1; | |
| 1350 | + if(j >= n){ | |
| 1351 | + leafsort(leafcount, leafmap, a, j); | |
| 1352 | + a += j+1; | |
| 1353 | + }else{ | |
| 1354 | + leafsort(leafcount, leafmap, a + (j+1), n); | |
| 1355 | + n = j; | |
| 1356 | + } | |
| 1357 | + } | |
| 1358 | +} | |
| @@ -0,0 +1,55 @@ | ||
| 1 | +#include "lib9.h" | |
| 2 | +#include <flate.h> | |
| 3 | + | |
| 4 | +typedef struct Block Block; | |
| 5 | + | |
| 6 | +struct Block | |
| 7 | +{ | |
| 8 | + uchar *pos; | |
| 9 | + uchar *limit; | |
| 10 | +}; | |
| 11 | + | |
| 12 | +static int | |
| 13 | +blread(void *vb, void *buf, int n) | |
| 14 | +{ | |
| 15 | + Block *b; | |
| 16 | + | |
| 17 | + b = vb; | |
| 18 | + if(n > b->limit - b->pos) | |
| 19 | + n = b->limit - b->pos; | |
| 20 | + memmove(buf, b->pos, n); | |
| 21 | + b->pos += n; | |
| 22 | + return n; | |
| 23 | +} | |
| 24 | + | |
| 25 | +static int | |
| 26 | +blwrite(void *vb, void *buf, int n) | |
| 27 | +{ | |
| 28 | + Block *b; | |
| 29 | + | |
| 30 | + b = vb; | |
| 31 | + | |
| 32 | + if(n > b->limit - b->pos) | |
| 33 | + n = b->limit - b->pos; | |
| 34 | + memmove(b->pos, buf, n); | |
| 35 | + b->pos += n; | |
| 36 | + return n; | |
| 37 | +} | |
| 38 | + | |
| 39 | +int | |
| 40 | +deflateblock(uchar *dst, int dsize, uchar *src, int ssize, int level, int debug) | |
| 41 | +{ | |
| 42 | + Block bd, bs; | |
| 43 | + int ok; | |
| 44 | + | |
| 45 | + bs.pos = src; | |
| 46 | + bs.limit = src + ssize; | |
| 47 | + | |
| 48 | + bd.pos = dst; | |
| 49 | + bd.limit = dst + dsize; | |
| 50 | + | |
| 51 | + ok = deflate(&bd, blwrite, &bs, blread, level, debug); | |
| 52 | + if(ok != FlateOk) | |
| 53 | + return ok; | |
| 54 | + return bd.pos - dst; | |
| 55 | +} | |
| @@ -0,0 +1,59 @@ | ||
| 1 | +#include "lib9.h" | |
| 2 | +#include <flate.h> | |
| 3 | +#include "zlib.h" | |
| 4 | + | |
| 5 | +typedef struct ZRead ZRead; | |
| 6 | + | |
| 7 | +struct ZRead | |
| 8 | +{ | |
| 9 | + ulong adler; | |
| 10 | + void *rr; | |
| 11 | + int (*r)(void*, void*, int); | |
| 12 | +}; | |
| 13 | + | |
| 14 | +static int | |
| 15 | +zlread(void *vzr, void *buf, int n) | |
| 16 | +{ | |
| 17 | + ZRead *zr; | |
| 18 | + | |
| 19 | + zr = vzr; | |
| 20 | + n = (*zr->r)(zr->rr, buf, n); | |
| 21 | + if(n <= 0) | |
| 22 | + return n; | |
| 23 | + zr->adler = adler32(zr->adler, buf, n); | |
| 24 | + return n; | |
| 25 | +} | |
| 26 | + | |
| 27 | +int | |
| 28 | +deflatezlib(void *wr, int (*w)(void*, void*, int), void *rr, int (*r)(void*, void*, int), int level, int debug) | |
| 29 | +{ | |
| 30 | + ZRead zr; | |
| 31 | + uchar buf[4]; | |
| 32 | + int ok; | |
| 33 | + | |
| 34 | + buf[0] = ZlibDeflate | ZlibWin32k; | |
| 35 | + | |
| 36 | + /* bogus zlib encoding of compression level */ | |
| 37 | + buf[1] = ((level > 2) + (level > 5) + (level > 8)) << 6; | |
| 38 | + | |
| 39 | + /* header check field */ | |
| 40 | + buf[1] |= 31 - ((buf[0] << 8) | buf[1]) % 31; | |
| 41 | + if((*w)(wr, buf, 2) != 2) | |
| 42 | + return FlateOutputFail; | |
| 43 | + | |
| 44 | + zr.rr = rr; | |
| 45 | + zr.r = r; | |
| 46 | + zr.adler = 1; | |
| 47 | + ok = deflate(wr, w, &zr, zlread, level, debug); | |
| 48 | + if(ok != FlateOk) | |
| 49 | + return ok; | |
| 50 | + | |
| 51 | + buf[0] = zr.adler >> 24; | |
| 52 | + buf[1] = zr.adler >> 16; | |
| 53 | + buf[2] = zr.adler >> 8; | |
| 54 | + buf[3] = zr.adler; | |
| 55 | + if((*w)(wr, buf, 4) != 4) | |
| 56 | + return FlateOutputFail; | |
| 57 | + | |
| 58 | + return FlateOk; | |
| 59 | +} | |
| @@ -0,0 +1,33 @@ | ||
| 1 | +#include "lib9.h" | |
| 2 | +#include <flate.h> | |
| 3 | +#include "zlib.h" | |
| 4 | + | |
| 5 | +int | |
| 6 | +deflatezlibblock(uchar *dst, int dsize, uchar *src, int ssize, int level, int debug) | |
| 7 | +{ | |
| 8 | + ulong adler; | |
| 9 | + int n; | |
| 10 | + | |
| 11 | + if(dsize < 6) | |
| 12 | + return FlateOutputFail; | |
| 13 | + | |
| 14 | + n = deflateblock(dst + 2, dsize - 6, src, ssize, level, debug); | |
| 15 | + if(n < 0) | |
| 16 | + return n; | |
| 17 | + | |
| 18 | + dst[0] = ZlibDeflate | ZlibWin32k; | |
| 19 | + | |
| 20 | + /* bogus zlib encoding of compression level */ | |
| 21 | + dst[1] = ((level > 2) + (level > 5) + (level > 8)) << 6; | |
| 22 | + | |
| 23 | + /* header check field */ | |
| 24 | + dst[1] |= 31 - ((dst[0] << 8) | dst[1]) % 31; | |
| 25 | + | |
| 26 | + adler = adler32(1, src, ssize); | |
| 27 | + dst[n + 2] = adler >> 24; | |
| 28 | + dst[n + 3] = adler >> 16; | |
| 29 | + dst[n + 4] = adler >> 8; | |
| 30 | + dst[n + 5] = adler; | |
| 31 | + | |
| 32 | + return n + 6; | |
| 33 | +} | |
| @@ -0,0 +1,22 @@ | ||
| 1 | +#include "lib9.h" | |
| 2 | +#include <flate.h> | |
| 3 | + | |
| 4 | +char * | |
| 5 | +flateerr(int err) | |
| 6 | +{ | |
| 7 | + switch(err){ | |
| 8 | + case FlateOk: | |
| 9 | + return "no error"; | |
| 10 | + case FlateNoMem: | |
| 11 | + return "out of memory"; | |
| 12 | + case FlateInputFail: | |
| 13 | + return "input error"; | |
| 14 | + case FlateOutputFail: | |
| 15 | + return "output error"; | |
| 16 | + case FlateCorrupted: | |
| 17 | + return "corrupted data"; | |
| 18 | + case FlateInternal: | |
| 19 | + return "internal error"; | |
| 20 | + } | |
| 21 | + return "unknown error"; | |
| 22 | +} | |
| @@ -0,0 +1,692 @@ | ||
| 1 | +#include "lib9.h" | |
| 2 | +#include <flate.h> | |
| 3 | + | |
| 4 | +enum { | |
| 5 | + HistorySize= 32*1024, | |
| 6 | + BufSize= 4*1024, | |
| 7 | + MaxHuffBits= 17, /* maximum bits in a encoded code */ | |
| 8 | + Nlitlen= 288, /* number of litlen codes */ | |
| 9 | + Noff= 32, /* number of offset codes */ | |
| 10 | + Nclen= 19, /* number of codelen codes */ | |
| 11 | + LenShift= 10, /* code = len<<LenShift|code */ | |
| 12 | + LitlenBits= 7, /* number of bits in litlen decode table */ | |
| 13 | + OffBits= 6, /* number of bits in offset decode table */ | |
| 14 | + ClenBits= 6, /* number of bits in code len decode table */ | |
| 15 | + MaxFlatBits= LitlenBits, | |
| 16 | + MaxLeaf= Nlitlen | |
| 17 | +}; | |
| 18 | + | |
| 19 | +typedef struct Input Input; | |
| 20 | +typedef struct History History; | |
| 21 | +typedef struct Huff Huff; | |
| 22 | + | |
| 23 | +struct Input | |
| 24 | +{ | |
| 25 | + int error; /* first error encountered, or FlateOk */ | |
| 26 | + void *wr; | |
| 27 | + int (*w)(void*, void*, int); | |
| 28 | + void *getr; | |
| 29 | + int (*get)(void*); | |
| 30 | + ulong sreg; | |
| 31 | + int nbits; | |
| 32 | +}; | |
| 33 | + | |
| 34 | +struct History | |
| 35 | +{ | |
| 36 | + uchar his[HistorySize]; | |
| 37 | + uchar *cp; /* current pointer in history */ | |
| 38 | + int full; /* his has been filled up at least once */ | |
| 39 | +}; | |
| 40 | + | |
| 41 | +struct Huff | |
| 42 | +{ | |
| 43 | + int maxbits; /* max bits for any code */ | |
| 44 | + int minbits; /* min bits to get before looking in flat */ | |
| 45 | + int flatmask; /* bits used in "flat" fast decoding table */ | |
| 46 | + ulong flat[1<<MaxFlatBits]; | |
| 47 | + ulong maxcode[MaxHuffBits]; | |
| 48 | + ulong last[MaxHuffBits]; | |
| 49 | + ulong decode[MaxLeaf]; | |
| 50 | +}; | |
| 51 | + | |
| 52 | +/* litlen code words 257-285 extra bits */ | |
| 53 | +static int litlenextra[Nlitlen-257] = | |
| 54 | +{ | |
| 55 | +/* 257 */ 0, 0, 0, | |
| 56 | +/* 260 */ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, | |
| 57 | +/* 270 */ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, | |
| 58 | +/* 280 */ 4, 5, 5, 5, 5, 0, 0, 0 | |
| 59 | +}; | |
| 60 | + | |
| 61 | +static int litlenbase[Nlitlen-257]; | |
| 62 | + | |
| 63 | +/* offset code word extra bits */ | |
| 64 | +static int offextra[Noff] = | |
| 65 | +{ | |
| 66 | + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, | |
| 67 | + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, | |
| 68 | + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, | |
| 69 | + 0, 0, | |
| 70 | +}; | |
| 71 | +static int offbase[Noff]; | |
| 72 | + | |
| 73 | +/* order code lengths */ | |
| 74 | +static int clenorder[Nclen] = | |
| 75 | +{ | |
| 76 | + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 | |
| 77 | +}; | |
| 78 | + | |
| 79 | +/* for static huffman tables */ | |
| 80 | +static Huff litlentab; | |
| 81 | +static Huff offtab; | |
| 82 | +static uchar revtab[256]; | |
| 83 | + | |
| 84 | +static int uncblock(Input *in, History*); | |
| 85 | +static int fixedblock(Input *in, History*); | |
| 86 | +static int dynamicblock(Input *in, History*); | |
| 87 | +static int sregfill(Input *in, int n); | |
| 88 | +static int sregunget(Input *in); | |
| 89 | +static int decode(Input*, History*, Huff*, Huff*); | |
| 90 | +static int hufftab(Huff*, char*, int, int); | |
| 91 | +static int hdecsym(Input *in, Huff *h, int b); | |
| 92 | + | |
| 93 | +int | |
| 94 | +inflateinit(void) | |
| 95 | +{ | |
| 96 | + char *len; | |
| 97 | + int i, j, base; | |
| 98 | + | |
| 99 | + /* byte reverse table */ | |
| 100 | + for(i=0; i<256; i++) | |
| 101 | + for(j=0; j<8; j++) | |
| 102 | + if(i & (1<<j)) | |
| 103 | + revtab[i] |= 0x80 >> j; | |
| 104 | + | |
| 105 | + for(i=257,base=3; i<Nlitlen; i++) { | |
| 106 | + litlenbase[i-257] = base; | |
| 107 | + base += 1<<litlenextra[i-257]; | |
| 108 | + } | |
| 109 | + /* strange table entry in spec... */ | |
| 110 | + litlenbase[285-257]--; | |
| 111 | + | |
| 112 | + for(i=0,base=1; i<Noff; i++) { | |
| 113 | + offbase[i] = base; | |
| 114 | + base += 1<<offextra[i]; | |
| 115 | + } | |
| 116 | + | |
| 117 | + len = malloc(MaxLeaf); | |
| 118 | + if(len == nil) | |
| 119 | + return FlateNoMem; | |
| 120 | + | |
| 121 | + /* static Litlen bit lengths */ | |
| 122 | + for(i=0; i<144; i++) | |
| 123 | + len[i] = 8; | |
| 124 | + for(i=144; i<256; i++) | |
| 125 | + len[i] = 9; | |
| 126 | + for(i=256; i<280; i++) | |
| 127 | + len[i] = 7; | |
| 128 | + for(i=280; i<Nlitlen; i++) | |
| 129 | + len[i] = 8; | |
| 130 | + | |
| 131 | + if(!hufftab(&litlentab, len, Nlitlen, MaxFlatBits)) | |
| 132 | + return FlateInternal; | |
| 133 | + | |
| 134 | + /* static Offset bit lengths */ | |
| 135 | + for(i=0; i<Noff; i++) | |
| 136 | + len[i] = 5; | |
| 137 | + | |
| 138 | + if(!hufftab(&offtab, len, Noff, MaxFlatBits)) | |
| 139 | + return FlateInternal; | |
| 140 | + free(len); | |
| 141 | + | |
| 142 | + return FlateOk; | |
| 143 | +} | |
| 144 | + | |
| 145 | +int | |
| 146 | +inflate(void *wr, int (*w)(void*, void*, int), void *getr, int (*get)(void*)) | |
| 147 | +{ | |
| 148 | + History *his; | |
| 149 | + Input in; | |
| 150 | + int final, type; | |
| 151 | + | |
| 152 | + his = malloc(sizeof(History)); | |
| 153 | + if(his == nil) | |
| 154 | + return FlateNoMem; | |
| 155 | + his->cp = his->his; | |
| 156 | + his->full = 0; | |
| 157 | + in.getr = getr; | |
| 158 | + in.get = get; | |
| 159 | + in.wr = wr; | |
| 160 | + in.w = w; | |
| 161 | + in.nbits = 0; | |
| 162 | + in.sreg = 0; | |
| 163 | + in.error = FlateOk; | |
| 164 | + | |
| 165 | + do { | |
| 166 | + if(!sregfill(&in, 3)) | |
| 167 | + goto bad; | |
| 168 | + final = in.sreg & 0x1; | |
| 169 | + type = (in.sreg>>1) & 0x3; | |
| 170 | + in.sreg >>= 3; | |
| 171 | + in.nbits -= 3; | |
| 172 | + switch(type) { | |
| 173 | + default: | |
| 174 | + in.error = FlateCorrupted; | |
| 175 | + goto bad; | |
| 176 | + case 0: | |
| 177 | + /* uncompressed */ | |
| 178 | + if(!uncblock(&in, his)) | |
| 179 | + goto bad; | |
| 180 | + break; | |
| 181 | + case 1: | |
| 182 | + /* fixed huffman */ | |
| 183 | + if(!fixedblock(&in, his)) | |
| 184 | + goto bad; | |
| 185 | + break; | |
| 186 | + case 2: | |
| 187 | + /* dynamic huffman */ | |
| 188 | + if(!dynamicblock(&in, his)) | |
| 189 | + goto bad; | |
| 190 | + break; | |
| 191 | + } | |
| 192 | + } while(!final); | |
| 193 | + | |
| 194 | + if(his->cp != his->his && (*w)(wr, his->his, his->cp - his->his) != his->cp - his->his) { | |
| 195 | + in.error = FlateOutputFail; | |
| 196 | + goto bad; | |
| 197 | + } | |
| 198 | + | |
| 199 | + if(!sregunget(&in)) | |
| 200 | + goto bad; | |
| 201 | + | |
| 202 | + free(his); | |
| 203 | + if(in.error != FlateOk) | |
| 204 | + return FlateInternal; | |
| 205 | + return FlateOk; | |
| 206 | + | |
| 207 | +bad: | |
| 208 | + free(his); | |
| 209 | + if(in.error == FlateOk) | |
| 210 | + return FlateInternal; | |
| 211 | + return in.error; | |
| 212 | +} | |
| 213 | + | |
| 214 | +static int | |
| 215 | +uncblock(Input *in, History *his) | |
| 216 | +{ | |
| 217 | + int len, nlen, c; | |
| 218 | + uchar *hs, *hp, *he; | |
| 219 | + | |
| 220 | + if(!sregunget(in)) | |
| 221 | + return 0; | |
| 222 | + len = (*in->get)(in->getr); | |
| 223 | + len |= (*in->get)(in->getr)<<8; | |
| 224 | + nlen = (*in->get)(in->getr); | |
| 225 | + nlen |= (*in->get)(in->getr)<<8; | |
| 226 | + if(len != (~nlen&0xffff)) { | |
| 227 | + in->error = FlateCorrupted; | |
| 228 | + return 0; | |
| 229 | + } | |
| 230 | + | |
| 231 | + hp = his->cp; | |
| 232 | + hs = his->his; | |
| 233 | + he = hs + HistorySize; | |
| 234 | + | |
| 235 | + while(len > 0) { | |
| 236 | + c = (*in->get)(in->getr); | |
| 237 | + if(c < 0) | |
| 238 | + return 0; | |
| 239 | + *hp++ = c; | |
| 240 | + if(hp == he) { | |
| 241 | + his->full = 1; | |
| 242 | + if((*in->w)(in->wr, hs, HistorySize) != HistorySize) { | |
| 243 | + in->error = FlateOutputFail; | |
| 244 | + return 0; | |
| 245 | + } | |
| 246 | + hp = hs; | |
| 247 | + } | |
| 248 | + len--; | |
| 249 | + } | |
| 250 | + | |
| 251 | + his->cp = hp; | |
| 252 | + | |
| 253 | + return 1; | |
| 254 | +} | |
| 255 | + | |
| 256 | +static int | |
| 257 | +fixedblock(Input *in, History *his) | |
| 258 | +{ | |
| 259 | + return decode(in, his, &litlentab, &offtab); | |
| 260 | +} | |
| 261 | + | |
| 262 | +static int | |
| 263 | +dynamicblock(Input *in, History *his) | |
| 264 | +{ | |
| 265 | + Huff *lentab, *offtab; | |
| 266 | + char *len; | |
| 267 | + int i, j, n, c, nlit, ndist, nclen, res, nb; | |
| 268 | + | |
| 269 | + if(!sregfill(in, 14)) | |
| 270 | + return 0; | |
| 271 | + nlit = (in->sreg&0x1f) + 257; | |
| 272 | + ndist = ((in->sreg>>5) & 0x1f) + 1; | |
| 273 | + nclen = ((in->sreg>>10) & 0xf) + 4; | |
| 274 | + in->sreg >>= 14; | |
| 275 | + in->nbits -= 14; | |
| 276 | + | |
| 277 | + if(nlit > Nlitlen || ndist > Noff || nlit < 257) { | |
| 278 | + in->error = FlateCorrupted; | |
| 279 | + return 0; | |
| 280 | + } | |
| 281 | + | |
| 282 | + /* huff table header */ | |
| 283 | + len = malloc(Nlitlen+Noff); | |
| 284 | + lentab = malloc(sizeof(Huff)); | |
| 285 | + offtab = malloc(sizeof(Huff)); | |
| 286 | + if(len == nil || lentab == nil || offtab == nil){ | |
| 287 | + in->error = FlateNoMem; | |
| 288 | + goto bad; | |
| 289 | + } | |
| 290 | + for(i=0; i < Nclen; i++) | |
| 291 | + len[i] = 0; | |
| 292 | + for(i=0; i<nclen; i++) { | |
| 293 | + if(!sregfill(in, 3)) | |
| 294 | + goto bad; | |
| 295 | + len[clenorder[i]] = in->sreg & 0x7; | |
| 296 | + in->sreg >>= 3; | |
| 297 | + in->nbits -= 3; | |
| 298 | + } | |
| 299 | + | |
| 300 | + if(!hufftab(lentab, len, Nclen, ClenBits)){ | |
| 301 | + in->error = FlateCorrupted; | |
| 302 | + goto bad; | |
| 303 | + } | |
| 304 | + | |
| 305 | + n = nlit+ndist; | |
| 306 | + for(i=0; i<n;) { | |
| 307 | + nb = lentab->minbits; | |
| 308 | + for(;;){ | |
| 309 | + if(in->nbits<nb && !sregfill(in, nb)) | |
| 310 | + goto bad; | |
| 311 | + c = lentab->flat[in->sreg & lentab->flatmask]; | |
| 312 | + nb = c & 0xff; | |
| 313 | + if(nb > in->nbits){ | |
| 314 | + if(nb != 0xff) | |
| 315 | + continue; | |
| 316 | + c = hdecsym(in, lentab, c); | |
| 317 | + if(c < 0) | |
| 318 | + goto bad; | |
| 319 | + }else{ | |
| 320 | + c >>= 8; | |
| 321 | + in->sreg >>= nb; | |
| 322 | + in->nbits -= nb; | |
| 323 | + } | |
| 324 | + break; | |
| 325 | + } | |
| 326 | + | |
| 327 | + if(c < 16) { | |
| 328 | + j = 1; | |
| 329 | + } else if(c == 16) { | |
| 330 | + if(in->nbits<2 && !sregfill(in, 2)) | |
| 331 | + goto bad; | |
| 332 | + j = (in->sreg&0x3)+3; | |
| 333 | + in->sreg >>= 2; | |
| 334 | + in->nbits -= 2; | |
| 335 | + if(i == 0) { | |
| 336 | + in->error = FlateCorrupted; | |
| 337 | + goto bad; | |
| 338 | + } | |
| 339 | + c = len[i-1]; | |
| 340 | + } else if(c == 17) { | |
| 341 | + if(in->nbits<3 && !sregfill(in, 3)) | |
| 342 | + goto bad; | |
| 343 | + j = (in->sreg&0x7)+3; | |
| 344 | + in->sreg >>= 3; | |
| 345 | + in->nbits -= 3; | |
| 346 | + c = 0; | |
| 347 | + } else if(c == 18) { | |
| 348 | + if(in->nbits<7 && !sregfill(in, 7)) | |
| 349 | + goto bad; | |
| 350 | + j = (in->sreg&0x7f)+11; | |
| 351 | + in->sreg >>= 7; | |
| 352 | + in->nbits -= 7; | |
| 353 | + c = 0; | |
| 354 | + } else { | |
| 355 | + in->error = FlateCorrupted; | |
| 356 | + goto bad; | |
| 357 | + } | |
| 358 | + | |
| 359 | + if(i+j > n) { | |
| 360 | + in->error = FlateCorrupted; | |
| 361 | + goto bad; | |
| 362 | + } | |
| 363 | + | |
| 364 | + while(j) { | |
| 365 | + len[i] = c; | |
| 366 | + i++; | |
| 367 | + j--; | |
| 368 | + } | |
| 369 | + } | |
| 370 | + | |
| 371 | + if(!hufftab(lentab, len, nlit, LitlenBits) | |
| 372 | + || !hufftab(offtab, &len[nlit], ndist, OffBits)){ | |
| 373 | + in->error = FlateCorrupted; | |
| 374 | + goto bad; | |
| 375 | + } | |
| 376 | + | |
| 377 | + res = decode(in, his, lentab, offtab); | |
| 378 | + | |
| 379 | + free(len); | |
| 380 | + free(lentab); | |
| 381 | + free(offtab); | |
| 382 | + | |
| 383 | + return res; | |
| 384 | + | |
| 385 | +bad: | |
| 386 | + free(len); | |
| 387 | + free(lentab); | |
| 388 | + free(offtab); | |
| 389 | + return 0; | |
| 390 | +} | |
| 391 | + | |
| 392 | +static int | |
| 393 | +decode(Input *in, History *his, Huff *litlentab, Huff *offtab) | |
| 394 | +{ | |
| 395 | + int len, off; | |
| 396 | + uchar *hs, *hp, *hq, *he; | |
| 397 | + int c; | |
| 398 | + int nb; | |
| 399 | + | |
| 400 | + hs = his->his; | |
| 401 | + he = hs + HistorySize; | |
| 402 | + hp = his->cp; | |
| 403 | + | |
| 404 | + for(;;) { | |
| 405 | + nb = litlentab->minbits; | |
| 406 | + for(;;){ | |
| 407 | + if(in->nbits<nb && !sregfill(in, nb)) | |
| 408 | + return 0; | |
| 409 | + c = litlentab->flat[in->sreg & litlentab->flatmask]; | |
| 410 | + nb = c & 0xff; | |
| 411 | + if(nb > in->nbits){ | |
| 412 | + if(nb != 0xff) | |
| 413 | + continue; | |
| 414 | + c = hdecsym(in, litlentab, c); | |
| 415 | + if(c < 0) | |
| 416 | + return 0; | |
| 417 | + }else{ | |
| 418 | + c >>= 8; | |
| 419 | + in->sreg >>= nb; | |
| 420 | + in->nbits -= nb; | |
| 421 | + } | |
| 422 | + break; | |
| 423 | + } | |
| 424 | + | |
| 425 | + if(c < 256) { | |
| 426 | + /* literal */ | |
| 427 | + *hp++ = c; | |
| 428 | + if(hp == he) { | |
| 429 | + his->full = 1; | |
| 430 | + if((*in->w)(in->wr, hs, HistorySize) != HistorySize) { | |
| 431 | + in->error = FlateOutputFail; | |
| 432 | + return 0; | |
| 433 | + } | |
| 434 | + hp = hs; | |
| 435 | + } | |
| 436 | + continue; | |
| 437 | + } | |
| 438 | + | |
| 439 | + if(c == 256) | |
| 440 | + break; | |
| 441 | + | |
| 442 | + if(c > 285) { | |
| 443 | + in->error = FlateCorrupted; | |
| 444 | + return 0; | |
| 445 | + } | |
| 446 | + | |
| 447 | + c -= 257; | |
| 448 | + nb = litlenextra[c]; | |
| 449 | + if(in->nbits < nb && !sregfill(in, nb)) | |
| 450 | + return 0; | |
| 451 | + len = litlenbase[c] + (in->sreg & ((1<<nb)-1)); | |
| 452 | + in->sreg >>= nb; | |
| 453 | + in->nbits -= nb; | |
| 454 | + | |
| 455 | + /* get offset */ | |
| 456 | + nb = offtab->minbits; | |
| 457 | + for(;;){ | |
| 458 | + if(in->nbits<nb && !sregfill(in, nb)) | |
| 459 | + return 0; | |
| 460 | + c = offtab->flat[in->sreg & offtab->flatmask]; | |
| 461 | + nb = c & 0xff; | |
| 462 | + if(nb > in->nbits){ | |
| 463 | + if(nb != 0xff) | |
| 464 | + continue; | |
| 465 | + c = hdecsym(in, offtab, c); | |
| 466 | + if(c < 0) | |
| 467 | + return 0; | |
| 468 | + }else{ | |
| 469 | + c >>= 8; | |
| 470 | + in->sreg >>= nb; | |
| 471 | + in->nbits -= nb; | |
| 472 | + } | |
| 473 | + break; | |
| 474 | + } | |
| 475 | + | |
| 476 | + if(c > 29) { | |
| 477 | + in->error = FlateCorrupted; | |
| 478 | + return 0; | |
| 479 | + } | |
| 480 | + | |
| 481 | + nb = offextra[c]; | |
| 482 | + if(in->nbits < nb && !sregfill(in, nb)) | |
| 483 | + return 0; | |
| 484 | + | |
| 485 | + off = offbase[c] + (in->sreg & ((1<<nb)-1)); | |
| 486 | + in->sreg >>= nb; | |
| 487 | + in->nbits -= nb; | |
| 488 | + | |
| 489 | + hq = hp - off; | |
| 490 | + if(hq < hs) { | |
| 491 | + if(!his->full) { | |
| 492 | + in->error = FlateCorrupted; | |
| 493 | + return 0; | |
| 494 | + } | |
| 495 | + hq += HistorySize; | |
| 496 | + } | |
| 497 | + | |
| 498 | + /* slow but correct */ | |
| 499 | + while(len) { | |
| 500 | + *hp = *hq; | |
| 501 | + hq++; | |
| 502 | + hp++; | |
| 503 | + if(hq >= he) | |
| 504 | + hq = hs; | |
| 505 | + if(hp == he) { | |
| 506 | + his->full = 1; | |
| 507 | + if((*in->w)(in->wr, hs, HistorySize) != HistorySize) { | |
| 508 | + in->error = FlateOutputFail; | |
| 509 | + return 0; | |
| 510 | + } | |
| 511 | + hp = hs; | |
| 512 | + } | |
| 513 | + len--; | |
| 514 | + } | |
| 515 | + | |
| 516 | + } | |
| 517 | + | |
| 518 | + his->cp = hp; | |
| 519 | + | |
| 520 | + return 1; | |
| 521 | +} | |
| 522 | + | |
| 523 | +static int | |
| 524 | +revcode(int c, int b) | |
| 525 | +{ | |
| 526 | + /* shift encode up so it starts on bit 15 then reverse */ | |
| 527 | + c <<= (16-b); | |
| 528 | + c = revtab[c>>8] | (revtab[c&0xff]<<8); | |
| 529 | + return c; | |
| 530 | +} | |
| 531 | + | |
| 532 | +/* | |
| 533 | + * construct the huffman decoding arrays and a fast lookup table. | |
| 534 | + * the fast lookup is a table indexed by the next flatbits bits, | |
| 535 | + * which returns the symbol matched and the number of bits consumed, | |
| 536 | + * or the minimum number of bits needed and 0xff if more than flatbits | |
| 537 | + * bits are needed. | |
| 538 | + * | |
| 539 | + * flatbits can be longer than the smallest huffman code, | |
| 540 | + * because shorter codes are assigned smaller lexical prefixes. | |
| 541 | + * this means assuming zeros for the next few bits will give a | |
| 542 | + * conservative answer, in the sense that it will either give the | |
| 543 | + * correct answer, or return the minimum number of bits which | |
| 544 | + * are needed for an answer. | |
| 545 | + */ | |
| 546 | +static int | |
| 547 | +hufftab(Huff *h, char *hb, int maxleaf, int flatbits) | |
| 548 | +{ | |
| 549 | + ulong bitcount[MaxHuffBits]; | |
| 550 | + ulong c, fc, ec, mincode, code, nc[MaxHuffBits]; | |
| 551 | + int i, b, minbits, maxbits; | |
| 552 | + | |
| 553 | + for(i = 0; i < MaxHuffBits; i++) | |
| 554 | + bitcount[i] = 0; | |
| 555 | + maxbits = -1; | |
| 556 | + minbits = MaxHuffBits + 1; | |
| 557 | + for(i=0; i < maxleaf; i++){ | |
| 558 | + b = hb[i]; | |
| 559 | + if(b){ | |
| 560 | + bitcount[b]++; | |
| 561 | + if(b < minbits) | |
| 562 | + minbits = b; | |
| 563 | + if(b > maxbits) | |
| 564 | + maxbits = b; | |
| 565 | + } | |
| 566 | + } | |
| 567 | + | |
| 568 | + h->maxbits = maxbits; | |
| 569 | + if(maxbits <= 0){ | |
| 570 | + h->maxbits = 0; | |
| 571 | + h->minbits = 0; | |
| 572 | + h->flatmask = 0; | |
| 573 | + return 1; | |
| 574 | + } | |
| 575 | + code = 0; | |
| 576 | + c = 0; | |
| 577 | + for(b = 0; b <= maxbits; b++){ | |
| 578 | + h->last[b] = c; | |
| 579 | + c += bitcount[b]; | |
| 580 | + mincode = code << 1; | |
| 581 | + nc[b] = mincode; | |
| 582 | + code = mincode + bitcount[b]; | |
| 583 | + if(code > (1 << b)) | |
| 584 | + return 0; | |
| 585 | + h->maxcode[b] = code - 1; | |
| 586 | + h->last[b] += code - 1; | |
| 587 | + } | |
| 588 | + | |
| 589 | + if(flatbits > maxbits) | |
| 590 | + flatbits = maxbits; | |
| 591 | + h->flatmask = (1 << flatbits) - 1; | |
| 592 | + if(minbits > flatbits) | |
| 593 | + minbits = flatbits; | |
| 594 | + h->minbits = minbits; | |
| 595 | + | |
| 596 | + b = 1 << flatbits; | |
| 597 | + for(i = 0; i < b; i++) | |
| 598 | + h->flat[i] = ~0; | |
| 599 | + | |
| 600 | + /* | |
| 601 | + * initialize the flat table to include the minimum possible | |
| 602 | + * bit length for each code prefix | |
| 603 | + */ | |
| 604 | + for(b = maxbits; b > flatbits; b--){ | |
| 605 | + code = h->maxcode[b]; | |
| 606 | + if(code == -1) | |
| 607 | + break; | |
| 608 | + mincode = code + 1 - bitcount[b]; | |
| 609 | + mincode >>= b - flatbits; | |
| 610 | + code >>= b - flatbits; | |
| 611 | + for(; mincode <= code; mincode++) | |
| 612 | + h->flat[revcode(mincode, flatbits)] = (b << 8) | 0xff; | |
| 613 | + } | |
| 614 | + | |
| 615 | + for(i = 0; i < maxleaf; i++){ | |
| 616 | + b = hb[i]; | |
| 617 | + if(b <= 0) | |
| 618 | + continue; | |
| 619 | + c = nc[b]++; | |
| 620 | + if(b <= flatbits){ | |
| 621 | + code = (i << 8) | b; | |
| 622 | + ec = (c + 1) << (flatbits - b); | |
| 623 | + if(ec > (1<<flatbits)) | |
| 624 | + return 0; /* this is actually an internal error */ | |
| 625 | + for(fc = c << (flatbits - b); fc < ec; fc++) | |
| 626 | + h->flat[revcode(fc, flatbits)] = code; | |
| 627 | + } | |
| 628 | + if(b > minbits){ | |
| 629 | + c = h->last[b] - c; | |
| 630 | + if(c >= maxleaf) | |
| 631 | + return 0; | |
| 632 | + h->decode[c] = i; | |
| 633 | + } | |
| 634 | + } | |
| 635 | + return 1; | |
| 636 | +} | |
| 637 | + | |
| 638 | +static int | |
| 639 | +hdecsym(Input *in, Huff *h, int nb) | |
| 640 | +{ | |
| 641 | + long c; | |
| 642 | + | |
| 643 | + if((nb & 0xff) == 0xff) | |
| 644 | + nb = nb >> 8; | |
| 645 | + else | |
| 646 | + nb = nb & 0xff; | |
| 647 | + for(; nb <= h->maxbits; nb++){ | |
| 648 | + if(in->nbits<nb && !sregfill(in, nb)) | |
| 649 | + return -1; | |
| 650 | + c = revtab[in->sreg&0xff]<<8; | |
| 651 | + c |= revtab[(in->sreg>>8)&0xff]; | |
| 652 | + c >>= (16-nb); | |
| 653 | + if(c <= h->maxcode[nb]){ | |
| 654 | + in->sreg >>= nb; | |
| 655 | + in->nbits -= nb; | |
| 656 | + return h->decode[h->last[nb] - c]; | |
| 657 | + } | |
| 658 | + } | |
| 659 | + in->error = FlateCorrupted; | |
| 660 | + return -1; | |
| 661 | +} | |
| 662 | + | |
| 663 | +static int | |
| 664 | +sregfill(Input *in, int n) | |
| 665 | +{ | |
| 666 | + int c; | |
| 667 | + | |
| 668 | + while(n > in->nbits) { | |
| 669 | + c = (*in->get)(in->getr); | |
| 670 | + if(c < 0){ | |
| 671 | + in->error = FlateInputFail; | |
| 672 | + return 0; | |
| 673 | + } | |
| 674 | + in->sreg |= c<<in->nbits; | |
| 675 | + in->nbits += 8; | |
| 676 | + } | |
| 677 | + return 1; | |
| 678 | +} | |
| 679 | + | |
| 680 | +static int | |
| 681 | +sregunget(Input *in) | |
| 682 | +{ | |
| 683 | + if(in->nbits >= 8) { | |
| 684 | + in->error = FlateInternal; | |
| 685 | + return 0; | |
| 686 | + } | |
| 687 | + | |
| 688 | + /* throw other bits on the floor */ | |
| 689 | + in->nbits = 0; | |
| 690 | + in->sreg = 0; | |
| 691 | + return 1; | |
| 692 | +} | |
| @@ -0,0 +1,53 @@ | ||
| 1 | +#include "lib9.h" | |
| 2 | +#include <flate.h> | |
| 3 | + | |
| 4 | +typedef struct Block Block; | |
| 5 | + | |
| 6 | +struct Block | |
| 7 | +{ | |
| 8 | + uchar *pos; | |
| 9 | + uchar *limit; | |
| 10 | +}; | |
| 11 | + | |
| 12 | +static int | |
| 13 | +blgetc(void *vb) | |
| 14 | +{ | |
| 15 | + Block *b; | |
| 16 | + | |
| 17 | + b = vb; | |
| 18 | + if(b->pos >= b->limit) | |
| 19 | + return -1; | |
| 20 | + return *b->pos++; | |
| 21 | +} | |
| 22 | + | |
| 23 | +static int | |
| 24 | +blwrite(void *vb, void *buf, int n) | |
| 25 | +{ | |
| 26 | + Block *b; | |
| 27 | + | |
| 28 | + b = vb; | |
| 29 | + | |
| 30 | + if(n > b->limit - b->pos) | |
| 31 | + n = b->limit - b->pos; | |
| 32 | + memmove(b->pos, buf, n); | |
| 33 | + b->pos += n; | |
| 34 | + return n; | |
| 35 | +} | |
| 36 | + | |
| 37 | +int | |
| 38 | +inflateblock(uchar *dst, int dsize, uchar *src, int ssize) | |
| 39 | +{ | |
| 40 | + Block bd, bs; | |
| 41 | + int ok; | |
| 42 | + | |
| 43 | + bs.pos = src; | |
| 44 | + bs.limit = src + ssize; | |
| 45 | + | |
| 46 | + bd.pos = dst; | |
| 47 | + bd.limit = dst + dsize; | |
| 48 | + | |
| 49 | + ok = inflate(&bd, blwrite, &bs, blgetc); | |
| 50 | + if(ok != FlateOk) | |
| 51 | + return ok; | |
| 52 | + return bd.pos - dst; | |
| 53 | +} | |
| @@ -0,0 +1,65 @@ | ||
| 1 | +#include "lib9.h" | |
| 2 | +#include <flate.h> | |
| 3 | +#include "zlib.h" | |
| 4 | + | |
| 5 | +typedef struct ZWrite ZWrite; | |
| 6 | + | |
| 7 | +struct ZWrite | |
| 8 | +{ | |
| 9 | + ulong adler; | |
| 10 | + void *wr; | |
| 11 | + int (*w)(void*, void*, int); | |
| 12 | +}; | |
| 13 | + | |
| 14 | +static int | |
| 15 | +zlwrite(void *vzw, void *buf, int n) | |
| 16 | +{ | |
| 17 | + ZWrite *zw; | |
| 18 | + | |
| 19 | + zw = vzw; | |
| 20 | + zw->adler = adler32(zw->adler, buf, n); | |
| 21 | + n = (*zw->w)(zw->wr, buf, n); | |
| 22 | + if(n <= 0) | |
| 23 | + return n; | |
| 24 | + return n; | |
| 25 | +} | |
| 26 | + | |
| 27 | +int | |
| 28 | +inflatezlib(void *wr, int (*w)(void*, void*, int), void *getr, int (*get)(void*)) | |
| 29 | +{ | |
| 30 | + ZWrite zw; | |
| 31 | + ulong v; | |
| 32 | + int c, i; | |
| 33 | + | |
| 34 | + c = (*get)(getr); | |
| 35 | + if(c < 0) | |
| 36 | + return FlateInputFail; | |
| 37 | + i = (*get)(getr); | |
| 38 | + if(i < 0) | |
| 39 | + return FlateInputFail; | |
| 40 | + | |
| 41 | + if(((c << 8) | i) % 31) | |
| 42 | + return FlateCorrupted; | |
| 43 | + if((c & ZlibMeth) != ZlibDeflate | |
| 44 | + || (c & ZlibCInfo) > ZlibWin32k) | |
| 45 | + return FlateCorrupted; | |
| 46 | + | |
| 47 | + zw.wr = wr; | |
| 48 | + zw.w = w; | |
| 49 | + zw.adler = 1; | |
| 50 | + i = inflate(&zw, zlwrite, getr, get); | |
| 51 | + if(i != FlateOk) | |
| 52 | + return i; | |
| 53 | + | |
| 54 | + v = 0; | |
| 55 | + for(i = 0; i < 4; i++){ | |
| 56 | + c = (*get)(getr); | |
| 57 | + if(c < 0) | |
| 58 | + return FlateInputFail; | |
| 59 | + v = (v << 8) | c; | |
| 60 | + } | |
| 61 | + if(zw.adler != v) | |
| 62 | + return FlateCorrupted; | |
| 63 | + | |
| 64 | + return FlateOk; | |
| 65 | +} | |
| @@ -0,0 +1,67 @@ | ||
| 1 | +#include "lib9.h" | |
| 2 | +#include <flate.h> | |
| 3 | +#include "zlib.h" | |
| 4 | + | |
| 5 | +typedef struct Block Block; | |
| 6 | + | |
| 7 | +struct Block | |
| 8 | +{ | |
| 9 | + uchar *pos; | |
| 10 | + uchar *limit; | |
| 11 | +}; | |
| 12 | + | |
| 13 | +static int | |
| 14 | +blgetc(void *vb) | |
| 15 | +{ | |
| 16 | + Block *b; | |
| 17 | + | |
| 18 | + b = vb; | |
| 19 | + if(b->pos >= b->limit) | |
| 20 | + return -1; | |
| 21 | + return *b->pos++; | |
| 22 | +} | |
| 23 | + | |
| 24 | +static int | |
| 25 | +blwrite(void *vb, void *buf, int n) | |
| 26 | +{ | |
| 27 | + Block *b; | |
| 28 | + | |
| 29 | + b = vb; | |
| 30 | + | |
| 31 | + if(n > b->limit - b->pos) | |
| 32 | + n = b->limit - b->pos; | |
| 33 | + memmove(b->pos, buf, n); | |
| 34 | + b->pos += n; | |
| 35 | + return n; | |
| 36 | +} | |
| 37 | + | |
| 38 | +int | |
| 39 | +inflatezlibblock(uchar *dst, int dsize, uchar *src, int ssize) | |
| 40 | +{ | |
| 41 | + Block bd, bs; | |
| 42 | + int ok; | |
| 43 | + | |
| 44 | + if(ssize < 6) | |
| 45 | + return FlateInputFail; | |
| 46 | + | |
| 47 | + if(((src[0] << 8) | src[1]) % 31) | |
| 48 | + return FlateCorrupted; | |
| 49 | + if((src[0] & ZlibMeth) != ZlibDeflate | |
| 50 | + || (src[0] & ZlibCInfo) > ZlibWin32k) | |
| 51 | + return FlateCorrupted; | |
| 52 | + | |
| 53 | + bs.pos = src + 2; | |
| 54 | + bs.limit = src + ssize - 6; | |
| 55 | + | |
| 56 | + bd.pos = dst; | |
| 57 | + bd.limit = dst + dsize; | |
| 58 | + | |
| 59 | + ok = inflate(&bd, blwrite, &bs, blgetc); | |
| 60 | + if(ok != FlateOk) | |
| 61 | + return ok; | |
| 62 | + | |
| 63 | + if(adler32(1, dst, bs.pos - dst) != ((bs.pos[0] << 24) | (bs.pos[1] << 16) | (bs.pos[2] << 8) | bs.pos[3])) | |
| 64 | + return FlateCorrupted; | |
| 65 | + | |
| 66 | + return bd.pos - dst; | |
| 67 | +} | |
| @@ -0,0 +1,21 @@ | ||
| 1 | +<../../../mkconfig | |
| 2 | + | |
| 3 | +LIB=libflate.a | |
| 4 | +OFILES=\ | |
| 5 | + deflate.$O\ | |
| 6 | + deflatezlib.$O\ | |
| 7 | + deflateblock.$O\ | |
| 8 | + deflatezlibblock.$O\ | |
| 9 | + inflate.$O\ | |
| 10 | + inflatezlib.$O\ | |
| 11 | + inflateblock.$O\ | |
| 12 | + inflatezlibblock.$O\ | |
| 13 | + flateerr.$O\ | |
| 14 | + crc.$O\ | |
| 15 | + adler.$O\ | |
| 16 | + | |
| 17 | +HFILES=\ | |
| 18 | + $ROOT/include/flate.h\ | |
| 19 | + zlib.h\ | |
| 20 | + | |
| 21 | +<$ROOT/mkfiles/mksyslib-$SHELLTYPE | |
| @@ -0,0 +1,11 @@ | ||
| 1 | +/* | |
| 2 | + * zlib header fields | |
| 3 | + */ | |
| 4 | +enum | |
| 5 | +{ | |
| 6 | + ZlibMeth = 0x0f, /* mask of compression methods */ | |
| 7 | + ZlibDeflate = 0x08, | |
| 8 | + | |
| 9 | + ZlibCInfo = 0xf0, /* mask of compression aux. info */ | |
| 10 | + ZlibWin32k = 0x70, /* 32k history window */ | |
| 11 | +}; | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +Inferno® Copyright © 1996-1999 Lucent Technologies Inc. All rights reserved. | |
| 2 | +PowerPC support Copyright © 1995-1997 C H Forsyth (forsyth@caldo.demon.co.uk). All rights reserved. | |
| 3 | +MPC8xx Inferno PowerPC port Copyright © 1998-2003 Vita Nuova Holdings Limited. All rights reserved. | |
| @@ -0,0 +1,123 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | +#define MAXALARM 10 | |
| 8 | + | |
| 9 | +Alarm alarmtab[MAXALARM]; | |
| 10 | + | |
| 11 | +/* | |
| 12 | + * Insert new into list after where | |
| 13 | + */ | |
| 14 | +void | |
| 15 | +insert(List **head, List *where, List *new) | |
| 16 | +{ | |
| 17 | + if(where == 0){ | |
| 18 | + new->next = *head; | |
| 19 | + *head = new; | |
| 20 | + }else{ | |
| 21 | + new->next = where->next; | |
| 22 | + where->next = new; | |
| 23 | + } | |
| 24 | + | |
| 25 | +} | |
| 26 | + | |
| 27 | +/* | |
| 28 | + * Delete old from list. where->next is known to be old. | |
| 29 | + */ | |
| 30 | +void | |
| 31 | +delete(List **head, List *where, List *old) | |
| 32 | +{ | |
| 33 | + if(where == 0){ | |
| 34 | + *head = old->next; | |
| 35 | + return; | |
| 36 | + } | |
| 37 | + where->next = old->next; | |
| 38 | +} | |
| 39 | + | |
| 40 | +Alarm* | |
| 41 | +newalarm(void) | |
| 42 | +{ | |
| 43 | + int i; | |
| 44 | + Alarm *a; | |
| 45 | + | |
| 46 | + for(i=0,a=alarmtab; i < nelem(alarmtab); i++,a++) | |
| 47 | + if(a->busy==0 && a->f==0){ | |
| 48 | + a->f = 0; | |
| 49 | + a->arg = 0; | |
| 50 | + a->busy = 1; | |
| 51 | + return a; | |
| 52 | + } | |
| 53 | + panic("newalarm"); | |
| 54 | + return 0; /* not reached */ | |
| 55 | +} | |
| 56 | + | |
| 57 | +Alarm* | |
| 58 | +alarm(int ms, void (*f)(Alarm*), void *arg) | |
| 59 | +{ | |
| 60 | + Alarm *a, *w, *pw; | |
| 61 | + ulong s; | |
| 62 | + | |
| 63 | + if(ms < 0) | |
| 64 | + ms = 0; | |
| 65 | + s = splhi(); | |
| 66 | + a = newalarm(); | |
| 67 | + a->dt = MS2TK(ms); | |
| 68 | + a->f = f; | |
| 69 | + a->arg = arg; | |
| 70 | + pw = 0; | |
| 71 | + for(w=m->alarm; w; pw=w, w=w->next){ | |
| 72 | + if(w->dt <= a->dt){ | |
| 73 | + a->dt -= w->dt; | |
| 74 | + continue; | |
| 75 | + } | |
| 76 | + w->dt -= a->dt; | |
| 77 | + break; | |
| 78 | + } | |
| 79 | + insert(&m->alarm, pw, a); | |
| 80 | + splx(s); | |
| 81 | + return a; | |
| 82 | +} | |
| 83 | + | |
| 84 | +void | |
| 85 | +cancel(Alarm *a) | |
| 86 | +{ | |
| 87 | + a->f = 0; | |
| 88 | +} | |
| 89 | + | |
| 90 | +void | |
| 91 | +alarminit(void) | |
| 92 | +{ | |
| 93 | +} | |
| 94 | + | |
| 95 | +#define NA 10 /* alarms per clock tick */ | |
| 96 | +void | |
| 97 | +checkalarms(void) | |
| 98 | +{ | |
| 99 | + int i, n, s; | |
| 100 | + Alarm *a; | |
| 101 | + void (*f)(Alarm*); | |
| 102 | + Alarm *alist[NA]; | |
| 103 | + | |
| 104 | + s = splhi(); | |
| 105 | + a = m->alarm; | |
| 106 | + if(a){ | |
| 107 | + for(n=0; a && a->dt<=0 && n<NA; n++){ | |
| 108 | + alist[n] = a; | |
| 109 | + delete(&m->alarm, 0, a); | |
| 110 | + a = m->alarm; | |
| 111 | + } | |
| 112 | + if(a) | |
| 113 | + a->dt--; | |
| 114 | + | |
| 115 | + for(i = 0; i < n; i++){ | |
| 116 | + f = alist[i]->f; /* avoid race with cancel */ | |
| 117 | + if(f) | |
| 118 | + (*f)(alist[i]); | |
| 119 | + alist[i]->busy = 0; | |
| 120 | + } | |
| 121 | + } | |
| 122 | + splx(s); | |
| 123 | +} | |
| @@ -0,0 +1,6 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "mem.h" | |
| 6 | +#include "io.h" | |
| @@ -0,0 +1,355 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | +#include "archfads.h" | |
| 8 | + | |
| 9 | +/* | |
| 10 | + * board-specific support for the 8xxFADS (including 860/21 development system) | |
| 11 | + */ | |
| 12 | + | |
| 13 | +enum { | |
| 14 | + USESDRAM = 0, /* set to 1 if kernel is to use SDRAM as well as DRAM */ | |
| 15 | + | |
| 16 | + /* sccr */ | |
| 17 | + RTSEL = IBIT(8), /* =0, select main oscillator (OSCM); =1, select external crystal (EXTCLK) */ | |
| 18 | + RTDIV = IBIT(7), /* =0, divide by 4; =1, divide by 512 */ | |
| 19 | + CRQEN = IBIT(9), /* =1, switch to high frequency when CPM active */ | |
| 20 | + PRQEN = IBIT(10), /* =1, switch to high frequency when interrupt pending */ | |
| 21 | + | |
| 22 | + /* plprcr */ | |
| 23 | + CSRC = IBIT(21), /* =0, clock is DFNH; =1, clock is DFNL */ | |
| 24 | +}; | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * called early in main.c, after machinit: | |
| 28 | + * using board and architecture specific registers, initialise | |
| 29 | + * 8xx registers that need it and complete initialisation of the Mach structure. | |
| 30 | + */ | |
| 31 | +void | |
| 32 | +archinit(void) | |
| 33 | +{ | |
| 34 | + IMM *io; | |
| 35 | + int mf, isfads, sysmhz, t; | |
| 36 | + ulong v; | |
| 37 | + | |
| 38 | + v = getimmr() & 0xFFFF; | |
| 39 | + isfads = 0; /* assume it's the 860/821 board */ | |
| 40 | + sysmhz = 40; | |
| 41 | + switch(v>>8){ | |
| 42 | + case 0x00: t = 0x86000; break; | |
| 43 | + case 0x20: t = 0x82300; isfads = 1; break; | |
| 44 | + case 0x21: t = 0x823a0; isfads = 1; break; | |
| 45 | + default: t = 0; break; | |
| 46 | + } | |
| 47 | + m->cputype = t; | |
| 48 | + m->bcsr = KADDR(BCSRMEM); | |
| 49 | + m->bcsr[1] |= DisableRS232a | DisableIR | DisableEther | DisablePCMCIA | DisableRS232b; | |
| 50 | + m->bcsr[1] &= ~(DisableDRAM|DisableFlash); | |
| 51 | + if(isfads){ | |
| 52 | + sysmhz = 50; | |
| 53 | + m->bcsr[1] &= ~EnableSDRAM; | |
| 54 | + m->bcsr[4] &= ~(EnableVideoClock|EnableVideoPort); | |
| 55 | + m->bcsr[4] |= DisableVideoLamp; | |
| 56 | + } | |
| 57 | + io = m->iomem; | |
| 58 | + if(1 || io->sccr & IBIT(7)){ /* RTDIV=1 */ | |
| 59 | + /* oscillator frequency can't be determined independently: check a switch */ | |
| 60 | + if((m->bcsr[2]>>19)&(1<<2)) | |
| 61 | + m->clockgen = 5*MHz; | |
| 62 | + else | |
| 63 | + m->clockgen = 4*MHz; | |
| 64 | + } else | |
| 65 | + m->clockgen = 32768; | |
| 66 | + mf = (sysmhz*MHz)/m->clockgen; | |
| 67 | + m->cpuhz = m->clockgen*mf; | |
| 68 | + io->plprcrk = KEEP_ALIVE_KEY; | |
| 69 | + io->plprcr &= ~IBIT(21); /* general system clock is DFNH */ | |
| 70 | + io->plprcr = (io->plprcr & ((1<<20)-1)) | ((mf-1)<<20); | |
| 71 | + io->mptpr = 0x0400; /* memory prescaler = 16 for refresh */ | |
| 72 | + io->plprcrk = ~KEEP_ALIVE_KEY; | |
| 73 | + if(isfads){ | |
| 74 | + m->bcsr[1] |= EnableSDRAM; | |
| 75 | + sdraminit(SDRAMMEM); | |
| 76 | + if(!USESDRAM) | |
| 77 | + m->bcsr[1] &= ~EnableSDRAM; /* tells kernel not to map it */ | |
| 78 | + } | |
| 79 | +} | |
| 80 | + | |
| 81 | +static void | |
| 82 | +archidprint(void) | |
| 83 | +{ | |
| 84 | + int f, i; | |
| 85 | + ulong v; | |
| 86 | + | |
| 87 | + /* 8xx and FADS specific */ | |
| 88 | + print("IMMR: "); | |
| 89 | + v = getimmr() & 0xFFFF; | |
| 90 | + switch(v>>8){ | |
| 91 | + case 0x00: print("MPC860/821"); break; | |
| 92 | + case 0x20: print("MPC823"); break; | |
| 93 | + case 0x21: print("MPC823A"); break; | |
| 94 | + default: print("Type #%lux", v>>8); break; | |
| 95 | + } | |
| 96 | + print(", mask #%lux\n", v&0xFF); | |
| 97 | + v = m->bcsr[3]>>16; | |
| 98 | + print("MPC8xxFADS rev %lud, DB: ", ((v>>4)&8)|((v>>1)&4)|(v&3)); | |
| 99 | + f = (v>>8)&0x3F; | |
| 100 | + switch(f){ | |
| 101 | + default: print("ID#%x", f); break; | |
| 102 | + case 0x00: print("MPC860/821"); break; | |
| 103 | + case 0x01: print("MPC813"); break; | |
| 104 | + case 0x02: print("MPC821"); break; | |
| 105 | + case 0x03: print("MPC823"); break; | |
| 106 | + case 0x20: print("MPC801"); break; | |
| 107 | + case 0x21: print("MPC850"); break; | |
| 108 | + case 0x22: print("MPC860"); break; | |
| 109 | + case 0x23: print("MPC860SAR"); break; | |
| 110 | + case 0x24: print("MPC860T"); break; | |
| 111 | + } | |
| 112 | + print("ADS, rev #%lux\n", (m->bcsr[2]>>16)&7); | |
| 113 | + for(i=0; i<=4; i++) | |
| 114 | + print("BCSR%d: %8.8lux\n", i, m->bcsr[i]); | |
| 115 | + v = m->bcsr[2]; | |
| 116 | + f = (v>>28)&0xF; | |
| 117 | + switch(f){ | |
| 118 | + default: print("Unknown"); break; | |
| 119 | + case 4: print("SM732A2000/SM73228 - 8M SIMM"); break; | |
| 120 | + case 5: print("SM732A1000A/SM73218 - 4M SIMM"); break; | |
| 121 | + case 6: print("MCM29080 - 8M SIMM"); break; | |
| 122 | + case 7: print("MCM29040 - 4M SIMM"); break; | |
| 123 | + case 8: print("MCM29020 - 2M SIMM"); break; | |
| 124 | + } | |
| 125 | + switch((m->bcsr[3]>>20)&7){ | |
| 126 | + default: i = 0; break; | |
| 127 | + case 1: i = 150; break; | |
| 128 | + case 2: i = 120; break; | |
| 129 | + case 3: i = 90; break; | |
| 130 | + } | |
| 131 | + print(" flash, %dns\n", i); | |
| 132 | + f = (v>>23)&0xF; | |
| 133 | + switch(f&3){ | |
| 134 | + case 0: i = 4; break; | |
| 135 | + case 1: i = 32; break; | |
| 136 | + case 2: i = 16; break; | |
| 137 | + case 3: i = 8; break; | |
| 138 | + } | |
| 139 | + print("%dM SIMM, ", i); | |
| 140 | + switch(f>>2){ | |
| 141 | + default: i = 0; break; | |
| 142 | + case 2: i = 70; break; | |
| 143 | + case 3: i = 60; break; | |
| 144 | + } | |
| 145 | + print("%dns\n", i); | |
| 146 | + print("options: #%lux\n", (m->bcsr[2]>>19)&0xF); | |
| 147 | + print("plprcr=%8.8lux sccr=%8.8lux\n", m->iomem->plprcr, m->iomem->sccr); | |
| 148 | +} | |
| 149 | + | |
| 150 | +void | |
| 151 | +cpuidprint(void) | |
| 152 | +{ | |
| 153 | + int t; | |
| 154 | + | |
| 155 | + print("PVR: "); | |
| 156 | + t = getpvr()>>16; | |
| 157 | + switch(t){ | |
| 158 | + case 0x01: print("MPC601"); break; | |
| 159 | + case 0x03: print("MPC603"); break; | |
| 160 | + case 0x04: print("MPC604"); break; | |
| 161 | + case 0x06: print("MPC603e"); break; | |
| 162 | + case 0x07: print("MPC603e-v7"); break; | |
| 163 | + case 0x50: print("MPC8xx"); break; | |
| 164 | + default: print("PowerPC version #%x", t); break; | |
| 165 | + } | |
| 166 | + print(", revision #%lux\n", getpvr()&0xffff); | |
| 167 | + archidprint(); | |
| 168 | + print("%lud MHz system\n", m->cpuhz/MHz); | |
| 169 | + print("\n"); | |
| 170 | +} | |
| 171 | + | |
| 172 | +static char* defplan9ini[2] = { | |
| 173 | + /* 860/821 */ | |
| 174 | + "ether0=type=SCC port=1 ea=00108bf12900\r\n" | |
| 175 | + "vgasize=640x480x8\r\n" | |
| 176 | + "kernelpercent=40\r\n" | |
| 177 | + "console=0 lcd\r\nbaud=9600\r\n", | |
| 178 | + | |
| 179 | + /* 823 */ | |
| 180 | + "ether0=type=SCC port=2 ea=00108bf12900\r\n" | |
| 181 | + "vgasize=640x480x8\r\n" | |
| 182 | + "kernelpercent=40\r\n" | |
| 183 | + "console=0 lcd\r\nbaud=9600\r\n", | |
| 184 | +}; | |
| 185 | + | |
| 186 | +char * | |
| 187 | +archconfig(void) | |
| 188 | +{ | |
| 189 | + print("Using default configuration\n"); | |
| 190 | + return defplan9ini[MPCMODEL(m->cputype) == 0x823]; | |
| 191 | +} | |
| 192 | + | |
| 193 | +/* | |
| 194 | + * provide value for #r/switch (devrtc.c) | |
| 195 | + */ | |
| 196 | +int | |
| 197 | +archoptionsw(void) | |
| 198 | +{ | |
| 199 | + return (m->bcsr[2]>>19)&0xF; /* value of switch DS1 */ | |
| 200 | +} | |
| 201 | + | |
| 202 | +/* | |
| 203 | + * invoked by clock.c:/^clockintr | |
| 204 | + */ | |
| 205 | +static void | |
| 206 | +twinkle(void) | |
| 207 | +{ | |
| 208 | + if(m->ticks%MS2TK(1000) == 0) | |
| 209 | + m->bcsr[4] ^= DisableLamp; | |
| 210 | +} | |
| 211 | + | |
| 212 | +void (*archclocktick)(void) = twinkle; | |
| 213 | + | |
| 214 | +/* | |
| 215 | + * for flash.c:/^flashreset | |
| 216 | + * retrieve flash type, virtual base and length and return 0; | |
| 217 | + * return -1 on error (no flash) | |
| 218 | + */ | |
| 219 | +int | |
| 220 | +archflashreset(char *type, void **addr, long *length) | |
| 221 | +{ | |
| 222 | + char *t; | |
| 223 | + int mbyte; | |
| 224 | + | |
| 225 | + if((m->iomem->memc[0].base & 1) == 0) | |
| 226 | + return -1; /* shouldn't happen */ | |
| 227 | + switch((m->bcsr[2]>>28)&0xF){ | |
| 228 | + default: return -1; /* unknown or not there */ | |
| 229 | + case 4: mbyte=8; t = "SM732x8"; break; | |
| 230 | + case 5: mbyte=4; t = "SM732x8"; break; | |
| 231 | + case 6: mbyte=8; t = "AMD29F0x0"; break; | |
| 232 | + case 7: mbyte=4; t = "AMD29F0x0"; break; | |
| 233 | + case 8: mbyte=2; t = "AMD29F0x0"; break; | |
| 234 | + } | |
| 235 | + strcpy(type, t); | |
| 236 | + *addr = KADDR(FLASHMEM); | |
| 237 | + *length = mbyte*1024*1024; | |
| 238 | + return 0; | |
| 239 | +} | |
| 240 | + | |
| 241 | +/* | |
| 242 | + * enable the clocks for the given SCC ether and reveal them to the caller. | |
| 243 | + * do anything else required to prepare the transceiver (eg, set full-duplex, reset loopback). | |
| 244 | + */ | |
| 245 | +int | |
| 246 | +archetherenable(int cpmid, int *rcs, int *tcs) | |
| 247 | +{ | |
| 248 | + IMM *io; | |
| 249 | + | |
| 250 | + switch(cpmid){ | |
| 251 | + default: | |
| 252 | + /* no other SCCs are wired on the FADS board */ | |
| 253 | + return -1; | |
| 254 | + | |
| 255 | + case SCC2ID: /* assume 8xxFADS board with 823DABS */ | |
| 256 | + io = ioplock(); | |
| 257 | + m->bcsr[1] |= DisableIR|DisableRS232b; | |
| 258 | + m->bcsr[1] &= ~DisableEther; | |
| 259 | + io->papar |= SIBIT(6)|SIBIT(5); /* enable CLK2 and CLK3 */ | |
| 260 | + io->padir &= ~(SIBIT(6)|SIBIT(5)); | |
| 261 | + | |
| 262 | + /* ETHLOOP etc set in BCSR elsewhere */ | |
| 263 | + *rcs = CLK2; | |
| 264 | + *tcs = CLK3; | |
| 265 | + iopunlock(); | |
| 266 | + break; | |
| 267 | + | |
| 268 | + case SCC1ID: /* assume 860/21 development board */ | |
| 269 | + io = ioplock(); | |
| 270 | + m->bcsr[1] |= DisableIR|DisableRS232b; /* TO DO: might not be shared with RS232b */ | |
| 271 | + m->bcsr[1] &= ~DisableEther; | |
| 272 | + io->papar |= SIBIT(6)|SIBIT(7); /* enable CLK2 and CLK1 */ | |
| 273 | + io->padir &= ~(SIBIT(6)|SIBIT(7)); | |
| 274 | + | |
| 275 | + /* settings peculiar to 860/821 development board */ | |
| 276 | + io->pcpar &= ~(SIBIT(4)|SIBIT(5)|SIBIT(6)); /* ETHLOOP, TPFULDL~, TPSQEL~ */ | |
| 277 | + io->pcdir |= SIBIT(4)|SIBIT(5)|SIBIT(6); | |
| 278 | + io->pcdat &= ~SIBIT(4); | |
| 279 | + io->pcdat |= SIBIT(5)|SIBIT(6); | |
| 280 | + *rcs = CLK2; | |
| 281 | + *tcs = CLK1; | |
| 282 | + iopunlock(); | |
| 283 | + break; | |
| 284 | + } | |
| 285 | + return 0; | |
| 286 | +} | |
| 287 | + | |
| 288 | +void | |
| 289 | +archetherdisable(int id) | |
| 290 | +{ | |
| 291 | + USED(id); | |
| 292 | + m->bcsr[1] |= DisableEther|DisableIR|DisableRS232b; | |
| 293 | +} | |
| 294 | + | |
| 295 | +/* | |
| 296 | + * do anything extra required to enable the UART on the given CPM port | |
| 297 | + */ | |
| 298 | +void | |
| 299 | +archenableuart(int id, int irda) | |
| 300 | +{ | |
| 301 | + switch(id){ | |
| 302 | + case SMC1ID: | |
| 303 | + m->bcsr[1] &= ~DisableRS232a; | |
| 304 | + break; | |
| 305 | + case SCC2ID: | |
| 306 | + m->bcsr[1] |= DisableEther|DisableIR|DisableRS232b; | |
| 307 | + if(irda) | |
| 308 | + m->bcsr[1] &= ~DisableIR; | |
| 309 | + else | |
| 310 | + m->bcsr[1] &= ~DisableRS232b; | |
| 311 | + break; | |
| 312 | + default: | |
| 313 | + /* nothing special */ | |
| 314 | + break; | |
| 315 | + } | |
| 316 | +} | |
| 317 | + | |
| 318 | +/* | |
| 319 | + * do anything extra required to disable the UART on the given CPM port | |
| 320 | + */ | |
| 321 | +void | |
| 322 | +archdisableuart(int id) | |
| 323 | +{ | |
| 324 | + switch(id){ | |
| 325 | + case SMC1ID: | |
| 326 | + m->bcsr[1] |= DisableRS232a; | |
| 327 | + break; | |
| 328 | + case SCC2ID: | |
| 329 | + m->bcsr[1] |= DisableIR|DisableRS232b; | |
| 330 | + break; | |
| 331 | + default: | |
| 332 | + /* nothing special */ | |
| 333 | + break; | |
| 334 | + } | |
| 335 | +} | |
| 336 | + | |
| 337 | +/* | |
| 338 | + * enable/disable the LCD panel's backlight via | |
| 339 | + * York touch panel interface (does no harm without it) | |
| 340 | + */ | |
| 341 | +void | |
| 342 | +archbacklight(int on) | |
| 343 | +{ | |
| 344 | + IMM *io; | |
| 345 | + | |
| 346 | + delay(2); | |
| 347 | + io = ioplock(); | |
| 348 | + io->papar &= ~SIBIT(4); | |
| 349 | + io->padir |= SIBIT(4); | |
| 350 | + if(on) | |
| 351 | + io->padat |= SIBIT(4); | |
| 352 | + else | |
| 353 | + io->padat &= ~SIBIT(4); | |
| 354 | + iopunlock(); | |
| 355 | +} | |
| @@ -0,0 +1,42 @@ | ||
| 1 | + | |
| 2 | +enum { | |
| 3 | + /* BCSR1 bits */ | |
| 4 | + DisableFlash= IBIT(0), | |
| 5 | + DisableDRAM= IBIT(1), | |
| 6 | + DisableEther= IBIT(2), | |
| 7 | + DisableIR= IBIT(3), | |
| 8 | + DisableRS232a= IBIT(7), | |
| 9 | + DisablePCMCIA= IBIT(8), | |
| 10 | + PCCVCCMask= IBIT(9)|IBIT(15), | |
| 11 | + PCCVPPMask= IBIT(10)|IBIT(11), | |
| 12 | + DisableRS232b= IBIT(13), | |
| 13 | + EnableSDRAM= IBIT(14), | |
| 14 | + | |
| 15 | + PCCVCC0V= IBIT(15)|IBIT(9), | |
| 16 | + PCCVCC5V= IBIT(9), /* active low */ | |
| 17 | + PCCVCC3V= IBIT(15), /* active low */ | |
| 18 | + PCCVPP0V= IBIT(10)|IBIT(11), /* active low */ | |
| 19 | + PCCVPP5V= IBIT(10), /* active low */ | |
| 20 | + PCCVPP12V= IBIT(11), /* active low */ | |
| 21 | + PCCVPPHiZ= IBIT(10)|IBIT(11), | |
| 22 | + | |
| 23 | + /* BCSR4 bits */ | |
| 24 | + DisableTPDuplex= IBIT(1), | |
| 25 | + DisableLamp= IBIT(3), | |
| 26 | + DisableUSB= IBIT(4), | |
| 27 | + USBFullSpeed= IBIT(5), | |
| 28 | + DisableUSBVcc= IBIT(6), | |
| 29 | + DisableVideoLamp= IBIT(8), | |
| 30 | + EnableVideoClock= IBIT(9), | |
| 31 | + EnableVideoPort= IBIT(10), | |
| 32 | + DisableModem= IBIT(11), | |
| 33 | +}; | |
| 34 | + | |
| 35 | +enum { | |
| 36 | + /* memory controller CS assignment on FADS boards */ | |
| 37 | + BOOTCS = 0, | |
| 38 | + BCSRCS = 1, | |
| 39 | + DRAM1 = 2, | |
| 40 | + DRAM2 = 3, | |
| 41 | + SDRAM = 4, | |
| 42 | +}; | |
| @@ -0,0 +1,240 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +#include "archpaq.h" | |
| 9 | + | |
| 10 | +/* | |
| 11 | + * board-specific support for the 82x PowerPAQ | |
| 12 | + */ | |
| 13 | + | |
| 14 | +enum { | |
| 15 | + SYSMHZ = 50, /* desired system clock in MHz */ | |
| 16 | + | |
| 17 | + /* sccr */ | |
| 18 | + RTSEL = IBIT(8), /* =0, select main oscillator (OSCM); =1, select external crystal (EXTCLK) */ | |
| 19 | + RTDIV = IBIT(7), /* =0, divide by 4; =1, divide by 512 */ | |
| 20 | + CRQEN = IBIT(9), /* =1, switch to high frequency when CPM active */ | |
| 21 | + PRQEN = IBIT(10), /* =1, switch to high frequency when interrupt pending */ | |
| 22 | + | |
| 23 | + /* plprcr */ | |
| 24 | + CSRC = IBIT(21), /* =0, clock is DFNH; =1, clock is DFNL */ | |
| 25 | +}; | |
| 26 | + | |
| 27 | +/* | |
| 28 | + * called early in main.c, after machinit: | |
| 29 | + * using board and architecture specific registers, initialise | |
| 30 | + * 8xx registers that need it and complete initialisation of the Mach structure. | |
| 31 | + */ | |
| 32 | +void | |
| 33 | +archinit(void) | |
| 34 | +{ | |
| 35 | + IMM *io; | |
| 36 | + int mf, t; | |
| 37 | + | |
| 38 | + switch((getimmr()>>8)&0xFF){ | |
| 39 | + case 0x00: t = 0x86000; break; /* also 821 */ | |
| 40 | + case 0x20: t = 0x82300; break; | |
| 41 | + case 0x21: t = 0x823a0; break; | |
| 42 | + default: t = 0; break; | |
| 43 | + } | |
| 44 | + m->cputype = t; | |
| 45 | + m->bcsr = nil; /* there isn't one */ | |
| 46 | + m->clockgen = 32*1024; /* crystal frequency */ | |
| 47 | + io = m->iomem; | |
| 48 | + io->sccrk = KEEP_ALIVE_KEY; | |
| 49 | + io->sccr &= ~RTDIV; /* divide 32k by 4 */ | |
| 50 | + io->sccr |= RTSEL; | |
| 51 | + io->sccrk = ~KEEP_ALIVE_KEY; | |
| 52 | + mf = (SYSMHZ*MHz)/m->clockgen; | |
| 53 | + m->cpuhz = m->clockgen*mf; | |
| 54 | + io->plprcrk = KEEP_ALIVE_KEY; | |
| 55 | + io->plprcr &= ~IBIT(21); /* general system clock is DFNH */ | |
| 56 | + io->plprcr = (io->plprcr & ((1<<20)-1)) | ((mf-1)<<20); | |
| 57 | + io->mptpr = 0x0400; /* memory prescaler = 16 for refresh */ | |
| 58 | + io->plprcrk = ~KEEP_ALIVE_KEY; | |
| 59 | +} | |
| 60 | + | |
| 61 | +void | |
| 62 | +cpuidprint(void) | |
| 63 | +{ | |
| 64 | + int t, v; | |
| 65 | + | |
| 66 | + print("PVR: "); | |
| 67 | + t = getpvr()>>16; | |
| 68 | + switch(t){ | |
| 69 | + case 0x01: print("MPC601"); break; | |
| 70 | + case 0x03: print("MPC603"); break; | |
| 71 | + case 0x04: print("MPC604"); break; | |
| 72 | + case 0x06: print("MPC603e"); break; | |
| 73 | + case 0x07: print("MPC603e-v7"); break; | |
| 74 | + case 0x50: print("MPC8xx"); break; | |
| 75 | + default: print("PowerPC version #%x", t); break; | |
| 76 | + } | |
| 77 | + print(", revision #%lux\n", getpvr()&0xffff); | |
| 78 | + print("IMMR: "); | |
| 79 | + v = getimmr() & 0xFFFF; | |
| 80 | + switch(v>>8){ | |
| 81 | + case 0x00: print("MPC860/821"); break; | |
| 82 | + case 0x20: print("MPC823"); break; | |
| 83 | + case 0x21: print("MPC823A"); break; | |
| 84 | + default: print("Type #%lux", v>>8); break; | |
| 85 | + } | |
| 86 | + print(", mask #%lux\n", v&0xFF); | |
| 87 | + print("plprcr=%8.8lux sccr=%8.8lux\n", m->iomem->plprcr, m->iomem->sccr); | |
| 88 | + print("%lud MHz system\n", m->cpuhz/MHz); | |
| 89 | + print("\n"); | |
| 90 | +} | |
| 91 | + | |
| 92 | +static char* defplan9ini[2] = { | |
| 93 | + /* 860/821 */ | |
| 94 | + "ether0=type=SCC port=1 ea=00108bf12900\r\n" | |
| 95 | + "vgasize=640x480x8\r\n" | |
| 96 | + "kernelpercent=40\r\n" | |
| 97 | + "console=0 lcd\r\nbaud=19200\r\n", | |
| 98 | + | |
| 99 | + /* 823 */ | |
| 100 | + "ether0=type=SCC port=2 ea=00108bf12900\r\n" | |
| 101 | + "vgasize=640x480x8\r\n" | |
| 102 | + "kernelpercent=40\r\n" | |
| 103 | + "console=0 lcd\r\nbaud=19200\r\n", | |
| 104 | +}; | |
| 105 | + | |
| 106 | +char * | |
| 107 | +archconfig(void) | |
| 108 | +{ | |
| 109 | + print("Using default configuration\n"); | |
| 110 | + return defplan9ini[MPCMODEL(m->cputype) == 0x823]; | |
| 111 | +} | |
| 112 | + | |
| 113 | +/* | |
| 114 | + * provide value for #r/switch (devrtc.c) | |
| 115 | + */ | |
| 116 | +int | |
| 117 | +archoptionsw(void) | |
| 118 | +{ | |
| 119 | + return 0; | |
| 120 | +} | |
| 121 | + | |
| 122 | +/* | |
| 123 | + * invoked by clock.c:/^clockintr | |
| 124 | + */ | |
| 125 | +static void | |
| 126 | +twinkle(void) | |
| 127 | +{ | |
| 128 | + /* no easy-to-use LED on PAQ (they use i2c) */ | |
| 129 | +} | |
| 130 | + | |
| 131 | +void (*archclocktick)(void) = twinkle; | |
| 132 | + | |
| 133 | +/* | |
| 134 | + * for flash.c:/^flashinit | |
| 135 | + * retrieve flash type, virtual base and length and return 0; | |
| 136 | + * return -1 on error (no flash) | |
| 137 | + */ | |
| 138 | +int | |
| 139 | +archflashreset(char *type, void **addr, long *length) | |
| 140 | +{ | |
| 141 | + strcpy(type, "AMD29F0x0"); | |
| 142 | + *addr = KADDR(FLASHMEM); | |
| 143 | + *length = 8*1024*1024; /* 8mbytes on some models */ | |
| 144 | + return 0; | |
| 145 | +} | |
| 146 | + | |
| 147 | +/* | |
| 148 | + * enable the clocks for the given SCC ether and reveal them to the caller. | |
| 149 | + * do anything else required to prepare the transceiver (eg, set full-duplex, reset loopback). | |
| 150 | + */ | |
| 151 | +int | |
| 152 | +archetherenable(int cpmid, int *rcs, int *tcs) | |
| 153 | +{ | |
| 154 | + USED(cpmid, rcs, tcs); | |
| 155 | + return -1; /* there isn't an ether on the PAQs */ | |
| 156 | +} | |
| 157 | + | |
| 158 | +void | |
| 159 | +archetherdisable(int id) | |
| 160 | +{ | |
| 161 | + USED(id); | |
| 162 | +} | |
| 163 | + | |
| 164 | +/* | |
| 165 | + * do anything extra required to enable the UART on the given CPM port | |
| 166 | + */ | |
| 167 | +void | |
| 168 | +archenableuart(int id, int irda) | |
| 169 | +{ | |
| 170 | + IMM *io; | |
| 171 | + | |
| 172 | + USED(irda); | |
| 173 | + switch(id){ | |
| 174 | + case SMC1ID: | |
| 175 | + io = ioplock(); | |
| 176 | + io->pbodr &= ~0xc0; | |
| 177 | + io->pbdat |= 0xc0; | |
| 178 | + io->pcdat |= 0x400; | |
| 179 | + io->pcpar &= ~0x400; | |
| 180 | + io->pcdir |= 0x400; | |
| 181 | + io->pcdat &= ~0x400; /* enable SMC RS232 buffer */ | |
| 182 | + iopunlock(); | |
| 183 | + break; | |
| 184 | + case SCC2ID: | |
| 185 | + /* TO DO */ | |
| 186 | + break; | |
| 187 | + default: | |
| 188 | + /* nothing special */ | |
| 189 | + break; | |
| 190 | + } | |
| 191 | +} | |
| 192 | + | |
| 193 | +/* | |
| 194 | + * do anything extra required to disable the UART on the given CPM port | |
| 195 | + */ | |
| 196 | +void | |
| 197 | +archdisableuart(int id) | |
| 198 | +{ | |
| 199 | + switch(id){ | |
| 200 | + case SMC1ID: | |
| 201 | + /* TO DO */ | |
| 202 | + break; | |
| 203 | + case SCC2ID: | |
| 204 | + /* TO DO */ | |
| 205 | + break; | |
| 206 | + default: | |
| 207 | + /* nothing special */ | |
| 208 | + break; | |
| 209 | + } | |
| 210 | +} | |
| 211 | + | |
| 212 | +/* | |
| 213 | + * enable/disable the LCD panel's backlight via i2c | |
| 214 | + */ | |
| 215 | +void | |
| 216 | +archbacklight(int on) | |
| 217 | +{ | |
| 218 | + uchar msg; | |
| 219 | + IMM *io; | |
| 220 | + | |
| 221 | + i2csetup(); | |
| 222 | + msg = ~7; | |
| 223 | + i2csend(LEDRegI2C, &msg, 1); | |
| 224 | + io = ioplock(); | |
| 225 | + io->pbpar &= ~EnableLCD; | |
| 226 | + io->pbodr &= ~EnableLCD; | |
| 227 | + io->pbdir |= EnableLCD; | |
| 228 | + if(on) | |
| 229 | + io->pbdat |= EnableLCD; | |
| 230 | + else | |
| 231 | + io->pbdat &= ~EnableLCD; | |
| 232 | + iopunlock(); | |
| 233 | + if(on){ | |
| 234 | + msg = ~(DisablePanelVCC5|DisableTFT); | |
| 235 | + i2csend(PanelI2C, &msg, 1); | |
| 236 | + }else{ | |
| 237 | + msg = ~0; | |
| 238 | + i2csend(PanelI2C, &msg, 1); | |
| 239 | + } | |
| 240 | +} | |
| @@ -0,0 +1,29 @@ | ||
| 1 | +enum { | |
| 2 | + /* memory controller CS assignment on PowerPAQ */ | |
| 3 | + BOOTCS = 0, | |
| 4 | + DRAM1 = 1, /* UPMB */ | |
| 5 | + DRAM2 = 2, /* UPMB */ | |
| 6 | + /* CS3 also connected to DRAM */ | |
| 7 | + /* CS4 128mbyte 8-bit gpcm, trlx, 15 wait; it's DAC */ | |
| 8 | + /* CS5 is external*/ | |
| 9 | +}; | |
| 10 | + | |
| 11 | +enum { | |
| 12 | + /* I2C addresses */ | |
| 13 | + PanelI2C = 0x21<<1, | |
| 14 | + /* the control bits are active low enables, or high disables */ | |
| 15 | + DisableVGA = ~0xFD, /* disable VGA signals */ | |
| 16 | + DisableTFT = ~0xFB, /* disable TFT panel signals */ | |
| 17 | + DisableSPIBus = ~0xF7, /* disable SPI/I2C to panel */ | |
| 18 | + DisablePanelVCC5 = ~0xEF, /* disable +5V to panel(s) */ | |
| 19 | + DisablePanelVCC3 = ~0xDF, /* disable +3.3V to panel(s) */ | |
| 20 | + DisableMonoPanel = ~0xBF, /* disable mono panel signals */ | |
| 21 | + DisableSPISelect = ~0x7F, /* disable SPI chip select to LVDS panel */ | |
| 22 | + ContrastI2C = 0x2E<<1, | |
| 23 | + LEDRegI2C = 0x20<<1, | |
| 24 | + DisableGreenLED = ~0xFE, | |
| 25 | + DisableYellowLED = ~0xFD, | |
| 26 | + DisableRedLED = ~0xFB, | |
| 27 | + | |
| 28 | + EnableLCD = IBIT(23), /* LCD enable bit in i/o port B */ | |
| 29 | +}; | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include "lib.h" | |
| 3 | + | |
| 4 | +#include "mem.h" | |
| 5 | +#include "dat.h" | |
| 6 | +#include "fns.h" | |
| 7 | +#include "io.h" | |
| 8 | +#include "ureg.h" | |
| @@ -0,0 +1,507 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +#include "ip.h" | |
| 9 | + | |
| 10 | +enum { | |
| 11 | + CHECKSUM = 1, /* set zero if trouble booting from Linux */ | |
| 12 | +}; | |
| 13 | + | |
| 14 | +uchar broadcast[Eaddrlen] = { | |
| 15 | + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 16 | +}; | |
| 17 | + | |
| 18 | +static ushort tftpport = 5000; | |
| 19 | +static int Id = 1; | |
| 20 | +static Netaddr myaddr; | |
| 21 | +static Netaddr server; | |
| 22 | + | |
| 23 | +typedef struct { | |
| 24 | + uchar header[4]; | |
| 25 | + uchar data[Segsize]; | |
| 26 | +} Tftp; | |
| 27 | +static Tftp tftpb; | |
| 28 | + | |
| 29 | +static void | |
| 30 | +hnputs(uchar *ptr, ushort val) | |
| 31 | +{ | |
| 32 | + ptr[0] = val>>8; | |
| 33 | + ptr[1] = val; | |
| 34 | +} | |
| 35 | + | |
| 36 | +static void | |
| 37 | +hnputl(uchar *ptr, ulong val) | |
| 38 | +{ | |
| 39 | + ptr[0] = val>>24; | |
| 40 | + ptr[1] = val>>16; | |
| 41 | + ptr[2] = val>>8; | |
| 42 | + ptr[3] = val; | |
| 43 | +} | |
| 44 | + | |
| 45 | +static ulong | |
| 46 | +nhgetl(uchar *ptr) | |
| 47 | +{ | |
| 48 | + return ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]); | |
| 49 | +} | |
| 50 | + | |
| 51 | +static ushort | |
| 52 | +nhgets(uchar *ptr) | |
| 53 | +{ | |
| 54 | + return ((ptr[0]<<8) | ptr[1]); | |
| 55 | +} | |
| 56 | + | |
| 57 | +static short endian = 1; | |
| 58 | +static char* aendian = (char*)&endian; | |
| 59 | +#define LITTLE *aendian | |
| 60 | + | |
| 61 | +static ushort | |
| 62 | +ptcl_csum(void *a, int len) | |
| 63 | +{ | |
| 64 | + uchar *addr; | |
| 65 | + ulong t1, t2; | |
| 66 | + ulong losum, hisum, mdsum, x; | |
| 67 | + | |
| 68 | + addr = a; | |
| 69 | + losum = 0; | |
| 70 | + hisum = 0; | |
| 71 | + mdsum = 0; | |
| 72 | + | |
| 73 | + x = 0; | |
| 74 | + if((ulong)addr & 1) { | |
| 75 | + if(len) { | |
| 76 | + hisum += addr[0]; | |
| 77 | + len--; | |
| 78 | + addr++; | |
| 79 | + } | |
| 80 | + x = 1; | |
| 81 | + } | |
| 82 | + while(len >= 16) { | |
| 83 | + t1 = *(ushort*)(addr+0); | |
| 84 | + t2 = *(ushort*)(addr+2); mdsum += t1; | |
| 85 | + t1 = *(ushort*)(addr+4); mdsum += t2; | |
| 86 | + t2 = *(ushort*)(addr+6); mdsum += t1; | |
| 87 | + t1 = *(ushort*)(addr+8); mdsum += t2; | |
| 88 | + t2 = *(ushort*)(addr+10); mdsum += t1; | |
| 89 | + t1 = *(ushort*)(addr+12); mdsum += t2; | |
| 90 | + t2 = *(ushort*)(addr+14); mdsum += t1; | |
| 91 | + mdsum += t2; | |
| 92 | + len -= 16; | |
| 93 | + addr += 16; | |
| 94 | + } | |
| 95 | + while(len >= 2) { | |
| 96 | + mdsum += *(ushort*)addr; | |
| 97 | + len -= 2; | |
| 98 | + addr += 2; | |
| 99 | + } | |
| 100 | + if(x) { | |
| 101 | + if(len) | |
| 102 | + losum += addr[0]; | |
| 103 | + if(LITTLE) | |
| 104 | + losum += mdsum; | |
| 105 | + else | |
| 106 | + hisum += mdsum; | |
| 107 | + } else { | |
| 108 | + if(len) | |
| 109 | + hisum += addr[0]; | |
| 110 | + if(LITTLE) | |
| 111 | + hisum += mdsum; | |
| 112 | + else | |
| 113 | + losum += mdsum; | |
| 114 | + } | |
| 115 | + | |
| 116 | + losum += hisum >> 8; | |
| 117 | + losum += (hisum & 0xff) << 8; | |
| 118 | + while(hisum = losum>>16) | |
| 119 | + losum = hisum + (losum & 0xffff); | |
| 120 | + | |
| 121 | + return ~losum; | |
| 122 | +} | |
| 123 | + | |
| 124 | +static ushort | |
| 125 | +ip_csum(uchar *addr) | |
| 126 | +{ | |
| 127 | + int len; | |
| 128 | + ulong sum = 0; | |
| 129 | + | |
| 130 | + len = (addr[0]&0xf)<<2; | |
| 131 | + | |
| 132 | + while(len > 0) { | |
| 133 | + sum += addr[0]<<8 | addr[1] ; | |
| 134 | + len -= 2; | |
| 135 | + addr += 2; | |
| 136 | + } | |
| 137 | + | |
| 138 | + sum = (sum & 0xffff) + (sum >> 16); | |
| 139 | + sum = (sum & 0xffff) + (sum >> 16); | |
| 140 | + return (sum^0xffff); | |
| 141 | +} | |
| 142 | + | |
| 143 | +static void | |
| 144 | +udpsend(int ctlrno, Netaddr *a, void *data, int dlen) | |
| 145 | +{ | |
| 146 | + Udphdr *uh; | |
| 147 | + Etherhdr *ip; | |
| 148 | + static Etherpkt pkt; | |
| 149 | + int len, ptcllen; | |
| 150 | + | |
| 151 | + | |
| 152 | + uh = (Udphdr*)&pkt; | |
| 153 | + | |
| 154 | + memset(uh, 0, sizeof(Etherpkt)); | |
| 155 | + memmove(uh->udpcksum+sizeof(uh->udpcksum), data, dlen); | |
| 156 | + | |
| 157 | + /* | |
| 158 | + * UDP portion | |
| 159 | + */ | |
| 160 | + ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE); | |
| 161 | + uh->ttl = 0; | |
| 162 | + uh->udpproto = IP_UDPPROTO; | |
| 163 | + uh->frag[0] = 0; | |
| 164 | + uh->frag[1] = 0; | |
| 165 | + hnputs(uh->udpplen, ptcllen); | |
| 166 | + hnputl(uh->udpsrc, myaddr.ip); | |
| 167 | + hnputs(uh->udpsport, myaddr.port); | |
| 168 | + hnputl(uh->udpdst, a->ip); | |
| 169 | + hnputs(uh->udpdport, a->port); | |
| 170 | + hnputs(uh->udplen, ptcllen); | |
| 171 | + uh->udpcksum[0] = 0; | |
| 172 | + uh->udpcksum[1] = 0; | |
| 173 | + /*dlen = (dlen+1)&~1; */ | |
| 174 | + hnputs(uh->udpcksum, ptcl_csum(&uh->ttl, dlen+UDP_HDRSIZE)); | |
| 175 | + | |
| 176 | + /* | |
| 177 | + * IP portion | |
| 178 | + */ | |
| 179 | + ip = (Etherhdr*)&pkt; | |
| 180 | + len = sizeof(Udphdr)+dlen; | |
| 181 | + ip->vihl = IP_VER|IP_HLEN; | |
| 182 | + ip->tos = 0; | |
| 183 | + ip->ttl = 255; | |
| 184 | + hnputs(ip->length, len-ETHER_HDR); | |
| 185 | + hnputs(ip->id, Id++); | |
| 186 | + ip->frag[0] = 0; | |
| 187 | + ip->frag[1] = 0; | |
| 188 | + ip->cksum[0] = 0; | |
| 189 | + ip->cksum[1] = 0; | |
| 190 | + hnputs(ip->cksum, ip_csum(&ip->vihl)); | |
| 191 | + | |
| 192 | + /* | |
| 193 | + * Ethernet MAC portion | |
| 194 | + */ | |
| 195 | + hnputs(ip->type, ET_IP); | |
| 196 | + memmove(ip->d, a->ea, sizeof(ip->d)); | |
| 197 | + | |
| 198 | + ethertxpkt(ctlrno, &pkt, len, Timeout); | |
| 199 | +} | |
| 200 | + | |
| 201 | +static void | |
| 202 | +nak(int ctlrno, Netaddr *a, int code, char *msg, int report) | |
| 203 | +{ | |
| 204 | + int n; | |
| 205 | + char buf[128]; | |
| 206 | + | |
| 207 | + buf[0] = 0; | |
| 208 | + buf[1] = Tftp_ERROR; | |
| 209 | + buf[2] = 0; | |
| 210 | + buf[3] = code; | |
| 211 | + strcpy(buf+4, msg); | |
| 212 | + n = strlen(msg) + 4 + 1; | |
| 213 | + udpsend(ctlrno, a, buf, n); | |
| 214 | + if(report) | |
| 215 | + print("\ntftp: error(%d): %s\n", code, msg); | |
| 216 | +} | |
| 217 | + | |
| 218 | +static int | |
| 219 | +udprecv(int ctlrno, Netaddr *a, void *data, int dlen) | |
| 220 | +{ | |
| 221 | + int n, len; | |
| 222 | + ushort csm; | |
| 223 | + Udphdr *h; | |
| 224 | + ulong addr, timo; | |
| 225 | + static Etherpkt pkt; | |
| 226 | + static int rxactive; | |
| 227 | + | |
| 228 | + if(rxactive == 0) | |
| 229 | + timo = 1000; | |
| 230 | + else | |
| 231 | + timo = Timeout; | |
| 232 | + timo += TK2MS(m->ticks); | |
| 233 | + while(timo > TK2MS(m->ticks)){ | |
| 234 | + n = etherrxpkt(ctlrno, &pkt, timo-TK2MS(m->ticks)); | |
| 235 | + if(n <= 0) | |
| 236 | + continue; | |
| 237 | + | |
| 238 | + h = (Udphdr*)&pkt; | |
| 239 | + if(nhgets(h->type) != ET_IP) | |
| 240 | + continue; | |
| 241 | + | |
| 242 | + if(ip_csum(&h->vihl)) { | |
| 243 | + print("ip chksum error\n"); | |
| 244 | + continue; | |
| 245 | + } | |
| 246 | + if(h->vihl != (IP_VER|IP_HLEN)) { | |
| 247 | + print("ip bad vers/hlen\n"); | |
| 248 | + continue; | |
| 249 | + } | |
| 250 | + | |
| 251 | + if(h->udpproto != IP_UDPPROTO) | |
| 252 | + continue; | |
| 253 | + | |
| 254 | + h->ttl = 0; | |
| 255 | + len = nhgets(h->udplen); | |
| 256 | + hnputs(h->udpplen, len); | |
| 257 | + | |
| 258 | + if(CHECKSUM && nhgets(h->udpcksum)) { | |
| 259 | + csm = ptcl_csum(&h->ttl, len+UDP_PHDRSIZE); | |
| 260 | + if(csm != 0) { | |
| 261 | + print("udp chksum error csum #%4lux len %d\n", csm, n); | |
| 262 | + break; | |
| 263 | + } | |
| 264 | + } | |
| 265 | + | |
| 266 | + if(a->port != 0 && nhgets(h->udpsport) != a->port) | |
| 267 | + continue; | |
| 268 | + | |
| 269 | + addr = nhgetl(h->udpsrc); | |
| 270 | + if(a->ip != Bcastip && addr != a->ip) | |
| 271 | + continue; | |
| 272 | + | |
| 273 | + len -= UDP_HDRSIZE-UDP_PHDRSIZE; | |
| 274 | + if(len > dlen) { | |
| 275 | + print("udp: packet too big\n"); | |
| 276 | + continue; | |
| 277 | + } | |
| 278 | + | |
| 279 | + memmove(data, h->udpcksum+sizeof(h->udpcksum), len); | |
| 280 | + a->ip = addr; | |
| 281 | + a->port = nhgets(h->udpsport); | |
| 282 | + memmove(a->ea, pkt.s, sizeof(a->ea)); | |
| 283 | + | |
| 284 | + rxactive = 1; | |
| 285 | + return len; | |
| 286 | + } | |
| 287 | + | |
| 288 | + return 0; | |
| 289 | +} | |
| 290 | + | |
| 291 | +static int tftpblockno; | |
| 292 | + | |
| 293 | +static int | |
| 294 | +tftpopen(int ctlrno, Netaddr *a, char *name, Tftp *tftp) | |
| 295 | +{ | |
| 296 | + int i, len, rlen, oport; | |
| 297 | + char buf[Segsize+2]; | |
| 298 | + | |
| 299 | + buf[0] = 0; | |
| 300 | + buf[1] = Tftp_READ; | |
| 301 | + len = sprint(buf+2, "%s", name) + 2; | |
| 302 | + len += sprint(buf+len+1, "octet") + 2; | |
| 303 | + | |
| 304 | + oport = a->port; | |
| 305 | + for(i = 0; i < 5; i++){ | |
| 306 | + a->port = oport; | |
| 307 | + udpsend(ctlrno, a, buf, len); | |
| 308 | + a->port = 0; | |
| 309 | + if((rlen = udprecv(ctlrno, a, tftp, sizeof(Tftp))) < sizeof(tftp->header)) | |
| 310 | + continue; | |
| 311 | + | |
| 312 | + switch((tftp->header[0]<<8)|tftp->header[1]){ | |
| 313 | + | |
| 314 | + case Tftp_ERROR: | |
| 315 | + print("tftpopen: error (%d): %s\n", | |
| 316 | + (tftp->header[2]<<8)|tftp->header[3], tftp->data); | |
| 317 | + return -1; | |
| 318 | + | |
| 319 | + case Tftp_DATA: | |
| 320 | + tftpblockno = 1; | |
| 321 | + len = (tftp->header[2]<<8)|tftp->header[3]; | |
| 322 | + if(len != tftpblockno){ | |
| 323 | + print("tftpopen: block error: %d\n", len); | |
| 324 | + nak(ctlrno, a, 1, "block error", 0); | |
| 325 | + return -1; | |
| 326 | + } | |
| 327 | + return rlen-sizeof(tftp->header); | |
| 328 | + } | |
| 329 | + } | |
| 330 | + | |
| 331 | + print("tftpopen: failed to connect to server\n"); | |
| 332 | + return -1; | |
| 333 | +} | |
| 334 | + | |
| 335 | +static int | |
| 336 | +tftpread(int ctlrno, Netaddr *a, Tftp *tftp, int dlen) | |
| 337 | +{ | |
| 338 | + int blockno, len, retry; | |
| 339 | + uchar buf[4]; | |
| 340 | + | |
| 341 | + buf[0] = 0; | |
| 342 | + buf[1] = Tftp_ACK; | |
| 343 | + buf[2] = tftpblockno>>8; | |
| 344 | + buf[3] = tftpblockno; | |
| 345 | + tftpblockno++; | |
| 346 | + | |
| 347 | + dlen += sizeof(tftp->header); | |
| 348 | + | |
| 349 | + retry = 0; | |
| 350 | +buggery: | |
| 351 | + udpsend(ctlrno, a, buf, sizeof(buf)); | |
| 352 | + | |
| 353 | + if((len = udprecv(ctlrno, a, tftp, dlen)) < dlen){ | |
| 354 | + print("tftpread: %d != %d\n", len, dlen); | |
| 355 | + nak(ctlrno, a, 2, "short read", 0); | |
| 356 | + if(retry++ < 5) | |
| 357 | + goto buggery; | |
| 358 | + return -1; | |
| 359 | + } | |
| 360 | + | |
| 361 | + blockno = (tftp->header[2]<<8)|tftp->header[3]; | |
| 362 | + if(blockno != tftpblockno){ | |
| 363 | + print("?"); | |
| 364 | + | |
| 365 | + if(blockno == tftpblockno-1 && retry++ < 8) | |
| 366 | + goto buggery; | |
| 367 | + print("tftpread: block error: %d, expected %d\n", blockno, tftpblockno); | |
| 368 | + nak(ctlrno, a, 1, "block error", 0); | |
| 369 | + | |
| 370 | + return -1; | |
| 371 | + } | |
| 372 | + | |
| 373 | + return len-sizeof(tftp->header); | |
| 374 | +} | |
| 375 | + | |
| 376 | +int | |
| 377 | +bootp(int ctlrno, char *file) | |
| 378 | +{ | |
| 379 | + Bootp req, rep; | |
| 380 | + int i, dlen, segsize, text, data, bss, total; | |
| 381 | + uchar *ea, *addr, *p; | |
| 382 | + ulong entry; | |
| 383 | + Exec *exec; | |
| 384 | + char name[128], *filename, *sysname; | |
| 385 | + | |
| 386 | + if((ea = etheraddr(ctlrno)) == 0){ | |
| 387 | + print("invalid ctlrno %d\n", ctlrno); | |
| 388 | + return -1; | |
| 389 | + } | |
| 390 | + | |
| 391 | + filename = 0; | |
| 392 | + sysname = 0; | |
| 393 | + if(file && *file){ | |
| 394 | + strcpy(name, file); | |
| 395 | + if(filename = strchr(name, ':')){ | |
| 396 | + if(filename != name && *(filename-1) != '\\'){ | |
| 397 | + sysname = name; | |
| 398 | + *filename++ = 0; | |
| 399 | + } | |
| 400 | + } | |
| 401 | + else | |
| 402 | + filename = name; | |
| 403 | + } | |
| 404 | + | |
| 405 | + | |
| 406 | + memset(&req, 0, sizeof(req)); | |
| 407 | + req.op = Bootrequest; | |
| 408 | + req.htype = 1; /* ethernet */ | |
| 409 | + req.hlen = Eaddrlen; /* ethernet */ | |
| 410 | + memmove(req.chaddr, ea, Eaddrlen); | |
| 411 | + | |
| 412 | + myaddr.ip = 0; | |
| 413 | + myaddr.port = BPportsrc; | |
| 414 | + memmove(myaddr.ea, ea, Eaddrlen); | |
| 415 | + | |
| 416 | + for(i = 0; i < 10; i++) { | |
| 417 | + server.ip = Bcastip; | |
| 418 | + server.port = BPportdst; | |
| 419 | + memmove(server.ea, broadcast, sizeof(server.ea)); | |
| 420 | + udpsend(ctlrno, &server, &req, sizeof(req)); | |
| 421 | + if(udprecv(ctlrno, &server, &rep, sizeof(rep)) <= 0) | |
| 422 | + continue; | |
| 423 | + if(memcmp(req.chaddr, rep.chaddr, Eaddrlen)) | |
| 424 | + continue; | |
| 425 | + if(rep.htype != 1 || rep.hlen != Eaddrlen) | |
| 426 | + continue; | |
| 427 | + if(sysname == 0 || strcmp(sysname, rep.sname) == 0) | |
| 428 | + break; | |
| 429 | + } | |
| 430 | + if(i >= 10) { | |
| 431 | + print("bootp timed out\n"); | |
| 432 | + return -1; | |
| 433 | + } | |
| 434 | + | |
| 435 | + if(filename == 0 || *filename == 0) | |
| 436 | + filename = rep.file; | |
| 437 | + | |
| 438 | + if(rep.sname[0] != '\0') | |
| 439 | + print("%s ", rep.sname); | |
| 440 | + print("(%d.%d.%d.%d!%d): %s\n", | |
| 441 | + rep.siaddr[0], | |
| 442 | + rep.siaddr[1], | |
| 443 | + rep.siaddr[2], | |
| 444 | + rep.siaddr[3], | |
| 445 | + server.port, | |
| 446 | + filename);uartwait(); | |
| 447 | + | |
| 448 | + myaddr.ip = nhgetl(rep.yiaddr); | |
| 449 | + myaddr.port = tftpport++; | |
| 450 | + server.ip = nhgetl(rep.siaddr); | |
| 451 | + server.port = TFTPport; | |
| 452 | + | |
| 453 | + if((dlen = tftpopen(ctlrno, &server, filename, &tftpb)) < 0) | |
| 454 | + return -1; | |
| 455 | + exec = (Exec*)(tftpb.data); | |
| 456 | + if(dlen < sizeof(Exec) || GLLONG(exec->magic) != Q_MAGIC){ | |
| 457 | + nak(ctlrno, &server, 0, "bad magic number", 1); | |
| 458 | + return -1; | |
| 459 | + } | |
| 460 | + text = GLLONG(exec->text); | |
| 461 | + data = GLLONG(exec->data); | |
| 462 | + bss = GLLONG(exec->bss); | |
| 463 | + total = text+data+bss; | |
| 464 | + entry = GLLONG(exec->entry); | |
| 465 | +print("load@%8.8lux: ", PADDR(entry));uartwait(); | |
| 466 | + print("%d", text); | |
| 467 | + | |
| 468 | + addr = (uchar*)PADDR(entry); | |
| 469 | + p = tftpb.data+sizeof(Exec); | |
| 470 | + dlen -= sizeof(Exec); | |
| 471 | + segsize = text; | |
| 472 | + for(;;){ | |
| 473 | + if(dlen == 0){ | |
| 474 | + if((dlen = tftpread(ctlrno, &server, &tftpb, sizeof(tftpb.data))) < 0) | |
| 475 | + return -1; | |
| 476 | + p = tftpb.data; | |
| 477 | + } | |
| 478 | + if(segsize <= dlen) | |
| 479 | + i = segsize; | |
| 480 | + else | |
| 481 | + i = dlen; | |
| 482 | + memmove(addr, p, i); | |
| 483 | + | |
| 484 | + addr += i; | |
| 485 | + p += i; | |
| 486 | + segsize -= i; | |
| 487 | + dlen -= i; | |
| 488 | + | |
| 489 | + if(segsize <= 0){ | |
| 490 | + if(data == 0) | |
| 491 | + break; | |
| 492 | + print("+%d", data); | |
| 493 | + segsize = data; | |
| 494 | + data = 0; | |
| 495 | + addr = (uchar*)PGROUND((ulong)addr); | |
| 496 | + } | |
| 497 | + } | |
| 498 | + nak(ctlrno, &server, 3, "ok", 0); /* tftpclose */ | |
| 499 | + print("+%d=%d\n", bss, total); | |
| 500 | + print("entry: 0x%lux\n", entry); | |
| 501 | + uartwait(); | |
| 502 | + scc2stop(); | |
| 503 | + splhi(); | |
| 504 | + (*(void(*)(void))(PADDR(entry)))(); | |
| 505 | + | |
| 506 | + return 0; | |
| 507 | +} | |
| @@ -0,0 +1,71 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | +#include "ureg.h" | |
| 8 | + | |
| 9 | +enum { | |
| 10 | + Timebase = 4, /* system clock cycles per time base cycle */ | |
| 11 | +}; | |
| 12 | + | |
| 13 | +void (*archclocktick)(void); /* set by arch*.c when desired */ | |
| 14 | + | |
| 15 | +static ulong clkreload; | |
| 16 | + | |
| 17 | +void | |
| 18 | +delay(int l) | |
| 19 | +{ | |
| 20 | + ulong i, j; | |
| 21 | + | |
| 22 | + j = m->delayloop; | |
| 23 | + while(l-- > 0) | |
| 24 | + for(i=0; i < j; i++) | |
| 25 | + ; | |
| 26 | +} | |
| 27 | + | |
| 28 | +void | |
| 29 | +microdelay(int l) | |
| 30 | +{ | |
| 31 | + ulong i; | |
| 32 | + | |
| 33 | + l *= m->delayloop; | |
| 34 | + l /= 1000; | |
| 35 | + if(l <= 0) | |
| 36 | + l = 1; | |
| 37 | + for(i = 0; i < l; i++) | |
| 38 | + ; | |
| 39 | +} | |
| 40 | + | |
| 41 | +void | |
| 42 | +clockintr(Ureg*, void*) | |
| 43 | +{ | |
| 44 | + putdec(clkreload); | |
| 45 | + m->ticks++; | |
| 46 | + checkalarms(); | |
| 47 | + if(archclocktick != nil) | |
| 48 | + archclocktick(); | |
| 49 | +} | |
| 50 | + | |
| 51 | +void | |
| 52 | +clockinit(void) | |
| 53 | +{ | |
| 54 | + long x; | |
| 55 | + | |
| 56 | + m->delayloop = m->cpuhz/1000; /* initial estimate */ | |
| 57 | + do { | |
| 58 | + x = gettbl(); | |
| 59 | + delay(10); | |
| 60 | + x = gettbl() - x; | |
| 61 | + } while(x < 0); | |
| 62 | + | |
| 63 | + /* | |
| 64 | + * fix count | |
| 65 | + */ | |
| 66 | + m->delayloop = ((vlong)m->delayloop*(10*m->clockgen/1000))/(x*Timebase); | |
| 67 | + if(m->delayloop == 0) | |
| 68 | + m->delayloop = 1; | |
| 69 | + clkreload = (m->clockgen/Timebase)/HZ-1; | |
| 70 | + putdec(clkreload); | |
| 71 | +} | |
| @@ -0,0 +1,173 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +#include "dosfs.h" | |
| 9 | + | |
| 10 | +static char *confname[MAXCONF]; | |
| 11 | +static char *confval[MAXCONF]; | |
| 12 | +static int nconf; | |
| 13 | + | |
| 14 | +extern char **ini; | |
| 15 | + | |
| 16 | +char* | |
| 17 | +getconf(char *name) | |
| 18 | +{ | |
| 19 | + int i; | |
| 20 | + | |
| 21 | + for(i = 0; i < nconf; i++) | |
| 22 | + if(strcmp(confname[i], name) == 0) | |
| 23 | + return confval[i]; | |
| 24 | + return 0; | |
| 25 | +} | |
| 26 | + | |
| 27 | +/* | |
| 28 | + * read configuration file | |
| 29 | + */ | |
| 30 | +int | |
| 31 | +plan9ini(Dos *dos, char *val) | |
| 32 | +{ | |
| 33 | + Dosfile rc; | |
| 34 | + int i, n; | |
| 35 | + char *cp, *p, *q, *line[MAXCONF]; | |
| 36 | + | |
| 37 | + cp = BOOTARGS; | |
| 38 | + if(dos) { | |
| 39 | + if(dosstat(dos, *ini, &rc) <= 0) | |
| 40 | + return -1; | |
| 41 | + | |
| 42 | + *cp = 0; | |
| 43 | + n = dosread(&rc, cp, BOOTARGSLEN-1); | |
| 44 | + if(n <= 0) | |
| 45 | + return -1; | |
| 46 | + cp[n] = 0; | |
| 47 | + } else if(val != nil){ | |
| 48 | + if(memchr(val, 0, BOOTARGSLEN-1) == nil) | |
| 49 | + return -1; | |
| 50 | + print("Using flash configuration\n"); | |
| 51 | + strcpy(cp, val); | |
| 52 | + n = strlen(cp); | |
| 53 | + }else{ | |
| 54 | + strcpy(cp, archconfig()); | |
| 55 | + n = strlen(cp); | |
| 56 | + } | |
| 57 | + | |
| 58 | + /* | |
| 59 | + * Make a working copy. | |
| 60 | + * We could change this to pass the parsed strings | |
| 61 | + * to the booted programme instead of the raw | |
| 62 | + * string, then it only gets done once. | |
| 63 | + */ | |
| 64 | + memmove(cp+BOOTARGSLEN, cp, n+1); | |
| 65 | + cp += BOOTARGSLEN; | |
| 66 | + | |
| 67 | + /* | |
| 68 | + * Strip out '\r', change '\t' -> ' '. | |
| 69 | + */ | |
| 70 | + p = cp; | |
| 71 | + for(q = cp; *q; q++){ | |
| 72 | + if(*q == '\r') | |
| 73 | + continue; | |
| 74 | + if(*q == '\t') | |
| 75 | + *q = ' '; | |
| 76 | + *p++ = *q; | |
| 77 | + } | |
| 78 | + *p = 0; | |
| 79 | + n = getcfields(cp, line, MAXCONF, "\n"); | |
| 80 | + for(i = 0; i < n; i++){ | |
| 81 | + cp = strchr(line[i], '='); | |
| 82 | + if(cp == 0) | |
| 83 | + continue; | |
| 84 | + *cp++ = 0; | |
| 85 | + if(cp - line[i] >= NAMELEN+1) | |
| 86 | + *(line[i]+NAMELEN-1) = 0; | |
| 87 | + confname[nconf] = line[i]; | |
| 88 | + confval[nconf] = cp; | |
| 89 | + nconf++; | |
| 90 | + } | |
| 91 | + return 0; | |
| 92 | +} | |
| 93 | + | |
| 94 | +int | |
| 95 | +parseether(uchar *to, char *from) | |
| 96 | +{ | |
| 97 | + char nip[4]; | |
| 98 | + char *p; | |
| 99 | + int i; | |
| 100 | + | |
| 101 | + p = from; | |
| 102 | + while(*p == ' ') | |
| 103 | + ++p; | |
| 104 | + for(i = 0; i < 6; i++){ | |
| 105 | + if(*p == 0) | |
| 106 | + return -1; | |
| 107 | + nip[0] = *p++; | |
| 108 | + if(*p == 0) | |
| 109 | + return -1; | |
| 110 | + nip[1] = *p++; | |
| 111 | + nip[2] = 0; | |
| 112 | + to[i] = strtoul(nip, 0, 16); | |
| 113 | + if(*p == ':') | |
| 114 | + p++; | |
| 115 | + } | |
| 116 | + return 0; | |
| 117 | +} | |
| 118 | + | |
| 119 | +int | |
| 120 | +isaconfig(char *class, int ctlrno, ISAConf *isa) | |
| 121 | +{ | |
| 122 | + char cc[NAMELEN], *p, *q, *r; | |
| 123 | + int n; | |
| 124 | + | |
| 125 | + sprint(cc, "%s%d", class, ctlrno); | |
| 126 | + for(n = 0; n < nconf; n++){ | |
| 127 | + if(strncmp(confname[n], cc, NAMELEN)) | |
| 128 | + continue; | |
| 129 | + isa->nopt = 0; | |
| 130 | + p = confval[n]; | |
| 131 | + while(*p){ | |
| 132 | + while(*p == ' ' || *p == '\t') | |
| 133 | + p++; | |
| 134 | + if(*p == '\0') | |
| 135 | + break; | |
| 136 | + if(strncmp(p, "type=", 5) == 0){ | |
| 137 | + p += 5; | |
| 138 | + for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){ | |
| 139 | + if(*p == '\0' || *p == ' ' || *p == '\t') | |
| 140 | + break; | |
| 141 | + *q = *p++; | |
| 142 | + } | |
| 143 | + *q = '\0'; | |
| 144 | + } | |
| 145 | + else if(strncmp(p, "port=", 5) == 0) | |
| 146 | + isa->port = strtoul(p+5, &p, 0); | |
| 147 | + else if(strncmp(p, "irq=", 4) == 0) | |
| 148 | + isa->irq = strtoul(p+4, &p, 0); | |
| 149 | + else if(strncmp(p, "mem=", 4) == 0) | |
| 150 | + isa->mem = strtoul(p+4, &p, 0); | |
| 151 | + else if(strncmp(p, "size=", 5) == 0) | |
| 152 | + isa->size = strtoul(p+5, &p, 0); | |
| 153 | + else if(strncmp(p, "ea=", 3) == 0){ | |
| 154 | + if(parseether(isa->ea, p+3) == -1) | |
| 155 | + memset(isa->ea, 0, 6); | |
| 156 | + } | |
| 157 | + else if(isa->nopt < NISAOPT){ | |
| 158 | + r = isa->opt[isa->nopt]; | |
| 159 | + while(*p && *p != ' ' && *p != '\t'){ | |
| 160 | + *r++ = *p++; | |
| 161 | + if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1) | |
| 162 | + break; | |
| 163 | + } | |
| 164 | + *r = '\0'; | |
| 165 | + isa->nopt++; | |
| 166 | + } | |
| 167 | + while(*p && *p != ' ' && *p != '\t') | |
| 168 | + p++; | |
| 169 | + } | |
| 170 | + return 1; | |
| 171 | + } | |
| 172 | + return 0; | |
| 173 | +} | |
| @@ -0,0 +1,173 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +static Queue* consiq; | |
| 9 | +static Queue* consoq; | |
| 10 | + | |
| 11 | +void | |
| 12 | +bothputs(char *s, int n) | |
| 13 | +{ | |
| 14 | + uartputs(s, n); | |
| 15 | + screenputs(s, n); | |
| 16 | +} | |
| 17 | + | |
| 18 | +static void (*consputs)(char*, int) = bothputs; /* or screenputs */ | |
| 19 | + | |
| 20 | +void | |
| 21 | +consinit(void) | |
| 22 | +{ | |
| 23 | + char *p; | |
| 24 | + int baud, port; | |
| 25 | + static int cgadone; | |
| 26 | + | |
| 27 | + p = getconf("console"); | |
| 28 | + if(0) | |
| 29 | + if(p == 0 || strcmp(p, "lcd") == 0 || strcmp(p, "screen") == 0){ | |
| 30 | + consiq = qopen(4*1024, 0, 0, 0); | |
| 31 | + consoq = qopen(8*1024, 0, 0, 0); | |
| 32 | + consputs = screenputs; | |
| 33 | + return; | |
| 34 | + } | |
| 35 | + if(p!=0 && strstr(p, "lcd") == 0) | |
| 36 | + consputs = bothputs; | |
| 37 | + else | |
| 38 | + consputs = uartputs; | |
| 39 | +//consputs = screenputs; | |
| 40 | + port = 0; | |
| 41 | + if(p) | |
| 42 | + port = strtoul(p, 0, 0); | |
| 43 | + baud = 0; | |
| 44 | + if(p = getconf("baud")) | |
| 45 | + baud = strtoul(p, 0, 0); | |
| 46 | + if(baud == 0) | |
| 47 | + baud = 9600; | |
| 48 | + uartspecial(port, baud, &consiq, &consoq, kbdchar); | |
| 49 | +} | |
| 50 | + | |
| 51 | +void | |
| 52 | +kbdchar(Queue *q, int c) | |
| 53 | +{ | |
| 54 | + c &= 0x7F; | |
| 55 | + if(c == 0x10) | |
| 56 | + panic("^p"); | |
| 57 | + qbputc(q, c); | |
| 58 | +} | |
| 59 | + | |
| 60 | +static int | |
| 61 | +getline(char *buf, int size, int dotimeout) | |
| 62 | +{ | |
| 63 | + int c, i=0; | |
| 64 | + ulong start; | |
| 65 | + char echo; | |
| 66 | + | |
| 67 | + for (;;) { | |
| 68 | + start = m->ticks; | |
| 69 | + do{ | |
| 70 | + if(dotimeout && ((m->ticks - start) > 5*HZ)) | |
| 71 | + return -2; | |
| 72 | + c = qbgetc(consiq); | |
| 73 | + }while(c == -1); | |
| 74 | + if(c == '\r') | |
| 75 | + c = '\n'; /* turn carriage return into newline */ | |
| 76 | + if(c == '\177') | |
| 77 | + c = '\010'; /* turn delete into backspace */ | |
| 78 | + if(c == '\025') | |
| 79 | + echo = '\n'; /* echo ^U as a newline */ | |
| 80 | + else | |
| 81 | + echo = c; | |
| 82 | + (*consputs)(&echo, 1); | |
| 83 | + | |
| 84 | + if(c == '\010'){ | |
| 85 | + if(i > 0) | |
| 86 | + i--; /* bs deletes last character */ | |
| 87 | + continue; | |
| 88 | + } | |
| 89 | + /* a newline ends a line */ | |
| 90 | + if (c == '\n') | |
| 91 | + break; | |
| 92 | + /* ^U wipes out the line */ | |
| 93 | + if (c =='\025') | |
| 94 | + return -1; | |
| 95 | + if(i == size) | |
| 96 | + return size; | |
| 97 | + buf[i++] = c; | |
| 98 | + } | |
| 99 | + buf[i] = 0; | |
| 100 | + return i; | |
| 101 | +} | |
| 102 | + | |
| 103 | +int | |
| 104 | +getstr(char *prompt, char *buf, int size, char *def) | |
| 105 | +{ | |
| 106 | + int len, isdefault; | |
| 107 | + | |
| 108 | + buf[0] = 0; | |
| 109 | + isdefault = (def && *def); | |
| 110 | + for (;;) { | |
| 111 | + if(isdefault) | |
| 112 | + print("%s[default==%s]: ", prompt, def); | |
| 113 | + else | |
| 114 | + print("%s: ", prompt); | |
| 115 | + len = getline(buf, size, isdefault); | |
| 116 | + switch(len){ | |
| 117 | + case -1: | |
| 118 | + /* ^U typed */ | |
| 119 | + continue; | |
| 120 | + case -2: | |
| 121 | + /* timeout, use default */ | |
| 122 | + (*consputs)("\n", 1); | |
| 123 | + len = 0; | |
| 124 | + break; | |
| 125 | + default: | |
| 126 | + break; | |
| 127 | + } | |
| 128 | + if(len >= size){ | |
| 129 | + print("line too long\n"); | |
| 130 | + continue; | |
| 131 | + } | |
| 132 | + break; | |
| 133 | + } | |
| 134 | + if(len == 0 && isdefault) | |
| 135 | + strcpy(buf, def); | |
| 136 | + return 0; | |
| 137 | +} | |
| 138 | + | |
| 139 | +int | |
| 140 | +sprint(char *s, char *fmt, ...) | |
| 141 | +{ | |
| 142 | + return donprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s; | |
| 143 | +} | |
| 144 | + | |
| 145 | +int | |
| 146 | +print(char *fmt, ...) | |
| 147 | +{ | |
| 148 | + char buf[PRINTSIZE]; | |
| 149 | + int n; | |
| 150 | + | |
| 151 | + if(consputs == 0) | |
| 152 | + return 0; | |
| 153 | + n = donprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; | |
| 154 | + (*consputs)(buf, n); | |
| 155 | + return n; | |
| 156 | +} | |
| 157 | + | |
| 158 | +void | |
| 159 | +panic(char *fmt, ...) | |
| 160 | +{ | |
| 161 | + char buf[PRINTSIZE]; | |
| 162 | + int n; | |
| 163 | + | |
| 164 | + if(consputs){ | |
| 165 | + (*consputs)("panic: ", 7); | |
| 166 | + n = donprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; | |
| 167 | + (*consputs)(buf, n); | |
| 168 | + (*consputs)("\n", 1); | |
| 169 | + } | |
| 170 | + spllo(); | |
| 171 | + for(;;) | |
| 172 | + idle(); | |
| 173 | +} | |
| @@ -0,0 +1,162 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +enum { | |
| 9 | + BDSIZE= 1024, /* TO DO: check this */ | |
| 10 | +}; | |
| 11 | + | |
| 12 | +static Map bdmapv[BDSIZE/sizeof(BD)]; | |
| 13 | +static RMap bdmap = {"buffer descriptors"}; | |
| 14 | + | |
| 15 | +void | |
| 16 | +cpminit(void) | |
| 17 | +{ | |
| 18 | + IMM *io; | |
| 19 | + | |
| 20 | + io = m->iomem; | |
| 21 | + io->sdcr = 1; | |
| 22 | + io->lccr &= ~1; /* disable LCD */ | |
| 23 | + io->pcint = 0; /* disable all port C interrupts */ | |
| 24 | + io->pcso = 0; | |
| 25 | + io->pcdir =0; | |
| 26 | + io->pcpar = 0; | |
| 27 | + io->pcdat = 0; | |
| 28 | + io->papar = 0; | |
| 29 | + io->padir = 0; | |
| 30 | + io->paodr = 0; | |
| 31 | + io->padat = 0; | |
| 32 | + io->pbpar = 0; | |
| 33 | + io->pbdir = 0; | |
| 34 | + io->pbodr = 0; | |
| 35 | + io->pbdat = 0; | |
| 36 | + eieio(); | |
| 37 | + | |
| 38 | + for(io->cpcr = 0x8001; io->cpcr & 1;) /* reset all CPM channels */ | |
| 39 | + eieio(); | |
| 40 | + | |
| 41 | + mapinit(&bdmap, bdmapv, sizeof(bdmapv)); | |
| 42 | + mapfree(&bdmap, DPBASE, BDSIZE); | |
| 43 | +} | |
| 44 | + | |
| 45 | +void | |
| 46 | +cpmop(int op, int cno, int param) | |
| 47 | +{ | |
| 48 | + IMM *io; | |
| 49 | + int s; | |
| 50 | + | |
| 51 | + s = splhi(); | |
| 52 | + io = m->iomem; | |
| 53 | + eieio(); | |
| 54 | + while(io->cpcr & 1) | |
| 55 | + eieio(); | |
| 56 | + io->cpcr = (op<<8)|(cno<<4)|(param<<1)|1; | |
| 57 | + eieio(); | |
| 58 | + while(io->cpcr & 1) | |
| 59 | + eieio(); | |
| 60 | + splx(s); | |
| 61 | +} | |
| 62 | + | |
| 63 | +/* | |
| 64 | + * connect SCCx clocks in NSMI mode (x=1 for USB) | |
| 65 | + */ | |
| 66 | +void | |
| 67 | +sccnmsi(int x, int rcs, int tcs) | |
| 68 | +{ | |
| 69 | + IMM *io; | |
| 70 | + ulong v; | |
| 71 | + int sh; | |
| 72 | + | |
| 73 | + sh = (x-1)*8; /* each SCCx field in sicr is 8 bits */ | |
| 74 | + v = (((rcs&7)<<3) | (tcs&7)) << sh; | |
| 75 | + io = ioplock(); | |
| 76 | + io->sicr = (io->sicr & ~(0xFF<<sh)) | v; | |
| 77 | + iopunlock(); | |
| 78 | +} | |
| 79 | + | |
| 80 | +void | |
| 81 | +scc2stop(void) | |
| 82 | +{ | |
| 83 | + SCC *scc; | |
| 84 | + | |
| 85 | + scc = IOREGS(0xA20, SCC); | |
| 86 | + if(scc->gsmrl & (3<<4)){ | |
| 87 | + cpmop(GracefulStopTx, SCC2ID, 0); | |
| 88 | + cpmop(CloseRxBD, SCC2ID, 0); | |
| 89 | + delay(1); | |
| 90 | + scc->gsmrl &= ~(3<<4); /* disable current use */ | |
| 91 | + archetherdisable(SCC2ID); | |
| 92 | + } | |
| 93 | +} | |
| 94 | + | |
| 95 | +BD * | |
| 96 | +bdalloc(int n) | |
| 97 | +{ | |
| 98 | + ulong a; | |
| 99 | + | |
| 100 | + a = mapalloc(&bdmap, 0, n*sizeof(BD), 0); | |
| 101 | + if(a == 0) | |
| 102 | + panic("bdalloc"); | |
| 103 | + return KADDR(a); | |
| 104 | +} | |
| 105 | + | |
| 106 | +void | |
| 107 | +bdfree(BD *b, int n) | |
| 108 | +{ | |
| 109 | + if(b){ | |
| 110 | + eieio(); | |
| 111 | + mapfree(&bdmap, PADDR(b), n*sizeof(BD)); | |
| 112 | + } | |
| 113 | +} | |
| 114 | + | |
| 115 | +/* | |
| 116 | + * initialise receive and transmit buffer rings. | |
| 117 | + */ | |
| 118 | +int | |
| 119 | +ioringinit(Ring* r, int nrdre, int ntdre, int bufsize) | |
| 120 | +{ | |
| 121 | + int i, x; | |
| 122 | + | |
| 123 | + /* the ring entries must be aligned on sizeof(BD) boundaries */ | |
| 124 | + r->nrdre = nrdre; | |
| 125 | + if(r->rdr == nil) | |
| 126 | + r->rdr = bdalloc(nrdre); | |
| 127 | + /* the buffer size must align with cache lines since the cache doesn't snoop */ | |
| 128 | + bufsize = (bufsize+CACHELINESZ-1)&~(CACHELINESZ-1); | |
| 129 | + if(r->rrb == nil) | |
| 130 | + r->rrb = malloc(nrdre*bufsize); | |
| 131 | + if(r->rdr == nil || r->rrb == nil) | |
| 132 | + return -1; | |
| 133 | + dcflush(r->rrb, nrdre*bufsize); | |
| 134 | + x = PADDR(r->rrb); | |
| 135 | + for(i = 0; i < nrdre; i++){ | |
| 136 | + r->rdr[i].length = 0; | |
| 137 | + r->rdr[i].addr = x; | |
| 138 | + r->rdr[i].status = BDEmpty|BDInt; | |
| 139 | + x += bufsize; | |
| 140 | + } | |
| 141 | + r->rdr[i-1].status |= BDWrap; | |
| 142 | + r->rdrx = 0; | |
| 143 | + | |
| 144 | + r->ntdre = ntdre; | |
| 145 | + if(r->tdr == nil) | |
| 146 | + r->tdr = bdalloc(ntdre); | |
| 147 | + if(r->txb == nil) | |
| 148 | + r->txb = malloc(ntdre*sizeof(Block*)); | |
| 149 | + if(r->tdr == nil || r->txb == nil) | |
| 150 | + return -1; | |
| 151 | + for(i = 0; i < ntdre; i++){ | |
| 152 | + r->txb[i] = nil; | |
| 153 | + r->tdr[i].addr = 0; | |
| 154 | + r->tdr[i].length = 0; | |
| 155 | + r->tdr[i].status = 0; | |
| 156 | + } | |
| 157 | + r->tdr[i-1].status |= BDWrap; | |
| 158 | + r->tdrh = 0; | |
| 159 | + r->tdri = 0; | |
| 160 | + r->ntq = 0; | |
| 161 | + return 0; | |
| 162 | +} | |
| @@ -0,0 +1,42 @@ | ||
| 1 | +#include "boot.h" | |
| 2 | + | |
| 3 | +/* | |
| 4 | + * from Rob Warnock | |
| 5 | + */ | |
| 6 | +static ulong crc32tab[256]; /* initialised on first call to crc32 */ | |
| 7 | + | |
| 8 | +enum { | |
| 9 | + CRC32POLY = 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */ | |
| 10 | +}; | |
| 11 | + | |
| 12 | +/* | |
| 13 | + * Build auxiliary table for parallel byte-at-a-time CRC-32. | |
| 14 | + */ | |
| 15 | +static void | |
| 16 | +initcrc32(void) | |
| 17 | +{ | |
| 18 | + int i, j; | |
| 19 | + ulong c; | |
| 20 | + | |
| 21 | + for(i = 0; i < 256; i++) { | |
| 22 | + for(c = i << 24, j = 8; j > 0; j--) | |
| 23 | + if(c & (1<<31)) | |
| 24 | + c = (c<<1) ^ CRC32POLY; | |
| 25 | + else | |
| 26 | + c <<= 1; | |
| 27 | + crc32tab[i] = c; | |
| 28 | + } | |
| 29 | +} | |
| 30 | + | |
| 31 | +ulong | |
| 32 | +crc32(void *buf, int n, ulong crc) | |
| 33 | +{ | |
| 34 | + uchar *p; | |
| 35 | + | |
| 36 | + if(crc32tab[1] == 0) | |
| 37 | + initcrc32(); | |
| 38 | + crc = ~crc; | |
| 39 | + for(p = buf; --n >= 0;) | |
| 40 | + crc = (crc << 8) ^ crc32tab[(crc >> 24) ^ *p++]; | |
| 41 | + return ~crc; | |
| 42 | +} | |
| @@ -0,0 +1,217 @@ | ||
| 1 | +typedef struct Alarm Alarm; | |
| 2 | +typedef struct Block Block; | |
| 3 | +typedef struct IMM IMM; | |
| 4 | +typedef struct Queue Queue; | |
| 5 | + | |
| 6 | +typedef struct List { | |
| 7 | + void *next; | |
| 8 | +} List; | |
| 9 | + | |
| 10 | +typedef struct { | |
| 11 | + int fake; | |
| 12 | + int pri; | |
| 13 | +} Lock; | |
| 14 | +#define lock(x) | |
| 15 | +#define unlock(x) | |
| 16 | + | |
| 17 | +struct Alarm { | |
| 18 | + List; | |
| 19 | + int busy; | |
| 20 | + long dt; | |
| 21 | + void (*f)(Alarm*); | |
| 22 | + void *arg; | |
| 23 | +}; | |
| 24 | + | |
| 25 | +enum { | |
| 26 | + Eaddrlen = 6, | |
| 27 | + ETHERMINTU = 60, /* minimum transmit size */ | |
| 28 | + ETHERMAXTU = 1514, /* maximum transmit size */ | |
| 29 | + ETHERHDRSIZE = 14, /* size of an ethernet header */ | |
| 30 | + | |
| 31 | + MaxEther = 4, | |
| 32 | +}; | |
| 33 | + | |
| 34 | +typedef struct { | |
| 35 | + uchar d[Eaddrlen]; | |
| 36 | + uchar s[Eaddrlen]; | |
| 37 | + uchar type[2]; | |
| 38 | + uchar data[1500]; | |
| 39 | + uchar crc[4]; | |
| 40 | +} Etherpkt; | |
| 41 | + | |
| 42 | +extern uchar broadcast[Eaddrlen]; | |
| 43 | + | |
| 44 | +enum { | |
| 45 | + Npart = 20+2, /* 8 sub partitions, disk, and partition */ | |
| 46 | + Maxxfer = 16*1024, /* maximum transfer size/cmd */ | |
| 47 | +}; | |
| 48 | + | |
| 49 | +typedef struct { | |
| 50 | + ulong start; | |
| 51 | + ulong end; | |
| 52 | + char name[NAMELEN+1]; | |
| 53 | +} Partition; | |
| 54 | + | |
| 55 | +typedef struct { | |
| 56 | + int online; | |
| 57 | + int npart; /* number of real partitions */ | |
| 58 | + Partition p[Npart]; | |
| 59 | + ulong offset; | |
| 60 | + Partition *current; /* current partition */ | |
| 61 | + | |
| 62 | + ulong cap; /* total bytes */ | |
| 63 | + int bytes; /* bytes/sector */ | |
| 64 | + int sectors; /* sectors/track */ | |
| 65 | + int heads; /* heads/cyl */ | |
| 66 | + long cyl; /* cylinders/drive */ | |
| 67 | + | |
| 68 | + char lba; /* true if drive has logical block addressing */ | |
| 69 | + char multi; /* non-zero if drive does multiple block xfers */ | |
| 70 | +} Disc; | |
| 71 | + | |
| 72 | +enum { | |
| 73 | + ScsiTestunit = 0x00, | |
| 74 | + ScsiExtsens = 0x03, | |
| 75 | + ScsiInquiry = 0x12, | |
| 76 | + ScsiModesense = 0x1a, | |
| 77 | + ScsiStartunit = 0x1B, | |
| 78 | + ScsiStopunit = 0x1B, | |
| 79 | + ScsiGetcap = 0x25, | |
| 80 | + ScsiRead = 0x08, | |
| 81 | + ScsiWrite = 0x0a, | |
| 82 | + ScsiExtread = 0x28, | |
| 83 | + ScsiExtwrite = 0x2a, | |
| 84 | + | |
| 85 | + /* data direction */ | |
| 86 | + ScsiIn = 1, | |
| 87 | + ScsiOut = 0, | |
| 88 | +}; | |
| 89 | + | |
| 90 | +typedef struct Scsibuf Scsibuf; | |
| 91 | +typedef struct Scsibuf { | |
| 92 | + void* virt; | |
| 93 | + void* phys; | |
| 94 | + Scsibuf* next; | |
| 95 | +}; | |
| 96 | + | |
| 97 | +typedef struct Scsidata { | |
| 98 | + uchar* base; | |
| 99 | + uchar* lim; | |
| 100 | + uchar* ptr; | |
| 101 | +} Scsidata; | |
| 102 | + | |
| 103 | +typedef struct Ureg Ureg; | |
| 104 | + | |
| 105 | +typedef struct Scsi { | |
| 106 | + ulong pid; | |
| 107 | + ushort target; | |
| 108 | + ushort lun; | |
| 109 | + ushort rflag; | |
| 110 | + ushort status; | |
| 111 | + Scsidata cmd; | |
| 112 | + Scsidata data; | |
| 113 | + Scsibuf* b; | |
| 114 | + uchar* save; | |
| 115 | + uchar cmdblk[16]; | |
| 116 | +} Scsi; | |
| 117 | + | |
| 118 | +typedef struct Segdesc { | |
| 119 | + ulong d0; | |
| 120 | + ulong d1; | |
| 121 | +} Segdesc; | |
| 122 | + | |
| 123 | +typedef struct Mach { | |
| 124 | + ulong ticks; /* of the clock since boot time */ | |
| 125 | + ulong delayloop; | |
| 126 | + long cpuhz; /* general system clock (cycles) */ | |
| 127 | + long clockgen; /* clock generator frequency (cycles) */ | |
| 128 | + ulong cpupvr; /* cpu type in processor version register */ | |
| 129 | + ulong cputype; /* cpu variant in BCD (eg, 0x823xx) */ | |
| 130 | + void* alarm; /* alarms bound to this clock */ | |
| 131 | + ulong* bcsr; | |
| 132 | + IMM* iomem; | |
| 133 | +} Mach; | |
| 134 | + | |
| 135 | +/* Mach.cputype */ | |
| 136 | +#define MPCREV(x) ((x) & 0xFF) | |
| 137 | +#define MPCMODEL(x) (((x)>>8) & 0xFFF) | |
| 138 | +#define MPCFAMILY(x) (((x)>>24) & 0x0F) | |
| 139 | + | |
| 140 | + | |
| 141 | +extern Mach *m; | |
| 142 | + | |
| 143 | +#define Q_MAGIC ((((4*21)+0)*21)+7) | |
| 144 | + | |
| 145 | +typedef struct Exec Exec; | |
| 146 | +struct Exec | |
| 147 | +{ | |
| 148 | + uchar magic[4]; /* magic number */ | |
| 149 | + uchar text[4]; /* size of text segment */ | |
| 150 | + uchar data[4]; /* size of initialized data */ | |
| 151 | + uchar bss[4]; /* size of uninitialized data */ | |
| 152 | + uchar syms[4]; /* size of symbol table */ | |
| 153 | + uchar entry[4]; /* entry point */ | |
| 154 | + uchar spsz[4]; /* size of sp/pc offset table */ | |
| 155 | + uchar pcsz[4]; /* size of pc/line number table */ | |
| 156 | +}; | |
| 157 | + | |
| 158 | +/* | |
| 159 | + * bootline passed by boot program | |
| 160 | + */ | |
| 161 | +#define BOOTLINE ((char *)0x200000-150) | |
| 162 | + | |
| 163 | +/* | |
| 164 | + * Where we leave configuration info. | |
| 165 | + */ | |
| 166 | +#define BOOTARGS ((char*)(0x200000)) | |
| 167 | +#define BOOTARGSLEN 1024 | |
| 168 | +#define MAXCONF 32 | |
| 169 | + | |
| 170 | +/* | |
| 171 | + * a parsed plan9.ini line | |
| 172 | + */ | |
| 173 | +#define ISAOPTLEN 16 | |
| 174 | +#define NISAOPT 8 | |
| 175 | + | |
| 176 | +typedef struct ISAConf { | |
| 177 | + char type[NAMELEN]; | |
| 178 | + ulong port; | |
| 179 | + ulong irq; | |
| 180 | + ulong mem; | |
| 181 | + ulong size; | |
| 182 | + uchar ea[6]; | |
| 183 | + | |
| 184 | + int nopt; | |
| 185 | + char opt[NISAOPT][ISAOPTLEN]; | |
| 186 | +} ISAConf; | |
| 187 | + | |
| 188 | +typedef struct { | |
| 189 | + int size; | |
| 190 | + ulong addr; | |
| 191 | +} Map; | |
| 192 | + | |
| 193 | +typedef struct { | |
| 194 | + char* name; | |
| 195 | + Map* map; | |
| 196 | + Map* mapend; | |
| 197 | + | |
| 198 | + Lock; | |
| 199 | +} RMap; | |
| 200 | + | |
| 201 | +typedef struct PCIcfg PCIcfg; | |
| 202 | + | |
| 203 | +extern uchar* vgamem; | |
| 204 | + | |
| 205 | +struct Block { | |
| 206 | + uchar *rp; | |
| 207 | + uchar *wp; | |
| 208 | + uchar *lim; | |
| 209 | + uchar *data; | |
| 210 | + Block* next; | |
| 211 | + ulong magic; | |
| 212 | +}; | |
| 213 | +#define BLEN(b) ((b)->wp-(b)->rp) | |
| 214 | + | |
| 215 | +typedef struct QLock { | |
| 216 | + int dummy; | |
| 217 | +} QLock; | |
| @@ -0,0 +1,216 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <libg.h> | |
| 4 | +#include <gnot.h> | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | +static ulong bits0[] = { | |
| 9 | + 0x907070f0, 0xf0f07000, 0xf0888888, 0xf8707070, 0xe0e0e0e0, 0xe09070f0, 0x70f870f0, 0xf870f088, | |
| 10 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
| 11 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
| 12 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000e0, | |
| 13 | + 0xd0808080, 0x80808800, 0x8888c888, 0x80888888, 0x90909090, 0x90d08080, 0x80808080, 0x80888888, | |
| 14 | + 0x00000000, 0x08000000, 0x0c300000, 0x00000006, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
| 15 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000003c, 0xc03c0000, | |
| 16 | + 0x00006000, 0x06001e00, 0x60181860, 0x78000000, 0x00000000, 0x00000000, 0x0000001c, 0x18380090, | |
| 17 | + 0xb06060e0, 0xe0e0f800, 0xf088a888, 0x80808080, 0x90909090, 0x90b060e0, 0x808060e0, 0x80808888, | |
| 18 | + 0x00182428, 0x3e707018, 0x18180000, 0x00000006, 0x3c183c3c, 0x1c3e3c7e, 0x3c3c0000, 0x0200403c, | |
| 19 | + 0x3c187c1e, 0x787e7e1e, 0x663c7c66, 0x6066623c, 0x7c3c7c3c, 0x7e6266c2, 0x66667e30, 0xc00c1000, | |
| 20 | + 0x08006000, 0x06003000, 0x60181860, 0x18000000, 0x00000000, 0x10000000, 0x00000030, 0x180c0090, | |
| 21 | + 0x90101080, 0x80808818, 0x88f8a888, 0xe0807070, 0xe0e0e0e0, 0xe0901080, 0x70e01080, 0xe098f088, | |
| 22 | + 0x00182428, 0x6adad818, 0x18181000, 0x0000000c, 0x66386666, 0x2c3e667e, 0x66660000, 0x06006066, | |
| 23 | + 0x42186632, 0x6c606032, 0x66181864, 0x60667224, 0x66246666, 0x186262da, 0x62620630, 0x600c3800, | |
| 24 | + 0x10006000, 0x06003000, 0x60000060, 0x18000000, 0x00000000, 0x30000000, 0x00000030, 0x180c00e0, | |
| 25 | + 0x00e0e0f0, 0xf0f00018, 0x88889850, 0x80880808, 0x201c1c1c, 0x1c00e0f0, 0x0080e0f0, 0x80888888, | |
| 26 | + 0x00182428, 0x68dad808, 0x300c5418, 0x0000000c, 0x66580606, 0x2c206002, 0x66661818, 0x0cfe3006, | |
| 27 | + 0x9e2c6660, 0x66606060, 0x6618186c, 0x60667266, 0x66666660, 0x186262da, 0x36660c30, 0x600c2800, | |
| 28 | + 0x103c6c3c, 0x3e3c7e3e, 0x6c787866, 0x18d46c3c, 0x6c3e763c, 0x7e6666c2, 0x66667e18, 0x18180000, | |
| 29 | + 0x44180000, 0x18241c24, 0xf0888820, 0x8070f0f0, 0x20202020, 0x201c243e, 0x1cf8241c, 0x80708870, | |
| 30 | + 0x0018247c, 0x78745008, 0x300c3818, 0x00000018, 0x66180606, 0x4c206006, 0x76661818, 0x18fe180c, | |
| 31 | + 0xb62c6660, 0x66606060, 0x66181868, 0x607e5a66, 0x66666470, 0x186266da, 0x34340c30, 0x300c6c00, | |
| 32 | + 0x18667666, 0x66663066, 0x76181864, 0x18fe7666, 0x76663666, 0x306662da, 0x62620608, 0x1810323c, | |
| 33 | + 0x44247c7c, 0x24342042, 0x00000000, 0x00000000, 0x20202020, 0x20222408, 0x22002420, 0x00000000, | |
| 34 | + 0x00180028, 0x3c287610, 0x300cee7e, 0x00fe0018, 0x66180c18, 0x4c3c7c0c, 0x3c3e0000, 0x30000c18, | |
| 35 | + 0xb62c7c60, 0x667c7c6e, 0x7e181878, 0x605a5a66, 0x6466783c, 0x186234da, 0x18341830, 0x300c4400, | |
| 36 | + 0x18066660, 0x66663066, 0x66181868, 0x18d66666, 0x66663860, 0x306662da, 0x34620c30, 0x180c5a20, | |
| 37 | + 0x44241010, 0x242c2042, 0x0e3e103e, 0x3e3c1c3e, 0x3c1c1c1c, 0x1c3e1c08, 0x3e222418, 0x0e0e0e0e, | |
| 38 | + 0x0008007c, 0x1e5cdc00, 0x300c387e, 0x00fe0030, 0x66181806, 0x7e066618, 0x6e060000, 0x18001818, | |
| 39 | + 0xb67e6660, 0x66606066, 0x6618186c, 0x605a4e66, 0x78666c0e, 0x1862346c, 0x2c183030, 0x180c4400, | |
| 40 | + 0x003e6660, 0x667e3066, 0x66181878, 0x18d66666, 0x6666303c, 0x306634da, 0x18341808, 0x18104c38, | |
| 41 | + 0x3c181010, 0x18241c42, 0x11081008, 0x20222208, 0x00000000, 0x00220408, 0x22361804, 0x11111111, | |
| 42 | + 0x00000028, 0x16b6cc00, 0x300c5418, 0x00000030, 0x66183006, 0x7e066618, 0x66060000, 0x0cfe3000, | |
| 43 | + 0x9a466660, 0x66606066, 0x6618186c, 0x605a4e66, 0x60666606, 0x1862346c, 0x6c183030, 0x180c0000, | |
| 44 | + 0x00666660, 0x66603066, 0x6618186c, 0x18d66666, 0x66663006, 0x3066346c, 0x2c343018, 0x18180020, | |
| 45 | + 0x00091010, 0x000e0942, 0x10081008, 0x20222208, 0x0f06060f, 0x0a09041e, 0x002a0e38, 0x10101010, | |
| 46 | + 0x00180028, 0x56b6cc00, 0x300c1018, 0x18001860, 0x66187e66, 0x0c666630, 0x66661818, 0x06fe6018, | |
| 47 | + 0x40466632, 0x6c606036, 0x66181866, 0x605a4624, 0x60246666, 0x1834186c, 0x46186030, 0x0c0c0000, | |
| 48 | + 0x006e6666, 0x6e66306e, 0x66181866, 0x18d66666, 0x666e3066, 0x306e186c, 0x46186030, 0x180c003c, | |
| 49 | + 0x08090909, 0x1f110aff, 0x0e081008, 0x382c2208, 0x08020901, 0x0a0a0911, 0x09220907, 0x0e0e0e0e, | |
| 50 | + 0x00180028, 0x7c1c7600, 0x18180000, 0x18001860, 0x3c7e7e3c, 0x0c3c3c30, 0x3c3c1818, 0x02004018, | |
| 51 | + 0x3e467c1e, 0x787e601e, 0x663c1866, 0x7e42463c, 0x603c663c, 0x1818186c, 0x66187e30, 0x0c0c0000, | |
| 52 | + 0x00367c3c, 0x363c7c36, 0x667e1866, 0x7ed6663c, 0x7c367c3c, 0x1e36186c, 0x66187e30, 0x180c0008, | |
| 53 | + 0x080f0606, 0x04110c18, 0x01081008, 0x20222208, 0x0e020203, 0x0a0c0d1e, 0x0d220e08, 0x01010101, | |
| 54 | + 0x00000000, 0x10000000, 0x18180000, 0x080000c0, 0x00000000, 0x00000000, 0x00000008, 0x00000000, | |
| 55 | + 0x00000000, 0x00000000, 0x00001800, 0x00000000, 0x000c0000, 0x00000000, 0x00000030, 0x060c00fe, | |
| 56 | + 0x00000000, 0x00000006, 0x00001800, 0x00000000, 0x60060000, 0x00000000, 0x0010001c, 0x18380008, | |
| 57 | + 0x08090606, 0x040e0a18, 0x11081f08, 0x20221c3e, 0x08020401, 0x0f0a0b11, 0x0b220908, 0x11111111, | |
| 58 | + 0x00000000, 0x00000000, 0x0c300000, 0x080000c0, 0x00000000, 0x00000000, 0x00000008, 0x00000000, | |
| 59 | + 0x00000000, 0x00000000, 0x00007000, 0x00000000, 0x00060000, 0x00000000, 0x0000003c, 0x063c0000, | |
| 60 | + 0x00000000, 0x00000066, 0x00001800, 0x00000000, 0x60060000, 0x00000000, 0x00300000, 0x00000008, | |
| 61 | + 0x0f090909, 0x04030900, 0x0e000000, 0x00000000, 0x0f0f0f0f, 0x0209091e, 0x09000f07, 0x0e0e0e0e, | |
| 62 | + 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x00000000, 0x00000000, 0x00000010, 0x00000000, | |
| 63 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
| 64 | + 0x00000000, 0x0000003c, 0x00007000, 0x00000000, 0x60060000, 0x00000000, 0x00600000, 0x0000000f, | |
| 65 | + | |
| 66 | +}; | |
| 67 | + | |
| 68 | +static GBitmap strike0 = { | |
| 69 | + bits0, | |
| 70 | + 0, | |
| 71 | + 32, | |
| 72 | + 0, | |
| 73 | + {0, 0, 1024, 14}, | |
| 74 | + {0, 0, 1024, 14}, | |
| 75 | +}; | |
| 76 | + | |
| 77 | +static Fontchar info0[] = { | |
| 78 | + { 0, 0, 14, 0, 8 }, | |
| 79 | + { 8, 0, 14, 0, 8 }, | |
| 80 | + { 16, 0, 14, 0, 8 }, | |
| 81 | + { 24, 0, 14, 0, 8 }, | |
| 82 | + { 32, 0, 14, 0, 8 }, | |
| 83 | + { 40, 0, 14, 0, 8 }, | |
| 84 | + { 48, 0, 14, 0, 8 }, | |
| 85 | + { 56, 0, 14, 0, 8 }, | |
| 86 | + { 64, 0, 14, 0, 8 }, | |
| 87 | + { 72, 0, 14, 0, 8 }, | |
| 88 | + { 80, 0, 14, 0, 8 }, | |
| 89 | + { 88, 0, 14, 0, 8 }, | |
| 90 | + { 96, 0, 14, 0, 8 }, | |
| 91 | + { 104, 0, 14, 0, 8 }, | |
| 92 | + { 112, 0, 14, 0, 8 }, | |
| 93 | + { 120, 0, 14, 0, 8 }, | |
| 94 | + { 128, 0, 14, 0, 8 }, | |
| 95 | + { 136, 0, 14, 0, 8 }, | |
| 96 | + { 144, 0, 14, 0, 8 }, | |
| 97 | + { 152, 0, 14, 0, 8 }, | |
| 98 | + { 160, 0, 14, 0, 8 }, | |
| 99 | + { 168, 0, 14, 0, 8 }, | |
| 100 | + { 176, 0, 14, 0, 8 }, | |
| 101 | + { 184, 0, 14, 0, 8 }, | |
| 102 | + { 192, 0, 14, 0, 8 }, | |
| 103 | + { 200, 0, 14, 0, 8 }, | |
| 104 | + { 208, 0, 14, 0, 8 }, | |
| 105 | + { 216, 0, 14, 0, 8 }, | |
| 106 | + { 224, 0, 14, 0, 8 }, | |
| 107 | + { 232, 0, 14, 0, 8 }, | |
| 108 | + { 240, 0, 14, 0, 8 }, | |
| 109 | + { 248, 0, 14, 0, 8 }, | |
| 110 | + { 256, 0, 0, 0, 8 }, | |
| 111 | + { 264, 2, 11, 0, 8 }, | |
| 112 | + { 272, 2, 6, 0, 8 }, | |
| 113 | + { 280, 2, 11, 0, 8 }, | |
| 114 | + { 288, 1, 12, 0, 8 }, | |
| 115 | + { 296, 2, 11, 0, 8 }, | |
| 116 | + { 304, 2, 11, 0, 8 }, | |
| 117 | + { 312, 2, 7, 0, 8 }, | |
| 118 | + { 320, 1, 13, 0, 8 }, | |
| 119 | + { 328, 1, 13, 0, 8 }, | |
| 120 | + { 336, 3, 10, 0, 8 }, | |
| 121 | + { 344, 4, 10, 0, 8 }, | |
| 122 | + { 352, 9, 14, 0, 8 }, | |
| 123 | + { 360, 6, 8, 0, 8 }, | |
| 124 | + { 368, 9, 11, 0, 8 }, | |
| 125 | + { 376, 1, 13, 0, 8 }, | |
| 126 | + { 384, 2, 11, 0, 8 }, | |
| 127 | + { 392, 2, 11, 0, 8 }, | |
| 128 | + { 400, 2, 11, 0, 8 }, | |
| 129 | + { 408, 2, 11, 0, 8 }, | |
| 130 | + { 416, 2, 11, 0, 8 }, | |
| 131 | + { 424, 2, 11, 0, 8 }, | |
| 132 | + { 432, 2, 11, 0, 8 }, | |
| 133 | + { 440, 2, 11, 0, 8 }, | |
| 134 | + { 448, 2, 11, 0, 8 }, | |
| 135 | + { 456, 2, 11, 0, 8 }, | |
| 136 | + { 464, 4, 11, 0, 8 }, | |
| 137 | + { 472, 4, 14, 0, 8 }, | |
| 138 | + { 480, 2, 11, 0, 8 }, | |
| 139 | + { 488, 4, 10, 0, 8 }, | |
| 140 | + { 496, 2, 11, 0, 8 }, | |
| 141 | + { 504, 2, 11, 0, 8 }, | |
| 142 | + { 512, 2, 11, 0, 8 }, | |
| 143 | + { 520, 2, 11, 0, 8 }, | |
| 144 | + { 528, 2, 11, 0, 8 }, | |
| 145 | + { 536, 2, 11, 0, 8 }, | |
| 146 | + { 544, 2, 11, 0, 8 }, | |
| 147 | + { 552, 2, 11, 0, 8 }, | |
| 148 | + { 560, 2, 11, 0, 8 }, | |
| 149 | + { 568, 2, 11, 0, 8 }, | |
| 150 | + { 576, 2, 11, 0, 8 }, | |
| 151 | + { 584, 2, 11, 0, 8 }, | |
| 152 | + { 592, 2, 13, 0, 8 }, | |
| 153 | + { 600, 2, 11, 0, 8 }, | |
| 154 | + { 608, 2, 11, 0, 8 }, | |
| 155 | + { 616, 2, 11, 0, 8 }, | |
| 156 | + { 624, 2, 11, 0, 8 }, | |
| 157 | + { 632, 2, 11, 0, 8 }, | |
| 158 | + { 640, 2, 11, 0, 8 }, | |
| 159 | + { 648, 2, 13, 0, 8 }, | |
| 160 | + { 656, 2, 11, 0, 8 }, | |
| 161 | + { 664, 2, 11, 0, 8 }, | |
| 162 | + { 672, 2, 11, 0, 8 }, | |
| 163 | + { 680, 2, 11, 0, 8 }, | |
| 164 | + { 688, 2, 11, 0, 8 }, | |
| 165 | + { 696, 2, 11, 0, 8 }, | |
| 166 | + { 704, 2, 11, 0, 8 }, | |
| 167 | + { 712, 2, 11, 0, 8 }, | |
| 168 | + { 720, 2, 11, 0, 8 }, | |
| 169 | + { 728, 1, 13, 0, 8 }, | |
| 170 | + { 736, 1, 13, 0, 8 }, | |
| 171 | + { 744, 1, 13, 0, 8 }, | |
| 172 | + { 752, 2, 8, 0, 8 }, | |
| 173 | + { 760, 11, 12, 0, 8 }, | |
| 174 | + { 768, 2, 7, 0, 8 }, | |
| 175 | + { 776, 4, 11, 0, 8 }, | |
| 176 | + { 784, 1, 11, 0, 8 }, | |
| 177 | + { 792, 4, 11, 0, 8 }, | |
| 178 | + { 800, 1, 11, 0, 8 }, | |
| 179 | + { 808, 4, 11, 0, 8 }, | |
| 180 | + { 816, 1, 11, 0, 8 }, | |
| 181 | + { 824, 4, 14, 0, 8 }, | |
| 182 | + { 832, 1, 11, 0, 8 }, | |
| 183 | + { 840, 1, 11, 0, 8 }, | |
| 184 | + { 848, 1, 14, 0, 8 }, | |
| 185 | + { 856, 1, 11, 0, 8 }, | |
| 186 | + { 864, 1, 11, 0, 8 }, | |
| 187 | + { 872, 4, 11, 0, 8 }, | |
| 188 | + { 880, 4, 11, 0, 8 }, | |
| 189 | + { 888, 4, 11, 0, 8 }, | |
| 190 | + { 896, 4, 14, 0, 8 }, | |
| 191 | + { 904, 4, 14, 0, 8 }, | |
| 192 | + { 912, 4, 11, 0, 8 }, | |
| 193 | + { 920, 4, 11, 0, 8 }, | |
| 194 | + { 928, 2, 11, 0, 8 }, | |
| 195 | + { 936, 4, 11, 0, 8 }, | |
| 196 | + { 944, 4, 11, 0, 8 }, | |
| 197 | + { 952, 4, 11, 0, 8 }, | |
| 198 | + { 960, 4, 11, 0, 8 }, | |
| 199 | + { 968, 4, 14, 0, 8 }, | |
| 200 | + { 976, 4, 11, 0, 8 }, | |
| 201 | + { 984, 1, 12, 0, 8 }, | |
| 202 | + { 992, 1, 12, 0, 8 }, | |
| 203 | + { 1000, 1, 12, 0, 8 }, | |
| 204 | + { 1008, 5, 8, 0, 8 }, | |
| 205 | + { 1016, 0, 14, 0, 8 }, | |
| 206 | + { 1024, 0, 14, 0, 8 }, | |
| 207 | + { 0, 0, 0, 0, 0 } | |
| 208 | +}; | |
| 209 | + | |
| 210 | +GSubfont defont0 = { | |
| 211 | + 129, | |
| 212 | + 14, | |
| 213 | + 2, | |
| 214 | + info0, | |
| 215 | + &strike0, | |
| 216 | +}; | |
| @@ -0,0 +1,157 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +#include "etherif.h" | |
| 9 | + | |
| 10 | +static Ctlr ether[MaxEther]; | |
| 11 | + | |
| 12 | +static struct { | |
| 13 | + char *type; | |
| 14 | + int (*reset)(Ctlr*); | |
| 15 | +} cards[] = { | |
| 16 | + { "SCC", sccethreset, }, | |
| 17 | + { "SCC2", sccethreset, }, | |
| 18 | + { 0, } | |
| 19 | +}; | |
| 20 | + | |
| 21 | +int | |
| 22 | +etherinit(void) | |
| 23 | +{ | |
| 24 | + Ctlr *ctlr; | |
| 25 | + int ctlrno, i, mask, n; | |
| 26 | + | |
| 27 | + mask = 0; | |
| 28 | + for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){ | |
| 29 | + ctlr = ðer[ctlrno]; | |
| 30 | + memset(ctlr, 0, sizeof(Ctlr)); | |
| 31 | + if(isaconfig("ether", ctlrno, &ctlr->card) == 0) | |
| 32 | + continue; | |
| 33 | + for(n = 0; cards[n].type; n++){ | |
| 34 | + if(strcmp(cards[n].type, ctlr->card.type)) | |
| 35 | + continue; | |
| 36 | + ctlr->ctlrno = ctlrno; | |
| 37 | + if((*cards[n].reset)(ctlr)) | |
| 38 | + break; | |
| 39 | + | |
| 40 | + ctlr->iq = qopen(16*1024, 1, 0, 0); | |
| 41 | + ctlr->oq = qopen(16*1024, 1, 0, 0); | |
| 42 | + | |
| 43 | + ctlr->present = 1; | |
| 44 | + mask |= 1<<ctlrno; | |
| 45 | + | |
| 46 | + print("ether%d: %s: port 0x%luX irq %d", | |
| 47 | + ctlr->ctlrno, ctlr->card.type, ctlr->card.port, ctlr->card.irq); | |
| 48 | + if(ctlr->card.mem) | |
| 49 | + print(" addr 0x%luX", PADDR(ctlr->card.mem)); | |
| 50 | + if(ctlr->card.size) | |
| 51 | + print(" size 0x%luX", ctlr->card.size); | |
| 52 | + print(":"); | |
| 53 | + for(i = 0; i < sizeof(ctlr->card.ea); i++) | |
| 54 | + print(" %2.2uX", ctlr->card.ea[i]); | |
| 55 | + print("\n"); uartwait(); | |
| 56 | + setvec(VectorPIC + ctlr->card.irq, ctlr->card.intr, ctlr); | |
| 57 | + break; | |
| 58 | + } | |
| 59 | + } | |
| 60 | + | |
| 61 | + return mask; | |
| 62 | +} | |
| 63 | + | |
| 64 | +static Ctlr* | |
| 65 | +attach(int ctlrno) | |
| 66 | +{ | |
| 67 | + Ctlr *ctlr; | |
| 68 | + | |
| 69 | + if(ctlrno >= MaxEther || ether[ctlrno].present == 0) | |
| 70 | + return 0; | |
| 71 | + | |
| 72 | + ctlr = ðer[ctlrno]; | |
| 73 | + if(ctlr->present == 1){ | |
| 74 | + ctlr->present = 2; | |
| 75 | + (*ctlr->card.attach)(ctlr); | |
| 76 | + } | |
| 77 | + | |
| 78 | + return ctlr; | |
| 79 | +} | |
| 80 | + | |
| 81 | +uchar* | |
| 82 | +etheraddr(int ctlrno) | |
| 83 | +{ | |
| 84 | + Ctlr *ctlr; | |
| 85 | + | |
| 86 | + if((ctlr = attach(ctlrno)) == 0) | |
| 87 | + return 0; | |
| 88 | + | |
| 89 | + return ctlr->card.ea; | |
| 90 | +} | |
| 91 | + | |
| 92 | +int | |
| 93 | +etherrxpkt(int ctlrno, Etherpkt *pkt, int timo) | |
| 94 | +{ | |
| 95 | + int n; | |
| 96 | + Ctlr *ctlr; | |
| 97 | + Block *b; | |
| 98 | + ulong start; | |
| 99 | + | |
| 100 | + if((ctlr = attach(ctlrno)) == 0) | |
| 101 | + return 0; | |
| 102 | + | |
| 103 | + start = m->ticks; | |
| 104 | + while((b = qget(ctlr->iq)) == 0){ | |
| 105 | + if(TK2MS(m->ticks - start) >= timo){ | |
| 106 | + /* | |
| 107 | + print("ether%d: rx timeout\n", ctlrno); | |
| 108 | + */ | |
| 109 | + return 0; | |
| 110 | + } | |
| 111 | + } | |
| 112 | + | |
| 113 | + n = BLEN(b); | |
| 114 | + memmove(pkt, b->rp, n); | |
| 115 | + freeb(b); | |
| 116 | + | |
| 117 | + return n; | |
| 118 | +} | |
| 119 | + | |
| 120 | +int | |
| 121 | +etheriq(Ctlr *ctlr, Block *b, int freebp) | |
| 122 | +{ | |
| 123 | + if(memcmp(((Etherpkt*)b->rp)->d, ctlr->card.ea, Eaddrlen) != 0 && | |
| 124 | + memcmp(((Etherpkt*)b->rp)->d, broadcast, Eaddrlen) != 0){ | |
| 125 | + if(freebp) | |
| 126 | + freeb(b); | |
| 127 | + return 0; | |
| 128 | + } | |
| 129 | + qbwrite(ctlr->iq, b); | |
| 130 | + return 1; | |
| 131 | +} | |
| 132 | + | |
| 133 | +int | |
| 134 | +ethertxpkt(int ctlrno, Etherpkt *pkt, int len, int) | |
| 135 | +{ | |
| 136 | + Ctlr *ctlr; | |
| 137 | + Block *b; | |
| 138 | + int s; | |
| 139 | + | |
| 140 | + if((ctlr = attach(ctlrno)) == 0) | |
| 141 | + return 0; | |
| 142 | + | |
| 143 | + if(qlen(ctlr->oq) > 16*1024){ | |
| 144 | + print("ether%d: tx queue full\n", ctlrno); | |
| 145 | + return 0; | |
| 146 | + } | |
| 147 | + b = iallocb(sizeof(Etherpkt)); | |
| 148 | + memmove(b->wp, pkt, len); | |
| 149 | + memmove(((Etherpkt*)b->wp)->s, ctlr->card.ea, Eaddrlen); | |
| 150 | + b->wp += len; | |
| 151 | + qbwrite(ctlr->oq, b); | |
| 152 | + s = splhi(); | |
| 153 | + (*ctlr->card.transmit)(ctlr); | |
| 154 | + splx(s); | |
| 155 | + | |
| 156 | + return 1; | |
| 157 | +} | |
| @@ -0,0 +1,230 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +/* | |
| 9 | + * SMC1 in UART mode | |
| 10 | + */ | |
| 11 | + | |
| 12 | +typedef struct Uartsmc Uartsmc; | |
| 13 | +struct Uartsmc { | |
| 14 | + IOCparam; | |
| 15 | + ushort maxidl; | |
| 16 | + ushort idlc; | |
| 17 | + ushort brkln; | |
| 18 | + ushort brkec; | |
| 19 | + ushort brkcr; | |
| 20 | + ushort rmask; | |
| 21 | +}; | |
| 22 | + | |
| 23 | +typedef struct Uart Uart; | |
| 24 | +struct Uart | |
| 25 | +{ | |
| 26 | + int port; | |
| 27 | + int setup; | |
| 28 | + uchar txbusy; | |
| 29 | + | |
| 30 | + Queue* iq; | |
| 31 | + Queue* oq; | |
| 32 | + void (*rx)(Queue*, int); | |
| 33 | + void (*boot)(uchar*, int); | |
| 34 | + | |
| 35 | + ulong frame; | |
| 36 | + ulong overrun; | |
| 37 | + uchar rxbuf[128]; | |
| 38 | + char txbuf[16]; | |
| 39 | + BD* rxb; | |
| 40 | + BD* txb; | |
| 41 | +}; | |
| 42 | + | |
| 43 | +Uart uart[1]; | |
| 44 | +int predawn = 1; | |
| 45 | + | |
| 46 | +static void uartintr(Ureg*, void*); | |
| 47 | +static void uartkick(void*); | |
| 48 | + | |
| 49 | +static int | |
| 50 | +baudgen(int baud) | |
| 51 | +{ | |
| 52 | + int d; | |
| 53 | + | |
| 54 | + d = ((m->cpuhz/baud)+8)>>4; | |
| 55 | + if(d >= (1<<12)) | |
| 56 | + return ((d+15)>>3)|1; | |
| 57 | + return d<<1; | |
| 58 | +} | |
| 59 | + | |
| 60 | +static void | |
| 61 | +smcsetup(Uart *up, int baud) | |
| 62 | +{ | |
| 63 | + IMM *io; | |
| 64 | + Uartsmc *p; | |
| 65 | + BD *bd; | |
| 66 | + SMC *smc; | |
| 67 | + | |
| 68 | + archenableuart(SMC1ID, 0); | |
| 69 | + io = m->iomem; | |
| 70 | + io->pbpar |= IBIT(24)|IBIT(25); /* enable SMC1 TX/RX */ | |
| 71 | + io->pbdir &= ~(IBIT(24)|IBIT(25)); | |
| 72 | + io->brgc1 = baudgen(baud) | BaudEnable; | |
| 73 | + io->simode &= ~0xF000; /* SMC1 to NMSI mode, Tx/Rx clocks are BRG1 */ | |
| 74 | + | |
| 75 | + bd = bdalloc(1); | |
| 76 | + p = (Uartsmc*)KADDR(SMC1P); | |
| 77 | + p->rbase = (ushort)bd; | |
| 78 | + up->rxb = bd; | |
| 79 | + bd->status = BDEmpty|BDWrap|BDInt; | |
| 80 | + bd->length = 0; | |
| 81 | + bd->addr = PADDR(up->rxbuf); | |
| 82 | + bd = bdalloc(1); | |
| 83 | + p->tbase = (ushort)bd; | |
| 84 | + up->txb = bd; | |
| 85 | + bd->status = BDWrap|BDInt; | |
| 86 | + bd->length = 0; | |
| 87 | + bd->addr = PADDR(up->txbuf); | |
| 88 | + | |
| 89 | + cpmop(InitRxTx, SMC1ID, 0); | |
| 90 | + | |
| 91 | + /* protocol parameters */ | |
| 92 | + p->rfcr = 0x18; | |
| 93 | + p->tfcr = 0x18; | |
| 94 | + p->mrblr = 1; | |
| 95 | + p->maxidl = 1; | |
| 96 | + p->brkln = 0; | |
| 97 | + p->brkec = 0; | |
| 98 | + p->brkcr = 1; | |
| 99 | + smc = IOREGS(0xA80, SMC); | |
| 100 | + smc->smce = 0xff; /* clear events */ | |
| 101 | + smc->smcm = 0x17; /* enable all possible interrupts */ | |
| 102 | + setvec(VectorCPIC+4, uartintr, up); | |
| 103 | + smc->smcmr = 0x4820; /* 8-bit mode, no parity, 1 stop bit, UART mode, ... */ | |
| 104 | + smc->smcmr |= 3; /* enable rx/tx */ | |
| 105 | +} | |
| 106 | + | |
| 107 | +static void | |
| 108 | +uartintr(Ureg*, void *arg) | |
| 109 | +{ | |
| 110 | + Uart *up; | |
| 111 | + int ch, i; | |
| 112 | + BD *bd; | |
| 113 | + SMC *smc; | |
| 114 | + Block *b; | |
| 115 | + | |
| 116 | + up = arg; | |
| 117 | + smc = IOREGS(0xA80, SMC); | |
| 118 | + smc->smce = 0xff; /* clear all events */ | |
| 119 | + if((bd = up->rxb) != nil && (bd->status & BDEmpty) == 0){ | |
| 120 | + if(up->iq != nil && bd->length > 0){ | |
| 121 | + if(up->boot != nil){ | |
| 122 | + up->boot(up->rxbuf, bd->length); | |
| 123 | + }else if(up->rx != nil){ | |
| 124 | + for(i=0; i<bd->length; i++){ | |
| 125 | + ch = up->rxbuf[i]; | |
| 126 | + up->rx(up->iq, ch); | |
| 127 | + } | |
| 128 | + }else{ | |
| 129 | + b = iallocb(bd->length); | |
| 130 | + memmove(b->wp, up->rxbuf, bd->length); | |
| 131 | + b->wp += bd->length; | |
| 132 | + qbwrite(up->iq, b); | |
| 133 | + } | |
| 134 | + } | |
| 135 | + bd->status |= BDEmpty|BDInt; | |
| 136 | + } else if((bd = up->txb) != nil && (bd->status & BDReady) == 0){ | |
| 137 | + ch = -1; | |
| 138 | + if(up->oq) | |
| 139 | + ch = qbgetc(up->oq); | |
| 140 | + if(ch != -1){ | |
| 141 | + up->txbuf[0] = ch; | |
| 142 | + bd->length = 1; | |
| 143 | + bd->status |= BDReady; | |
| 144 | + }else | |
| 145 | + up->txbusy = 0; | |
| 146 | + } | |
| 147 | + /* TO DO: modem status, errors, etc */ | |
| 148 | +} | |
| 149 | + | |
| 150 | +static void | |
| 151 | +uartkick(void *arg) | |
| 152 | +{ | |
| 153 | + Uart *up = arg; | |
| 154 | + int s, c, i; | |
| 155 | + | |
| 156 | + s = splhi(); | |
| 157 | + while(up->txbusy == 0 && (c = qbgetc(up->oq)) != -1){ | |
| 158 | + if(predawn){ | |
| 159 | + while(up->txb->status & BDReady) | |
| 160 | + ; | |
| 161 | + } else { | |
| 162 | + for(i = 0; i < 100; i++){ | |
| 163 | + if((up->txb->status & BDReady) == 0) | |
| 164 | + break; | |
| 165 | + delay(1); | |
| 166 | + } | |
| 167 | + } | |
| 168 | + up->txbuf[0] = c; | |
| 169 | + up->txb->length = 1; | |
| 170 | + up->txb->status |= BDReady; | |
| 171 | + up->txbusy = !predawn; | |
| 172 | + } | |
| 173 | + splx(s); | |
| 174 | +} | |
| 175 | + | |
| 176 | +void | |
| 177 | +uartspecial(int port, int baud, Queue **iq, Queue **oq, void (*rx)(Queue*,int)) | |
| 178 | +{ | |
| 179 | + Uart *up = &uart[0]; | |
| 180 | + | |
| 181 | + if(up->setup) | |
| 182 | + return; | |
| 183 | + up->setup = 1; | |
| 184 | + | |
| 185 | + *iq = up->iq = qopen(4*1024, 0, 0, 0); | |
| 186 | + *oq = up->oq = qopen(16*1024, 0, uartkick, up); | |
| 187 | + up->rx = rx; | |
| 188 | + USED(port); | |
| 189 | + up->port = SMC1ID; | |
| 190 | + if(baud == 0) | |
| 191 | + baud = 9600; | |
| 192 | + smcsetup(up, baud); | |
| 193 | + /* if using SCCn's UART, would also set DTR and RTS, but SMC doesn't use them */ | |
| 194 | +} | |
| 195 | + | |
| 196 | +void | |
| 197 | +uartsetboot(void (*f)(uchar*, int)) | |
| 198 | +{ | |
| 199 | + uart[0].boot = f; | |
| 200 | +} | |
| 201 | + | |
| 202 | +void | |
| 203 | +uartputs(char *s, int n) | |
| 204 | +{ | |
| 205 | + Uart *up = &uart[0]; | |
| 206 | + Block *b; | |
| 207 | + int nl; | |
| 208 | + char *p; | |
| 209 | + | |
| 210 | + nl = 0; | |
| 211 | + for(p = s; p < s+n; p++) | |
| 212 | + if(*p == '\n') | |
| 213 | + nl++; | |
| 214 | + b = iallocb(n+nl); | |
| 215 | + while(n--){ | |
| 216 | + if(*s == '\n') | |
| 217 | + *b->wp++ = '\r'; | |
| 218 | + *b->wp++ = *s++; | |
| 219 | + } | |
| 220 | + qbwrite(up->oq, b); | |
| 221 | +} | |
| 222 | + | |
| 223 | +void | |
| 224 | +uartwait(void) | |
| 225 | +{ | |
| 226 | + Uart *up = &uart[0]; | |
| 227 | + | |
| 228 | + while(up->txbusy) | |
| 229 | + ; | |
| 230 | +} | |
| @@ -0,0 +1,103 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <bio.h> | |
| 4 | +#include <mach.h> | |
| 5 | + | |
| 6 | +static char *kernelfile = "/power/ipaq"; | |
| 7 | +ulong crc32(void *buf, int n, ulong crc); | |
| 8 | + | |
| 9 | +void | |
| 10 | +main(int argc, char **argv) | |
| 11 | +{ | |
| 12 | + int ifd, n; | |
| 13 | + char buf[64], reply[1]; | |
| 14 | + int i, execsize; | |
| 15 | + Fhdr f; | |
| 16 | + ulong csum; | |
| 17 | + | |
| 18 | + ARGBEGIN{ | |
| 19 | + }ARGEND | |
| 20 | + ifd = open(kernelfile, OREAD); | |
| 21 | + if(ifd < 0){ | |
| 22 | + fprint(2, "dload: can't open %s: %r\n", kernelfile); | |
| 23 | + exits("open"); | |
| 24 | + } | |
| 25 | + i = 0; | |
| 26 | + if(crackhdr(ifd, &f) == 0){ | |
| 27 | + fprint(2, "dload: not an executable file: %r\n"); | |
| 28 | + exits("format"); | |
| 29 | + } | |
| 30 | + if(f.magic != Q_MAGIC){ | |
| 31 | + fprint(2, "dload: not a powerpc executable\n"); | |
| 32 | + exits("format"); | |
| 33 | + } | |
| 34 | + execsize = f.txtsz + f.datsz + f.txtoff; | |
| 35 | + seek(ifd, 0, 0); | |
| 36 | + csum = ~0; | |
| 37 | + while(execsize > 0 && (n = read(ifd, buf, sizeof(buf))) > 0){ | |
| 38 | + if(n > execsize) | |
| 39 | + n = execsize; | |
| 40 | + for(;;){ | |
| 41 | + if(write(1, buf, sizeof(buf)) != sizeof(buf)){ /* always writes full buffer */ | |
| 42 | + fprint(2, "dload: write error: %r\n"); | |
| 43 | + exits("write"); | |
| 44 | + } | |
| 45 | + if(read(0, reply, 1) != 1){ | |
| 46 | + fprint(2, "dload: bad reply\n"); | |
| 47 | + exits("read"); | |
| 48 | + } | |
| 49 | + if(reply[0] != 'n') | |
| 50 | + break; | |
| 51 | + fprint(2, "!"); | |
| 52 | + } | |
| 53 | + if(reply[0] != 'y'){ | |
| 54 | + fprint(2, "dload: bad ack: %c\n", reply[0]); | |
| 55 | + exits("reply"); | |
| 56 | + } | |
| 57 | + if(++i%10 == 0) | |
| 58 | + fprint(2, "."); | |
| 59 | + execsize -= n; | |
| 60 | + } | |
| 61 | + exits(0); | |
| 62 | +} | |
| 63 | + | |
| 64 | +/* | |
| 65 | + * from Rob Warnock | |
| 66 | + */ | |
| 67 | +static ulong crc32tab[256]; /* initialised on first call to crc32 */ | |
| 68 | + | |
| 69 | +enum { | |
| 70 | + CRC32POLY = 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */ | |
| 71 | +}; | |
| 72 | + | |
| 73 | +/* | |
| 74 | + * Build auxiliary table for parallel byte-at-a-time CRC-32. | |
| 75 | + */ | |
| 76 | +static void | |
| 77 | +initcrc32(void) | |
| 78 | +{ | |
| 79 | + int i, j; | |
| 80 | + ulong c; | |
| 81 | + | |
| 82 | + for(i = 0; i < 256; i++) { | |
| 83 | + for(c = i << 24, j = 8; j > 0; j--) | |
| 84 | + if(c & (1<<31)) | |
| 85 | + c = (c<<1) ^ CRC32POLY; | |
| 86 | + else | |
| 87 | + c <<= 1; | |
| 88 | + crc32tab[i] = c; | |
| 89 | + } | |
| 90 | +} | |
| 91 | + | |
| 92 | +ulong | |
| 93 | +crc32(void *buf, int n, ulong crc) | |
| 94 | +{ | |
| 95 | + uchar *p; | |
| 96 | + | |
| 97 | + if(crc32tab[1] == 0) | |
| 98 | + initcrc32(); | |
| 99 | + crc = ~crc; | |
| 100 | + for(p = buf; --n >= 0;) | |
| 101 | + crc = (crc << 8) ^ crc32tab[(crc >> 24) ^ *p++]; | |
| 102 | + return ~crc; | |
| 103 | +} | |
| @@ -0,0 +1,332 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | + | |
| 4 | +#define PTR sizeof(char*) | |
| 5 | +#define SHORT sizeof(int) | |
| 6 | +#define INT sizeof(int) | |
| 7 | +#define LONG sizeof(long) | |
| 8 | +#define IDIGIT 30 | |
| 9 | +#define MAXCON 30 | |
| 10 | + | |
| 11 | +#define FLONG (1<<0) | |
| 12 | +#define FSHORT (1<<1) | |
| 13 | +#define FUNSIGN (1<<2) | |
| 14 | + | |
| 15 | +typedef struct Op Op; | |
| 16 | +struct Op | |
| 17 | +{ | |
| 18 | + char *p; | |
| 19 | + char *ep; | |
| 20 | + void *argp; | |
| 21 | + int f1; | |
| 22 | + int f2; | |
| 23 | + int f3; | |
| 24 | +}; | |
| 25 | + | |
| 26 | +static int noconv(Op*); | |
| 27 | +static int cconv(Op*); | |
| 28 | +static int dconv(Op*); | |
| 29 | +static int hconv(Op*); | |
| 30 | +static int lconv(Op*); | |
| 31 | +static int oconv(Op*); | |
| 32 | +static int sconv(Op*); | |
| 33 | +static int uconv(Op*); | |
| 34 | +static int xconv(Op*); | |
| 35 | +static int Xconv(Op*); | |
| 36 | +static int percent(Op*); | |
| 37 | + | |
| 38 | +static | |
| 39 | +int (*fmtconv[MAXCON])(Op*) = | |
| 40 | +{ | |
| 41 | + noconv, | |
| 42 | + cconv, dconv, hconv, lconv, | |
| 43 | + oconv, sconv, uconv, xconv, | |
| 44 | + Xconv, percent, | |
| 45 | +}; | |
| 46 | +static | |
| 47 | +char fmtindex[128] = | |
| 48 | +{ | |
| 49 | + ['c'] 1, | |
| 50 | + ['d'] 2, | |
| 51 | + ['h'] 3, | |
| 52 | + ['l'] 4, | |
| 53 | + ['o'] 5, | |
| 54 | + ['s'] 6, | |
| 55 | + ['u'] 7, | |
| 56 | + ['x'] 8, | |
| 57 | + ['X'] 9, | |
| 58 | + ['%'] 10, | |
| 59 | +}; | |
| 60 | + | |
| 61 | +static int convcount = { 11 }; | |
| 62 | +static int ucase; | |
| 63 | + | |
| 64 | +static void | |
| 65 | +PUT(Op *o, int c) | |
| 66 | +{ | |
| 67 | + static int pos; | |
| 68 | + int opos; | |
| 69 | + | |
| 70 | + if(c == '\t'){ | |
| 71 | + opos = pos; | |
| 72 | + pos = (opos+8) & ~7; | |
| 73 | + while(opos++ < pos && o->p < o->ep) | |
| 74 | + *o->p++ = ' '; | |
| 75 | + return; | |
| 76 | + } | |
| 77 | + if(o->p < o->ep){ | |
| 78 | + *o->p++ = c; | |
| 79 | + pos++; | |
| 80 | + } | |
| 81 | + if(c == '\n') | |
| 82 | + pos = 0; | |
| 83 | +} | |
| 84 | + | |
| 85 | +int | |
| 86 | +fmtinstall(char c, int (*f)(Op*)) | |
| 87 | +{ | |
| 88 | + | |
| 89 | + c &= 0177; | |
| 90 | + if(fmtindex[c] == 0) { | |
| 91 | + if(convcount >= MAXCON) | |
| 92 | + return 1; | |
| 93 | + fmtindex[c] = convcount++; | |
| 94 | + } | |
| 95 | + fmtconv[fmtindex[c]] = f; | |
| 96 | + return 0; | |
| 97 | +} | |
| 98 | + | |
| 99 | +char* | |
| 100 | +donprint(char *p, char *ep, char *fmt, void *argp) | |
| 101 | +{ | |
| 102 | + int sf1, c; | |
| 103 | + Op o; | |
| 104 | + | |
| 105 | + o.p = p; | |
| 106 | + o.ep = ep; | |
| 107 | + o.argp = argp; | |
| 108 | + | |
| 109 | +loop: | |
| 110 | + c = *fmt++; | |
| 111 | + if(c != '%') { | |
| 112 | + if(c == 0) { | |
| 113 | + if(o.p < o.ep) | |
| 114 | + *o.p = 0; | |
| 115 | + return o.p; | |
| 116 | + } | |
| 117 | + PUT(&o, c); | |
| 118 | + goto loop; | |
| 119 | + } | |
| 120 | + o.f1 = 0; | |
| 121 | + o.f2 = -1; | |
| 122 | + o.f3 = 0; | |
| 123 | + c = *fmt++; | |
| 124 | + sf1 = 0; | |
| 125 | + if(c == '-') { | |
| 126 | + sf1 = 1; | |
| 127 | + c = *fmt++; | |
| 128 | + } | |
| 129 | + while(c >= '0' && c <= '9') { | |
| 130 | + o.f1 = o.f1*10 + c-'0'; | |
| 131 | + c = *fmt++; | |
| 132 | + } | |
| 133 | + if(sf1) | |
| 134 | + o.f1 = -o.f1; | |
| 135 | + if(c != '.') | |
| 136 | + goto l1; | |
| 137 | + c = *fmt++; | |
| 138 | + while(c >= '0' && c <= '9') { | |
| 139 | + if(o.f2 < 0) | |
| 140 | + o.f2 = 0; | |
| 141 | + o.f2 = o.f2*10 + c-'0'; | |
| 142 | + c = *fmt++; | |
| 143 | + } | |
| 144 | +l1: | |
| 145 | + if(c == 0) | |
| 146 | + fmt--; | |
| 147 | + c = (*fmtconv[fmtindex[c&0177]])(&o); | |
| 148 | + if(c < 0) { | |
| 149 | + o.f3 |= -c; | |
| 150 | + c = *fmt++; | |
| 151 | + goto l1; | |
| 152 | + } | |
| 153 | + o.argp = (char*)o.argp + c; | |
| 154 | + goto loop; | |
| 155 | +} | |
| 156 | + | |
| 157 | +void | |
| 158 | +strconv(char *o, Op *op, int f1, int f2) | |
| 159 | +{ | |
| 160 | + int n, c; | |
| 161 | + char *p; | |
| 162 | + | |
| 163 | + n = strlen(o); | |
| 164 | + if(f1 >= 0) | |
| 165 | + while(n < f1) { | |
| 166 | + PUT(op, ' '); | |
| 167 | + n++; | |
| 168 | + } | |
| 169 | + for(p=o; c = *p++;) | |
| 170 | + if(f2 != 0) { | |
| 171 | + PUT(op, c); | |
| 172 | + f2--; | |
| 173 | + } | |
| 174 | + if(f1 < 0) { | |
| 175 | + f1 = -f1; | |
| 176 | + while(n < f1) { | |
| 177 | + PUT(op, ' '); | |
| 178 | + n++; | |
| 179 | + } | |
| 180 | + } | |
| 181 | +} | |
| 182 | + | |
| 183 | +int | |
| 184 | +numbconv(Op *op, int base) | |
| 185 | +{ | |
| 186 | + char b[IDIGIT]; | |
| 187 | + int i, f, n, r; | |
| 188 | + long v; | |
| 189 | + short h; | |
| 190 | + | |
| 191 | + f = 0; | |
| 192 | + switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) { | |
| 193 | + case FLONG: | |
| 194 | + v = *(long*)op->argp; | |
| 195 | + r = LONG; | |
| 196 | + break; | |
| 197 | + | |
| 198 | + case FUNSIGN|FLONG: | |
| 199 | + v = *(ulong*)op->argp; | |
| 200 | + r = LONG; | |
| 201 | + break; | |
| 202 | + | |
| 203 | + case FSHORT: | |
| 204 | + h = *(int*)op->argp; | |
| 205 | + v = h; | |
| 206 | + r = SHORT; | |
| 207 | + break; | |
| 208 | + | |
| 209 | + case FUNSIGN|FSHORT: | |
| 210 | + h = *(int*)op->argp; | |
| 211 | + v = (ushort)h; | |
| 212 | + r = SHORT; | |
| 213 | + break; | |
| 214 | + | |
| 215 | + default: | |
| 216 | + v = *(int*)op->argp; | |
| 217 | + r = INT; | |
| 218 | + break; | |
| 219 | + | |
| 220 | + case FUNSIGN: | |
| 221 | + v = *(unsigned*)op->argp; | |
| 222 | + r = INT; | |
| 223 | + break; | |
| 224 | + } | |
| 225 | + if(!(op->f3 & FUNSIGN) && v < 0) { | |
| 226 | + v = -v; | |
| 227 | + f = 1; | |
| 228 | + } | |
| 229 | + b[IDIGIT-1] = 0; | |
| 230 | + for(i = IDIGIT-2;; i--) { | |
| 231 | + n = (ulong)v % base; | |
| 232 | + n += '0'; | |
| 233 | + if(n > '9'){ | |
| 234 | + n += 'a' - ('9'+1); | |
| 235 | + if(ucase) | |
| 236 | + n += 'A'-'a'; | |
| 237 | + } | |
| 238 | + b[i] = n; | |
| 239 | + if(i < 2) | |
| 240 | + break; | |
| 241 | + v = (ulong)v / base; | |
| 242 | + if(op->f2 >= 0 && i >= IDIGIT-op->f2) | |
| 243 | + continue; | |
| 244 | + if(v <= 0) | |
| 245 | + break; | |
| 246 | + } | |
| 247 | + if(f) | |
| 248 | + b[--i] = '-'; | |
| 249 | + strconv(b+i, op, op->f1, -1); | |
| 250 | + return r; | |
| 251 | +} | |
| 252 | + | |
| 253 | +static int | |
| 254 | +noconv(Op *op) | |
| 255 | +{ | |
| 256 | + | |
| 257 | + strconv("***", op, 0, -1); | |
| 258 | + return 0; | |
| 259 | +} | |
| 260 | + | |
| 261 | +static int | |
| 262 | +cconv(Op *op) | |
| 263 | +{ | |
| 264 | + char b[2]; | |
| 265 | + | |
| 266 | + b[0] = *(int*)op->argp; | |
| 267 | + b[1] = 0; | |
| 268 | + strconv(b, op, op->f1, -1); | |
| 269 | + return INT; | |
| 270 | +} | |
| 271 | + | |
| 272 | +static int | |
| 273 | +dconv(Op *op) | |
| 274 | +{ | |
| 275 | + return numbconv(op, 10); | |
| 276 | +} | |
| 277 | + | |
| 278 | +static int | |
| 279 | +hconv(Op*) | |
| 280 | +{ | |
| 281 | + return -FSHORT; | |
| 282 | +} | |
| 283 | + | |
| 284 | +static int | |
| 285 | +lconv(Op*) | |
| 286 | +{ | |
| 287 | + return -FLONG; | |
| 288 | +} | |
| 289 | + | |
| 290 | +static int | |
| 291 | +oconv(Op *op) | |
| 292 | +{ | |
| 293 | + return numbconv(op, 8); | |
| 294 | +} | |
| 295 | + | |
| 296 | +static int | |
| 297 | +sconv(Op *op) | |
| 298 | +{ | |
| 299 | + strconv(*(char**)op->argp, op, op->f1, op->f2); | |
| 300 | + return PTR; | |
| 301 | +} | |
| 302 | + | |
| 303 | +static int | |
| 304 | +uconv(Op*) | |
| 305 | +{ | |
| 306 | + return -FUNSIGN; | |
| 307 | +} | |
| 308 | + | |
| 309 | +static int | |
| 310 | +xconv(Op *op) | |
| 311 | +{ | |
| 312 | + return numbconv(op, 16); | |
| 313 | +} | |
| 314 | + | |
| 315 | +static int | |
| 316 | +Xconv(Op *op) | |
| 317 | +{ | |
| 318 | + int r; | |
| 319 | + | |
| 320 | + ucase = 1; | |
| 321 | + r = numbconv(op, 16); | |
| 322 | + ucase = 0; | |
| 323 | + return r; | |
| 324 | +} | |
| 325 | + | |
| 326 | +static int | |
| 327 | +percent(Op *op) | |
| 328 | +{ | |
| 329 | + | |
| 330 | + PUT(op, '%'); | |
| 331 | + return 0; | |
| 332 | +} | |
| @@ -0,0 +1,614 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "dosfs.h" | |
| 7 | + | |
| 8 | +extern char *premature; | |
| 9 | + | |
| 10 | +/* | |
| 11 | + * predeclared | |
| 12 | + */ | |
| 13 | +static void bootdump(Dosboot*); | |
| 14 | +static void setname(Dosfile*, char*); | |
| 15 | +long dosreadseg(Dosfile*, long, long); | |
| 16 | + | |
| 17 | +/* | |
| 18 | + * debugging | |
| 19 | + */ | |
| 20 | +#define chatty 1 | |
| 21 | +#define chat if(chatty)print | |
| 22 | + | |
| 23 | +/* | |
| 24 | + * block io buffers | |
| 25 | + */ | |
| 26 | +enum | |
| 27 | +{ | |
| 28 | + Nbio= 16, | |
| 29 | +}; | |
| 30 | +typedef struct Clustbuf Clustbuf; | |
| 31 | +struct Clustbuf | |
| 32 | +{ | |
| 33 | + int age; | |
| 34 | + long sector; | |
| 35 | + uchar *iobuf; | |
| 36 | + Dos *dos; | |
| 37 | + int size; | |
| 38 | +}; | |
| 39 | +Clustbuf bio[Nbio]; | |
| 40 | + | |
| 41 | +/* | |
| 42 | + * get an io block from an io buffer | |
| 43 | + */ | |
| 44 | +Clustbuf* | |
| 45 | +getclust(Dos *dos, long sector) | |
| 46 | +{ | |
| 47 | + Clustbuf *p, *oldest; | |
| 48 | + int size; | |
| 49 | + | |
| 50 | + chat("getclust @ %d\n", sector); | |
| 51 | + | |
| 52 | + /* | |
| 53 | + * if we have it, just return it | |
| 54 | + */ | |
| 55 | + for(p = bio; p < &bio[Nbio]; p++){ | |
| 56 | + if(sector == p->sector && dos == p->dos){ | |
| 57 | + p->age = m->ticks; | |
| 58 | + chat("getclust %d in cache\n", sector); | |
| 59 | + return p; | |
| 60 | + } | |
| 61 | + } | |
| 62 | + | |
| 63 | + /* | |
| 64 | + * otherwise, reuse the oldest entry | |
| 65 | + */ | |
| 66 | + oldest = bio; | |
| 67 | + for(p = &bio[1]; p < &bio[Nbio]; p++){ | |
| 68 | + if(p->age <= oldest->age) | |
| 69 | + oldest = p; | |
| 70 | + } | |
| 71 | + p = oldest; | |
| 72 | + | |
| 73 | + /* | |
| 74 | + * make sure the buffer is big enough | |
| 75 | + */ | |
| 76 | + size = dos->clustsize*dos->sectsize; | |
| 77 | + if(p->iobuf==0 || p->size < size) | |
| 78 | + p->iobuf = ialloc(size, 0); | |
| 79 | + p->size = size; | |
| 80 | + | |
| 81 | + /* | |
| 82 | + * read in the cluster | |
| 83 | + */ | |
| 84 | + chat("getclust addr %d\n", (sector+dos->start)*dos->sectsize); | |
| 85 | + if((*dos->seek)(dos->dev, (sector+dos->start)*dos->sectsize) < 0){ | |
| 86 | + chat("can't seek block\n"); | |
| 87 | + return 0; | |
| 88 | + } | |
| 89 | + if((*dos->read)(dos->dev, p->iobuf, size) != size){ | |
| 90 | + chat("can't read block\n"); | |
| 91 | + return 0; | |
| 92 | + } | |
| 93 | + | |
| 94 | + p->age = m->ticks; | |
| 95 | + p->dos = dos; | |
| 96 | + p->sector = sector; | |
| 97 | + chat("getclust %d read\n", sector); | |
| 98 | + return p; | |
| 99 | +} | |
| 100 | + | |
| 101 | +/* | |
| 102 | + * walk the fat one level ( n is a current cluster number ). | |
| 103 | + * return the new cluster number or -1 if no more. | |
| 104 | + */ | |
| 105 | +static long | |
| 106 | +fatwalk(Dos *dos, int n) | |
| 107 | +{ | |
| 108 | + ulong k, sect; | |
| 109 | + Clustbuf *p; | |
| 110 | + int o; | |
| 111 | + | |
| 112 | + chat("fatwalk %d\n", n); | |
| 113 | + | |
| 114 | + if(n < 2 || n >= dos->fatclusters) | |
| 115 | + return -1; | |
| 116 | + | |
| 117 | + switch(dos->fatbits){ | |
| 118 | + case 12: | |
| 119 | + k = (3*n)/2; break; | |
| 120 | + case 16: | |
| 121 | + k = 2*n; break; | |
| 122 | + default: | |
| 123 | + return -1; | |
| 124 | + } | |
| 125 | + if(k >= dos->fatsize*dos->sectsize) | |
| 126 | + panic("getfat"); | |
| 127 | + | |
| 128 | + sect = (k/(dos->sectsize*dos->clustsize))*dos->clustsize + dos->fataddr; | |
| 129 | + o = k%(dos->sectsize*dos->clustsize); | |
| 130 | + p = getclust(dos, sect); | |
| 131 | + k = p->iobuf[o++]; | |
| 132 | + if(o >= dos->sectsize*dos->clustsize){ | |
| 133 | + p = getclust(dos, sect+dos->clustsize); | |
| 134 | + o = 0; | |
| 135 | + } | |
| 136 | + k |= p->iobuf[o]<<8; | |
| 137 | + if(dos->fatbits == 12){ | |
| 138 | + if(n&1) | |
| 139 | + k >>= 4; | |
| 140 | + else | |
| 141 | + k &= 0xfff; | |
| 142 | + if(k >= 0xff8) | |
| 143 | + k |= 0xf000; | |
| 144 | + } | |
| 145 | + k = k < 0xfff8 ? k : -1; | |
| 146 | + chat("fatwalk %d -> %d\n", n, k); | |
| 147 | + return k; | |
| 148 | +} | |
| 149 | + | |
| 150 | +/* | |
| 151 | + * map a file's logical cluster address to a physical sector address | |
| 152 | + */ | |
| 153 | +static long | |
| 154 | +fileaddr(Dosfile *fp, long ltarget) | |
| 155 | +{ | |
| 156 | + Dos *dos = fp->dos; | |
| 157 | + long l; | |
| 158 | + long p; | |
| 159 | + | |
| 160 | + chat("fileaddr %8.8s %d\n", fp->name, ltarget); | |
| 161 | + /* | |
| 162 | + * root directory is contiguous and easy | |
| 163 | + */ | |
| 164 | + if(fp->pstart == 0){ | |
| 165 | + if(ltarget*dos->sectsize*dos->clustsize >= dos->rootsize*sizeof(Dosdir)) | |
| 166 | + return -1; | |
| 167 | + l = dos->rootaddr + ltarget*dos->clustsize; | |
| 168 | + chat("fileaddr %d -> %d\n", ltarget, l); | |
| 169 | + return l; | |
| 170 | + } | |
| 171 | + | |
| 172 | + /* | |
| 173 | + * anything else requires a walk through the fat | |
| 174 | + */ | |
| 175 | + if(ltarget >= fp->lcurrent && fp->pcurrent){ | |
| 176 | + /* start at the currrent point */ | |
| 177 | + l = fp->lcurrent; | |
| 178 | + p = fp->pcurrent; | |
| 179 | + } else { | |
| 180 | + /* go back to the beginning */ | |
| 181 | + l = 0; | |
| 182 | + p = fp->pstart; | |
| 183 | + } | |
| 184 | + while(l != ltarget){ | |
| 185 | + /* walk the fat */ | |
| 186 | + p = fatwalk(dos, p); | |
| 187 | + if(p < 0) | |
| 188 | + return -1; | |
| 189 | + l++; | |
| 190 | + } | |
| 191 | + fp->lcurrent = l; | |
| 192 | + fp->pcurrent = p; | |
| 193 | + | |
| 194 | + /* | |
| 195 | + * clusters start at 2 instead of 0 (why? - presotto) | |
| 196 | + */ | |
| 197 | + l = dos->dataaddr + (p-2)*dos->clustsize; | |
| 198 | + chat("fileaddr %d -> %d\n", ltarget, l); | |
| 199 | + return l; | |
| 200 | +} | |
| 201 | + | |
| 202 | +/* | |
| 203 | + * read from a dos file | |
| 204 | + */ | |
| 205 | +long | |
| 206 | +dosread(Dosfile *fp, void *a, long n) | |
| 207 | +{ | |
| 208 | + long addr; | |
| 209 | + long rv; | |
| 210 | + int i; | |
| 211 | + int off; | |
| 212 | + Clustbuf *p; | |
| 213 | + uchar *from, *to; | |
| 214 | + | |
| 215 | + if((fp->attr & DDIR) == 0){ | |
| 216 | + if(fp->offset >= fp->length) | |
| 217 | + return 0; | |
| 218 | + if(fp->offset+n > fp->length) | |
| 219 | + n = fp->length - fp->offset; | |
| 220 | + } | |
| 221 | + | |
| 222 | + to = a; | |
| 223 | + for(rv = 0; rv < n; rv+=i){ | |
| 224 | + /* | |
| 225 | + * read the cluster | |
| 226 | + */ | |
| 227 | + addr = fileaddr(fp, fp->offset/fp->dos->clustbytes); | |
| 228 | + if(addr < 0) | |
| 229 | + return -1; | |
| 230 | + p = getclust(fp->dos, addr); | |
| 231 | + if(p == 0) | |
| 232 | + return -1; | |
| 233 | + | |
| 234 | + /* | |
| 235 | + * copy the bytes we need | |
| 236 | + */ | |
| 237 | + off = fp->offset % fp->dos->clustbytes; | |
| 238 | + from = &p->iobuf[off]; | |
| 239 | + i = n - rv; | |
| 240 | + if(i > fp->dos->clustbytes - off) | |
| 241 | + i = fp->dos->clustbytes - off; | |
| 242 | + memmove(to, from, i); | |
| 243 | + to += i; | |
| 244 | + fp->offset += i; | |
| 245 | + } | |
| 246 | + | |
| 247 | + return rv; | |
| 248 | +} | |
| 249 | + | |
| 250 | +/* | |
| 251 | + * walk a directory returns | |
| 252 | + * -1 if something went wrong | |
| 253 | + * 0 if not found | |
| 254 | + * 1 if found | |
| 255 | + */ | |
| 256 | +int | |
| 257 | +doswalk(Dosfile *file, char *name) | |
| 258 | +{ | |
| 259 | + Dosdir d; | |
| 260 | + long n; | |
| 261 | + | |
| 262 | + if((file->attr & DDIR) == 0){ | |
| 263 | + chat("walking non-directory!\n"); | |
| 264 | + return -1; | |
| 265 | + } | |
| 266 | + | |
| 267 | + setname(file, name); | |
| 268 | + | |
| 269 | + file->offset = 0; /* start at the beginning */ | |
| 270 | + while((n = dosread(file, &d, sizeof(d))) == sizeof(d)){ | |
| 271 | + chat("comparing to %8.8s.%3.3s\n", d.name, d.ext); | |
| 272 | + if(memcmp(file->name, d.name, sizeof(d.name)) != 0) | |
| 273 | + continue; | |
| 274 | + if(memcmp(file->ext, d.ext, sizeof(d.ext)) != 0) | |
| 275 | + continue; | |
| 276 | + if(d.attr & DVLABEL){ | |
| 277 | + chat("%8.8s.%3.3s is a LABEL\n", d.name, d.ext); | |
| 278 | + continue; | |
| 279 | + } | |
| 280 | + file->attr = d.attr; | |
| 281 | + file->pstart = GSHORT(d.start); | |
| 282 | + file->length = GLONG(d.length); | |
| 283 | + file->pcurrent = 0; | |
| 284 | + file->lcurrent = 0; | |
| 285 | + file->offset = 0; | |
| 286 | + return 1; | |
| 287 | + } | |
| 288 | + return n >= 0 ? 0 : -1; | |
| 289 | +} | |
| 290 | + | |
| 291 | + | |
| 292 | +/* | |
| 293 | + * instructions that boot blocks can start with | |
| 294 | + */ | |
| 295 | +#define JMPSHORT 0xeb | |
| 296 | +#define JMPNEAR 0xe9 | |
| 297 | + | |
| 298 | +/* | |
| 299 | + * read dos file system properties | |
| 300 | + */ | |
| 301 | +int | |
| 302 | +dosinit(Dos *dos, int start, int ishard) | |
| 303 | +{ | |
| 304 | + Dosboot *b; | |
| 305 | + int i; | |
| 306 | + Clustbuf *p; | |
| 307 | + Dospart *dp; | |
| 308 | + ulong mbroffset, offset; | |
| 309 | + | |
| 310 | + /* defaults till we know better */ | |
| 311 | + dos->start = start; | |
| 312 | + dos->sectsize = 512; | |
| 313 | + dos->clustsize = 1; | |
| 314 | + mbroffset = 0; | |
| 315 | + | |
| 316 | +dmddo: | |
| 317 | + /* get first sector */ | |
| 318 | + p = getclust(dos, mbroffset); | |
| 319 | + if(p == 0){ | |
| 320 | + chat("can't read boot block\n"); | |
| 321 | + return -1; | |
| 322 | + } | |
| 323 | + | |
| 324 | + /* | |
| 325 | + * If it's a hard disc then look for an MBR and pick either an | |
| 326 | + * active partition or the FAT with the lowest starting LBA. | |
| 327 | + * Things are tricky because we could be pointing to, amongst others: | |
| 328 | + * 1) a floppy BPB; | |
| 329 | + * 2) a hard disc MBR; | |
| 330 | + * 3) a hard disc extended partition table; | |
| 331 | + * 4) a logical drive on a hard disc; | |
| 332 | + * 5) a disc-manager boot block. | |
| 333 | + * They all have the same magic at the end of the block. | |
| 334 | + */ | |
| 335 | + if(p->iobuf[0x1FE] != 0x55 || p->iobuf[0x1FF] != 0xAA) { | |
| 336 | + chat("not DOS\n"); | |
| 337 | + return -1; | |
| 338 | + } | |
| 339 | + p->dos = 0; | |
| 340 | + b = (Dosboot *)p->iobuf; | |
| 341 | + if(ishard && b->mediadesc != 0xF8){ | |
| 342 | + dp = (Dospart*)&p->iobuf[0x1BE]; | |
| 343 | + offset = 0xFFFFFFFF; | |
| 344 | + for(i = 0; i < 4; i++, dp++){ | |
| 345 | + if(dp->type == DMDDO){ | |
| 346 | + mbroffset = 63; | |
| 347 | + goto dmddo; | |
| 348 | + } | |
| 349 | + if(dp->type != FAT12 && dp->type != FAT16 && dp->type != FATHUGE) | |
| 350 | + continue; | |
| 351 | + if(dp->flag & 0x80){ | |
| 352 | + offset = GLONG(dp->start); | |
| 353 | + break; | |
| 354 | + } | |
| 355 | + if(GLONG(dp->start) < offset) | |
| 356 | + offset = GLONG(dp->start); | |
| 357 | + } | |
| 358 | + if(i != 4 || offset != 0xFFFFFFFF){ | |
| 359 | + dos->start = mbroffset+offset; | |
| 360 | + p = getclust(dos, 0); | |
| 361 | + if(p == 0 || p->iobuf[0x1FE] != 0x55 || p->iobuf[0x1FF] != 0xAA) | |
| 362 | + return -1; | |
| 363 | + } | |
| 364 | + p->dos = 0; | |
| 365 | + } | |
| 366 | + | |
| 367 | + b = (Dosboot *)p->iobuf; | |
| 368 | + if(b->magic[0] != JMPNEAR && (b->magic[0] != JMPSHORT || b->magic[2] != 0x90)){ | |
| 369 | + chat("no dos file system\n"); | |
| 370 | + return -1; | |
| 371 | + } | |
| 372 | + | |
| 373 | + if(chatty) | |
| 374 | + bootdump(b); | |
| 375 | + | |
| 376 | + /* | |
| 377 | + * determine the systems' wondersous properties | |
| 378 | + */ | |
| 379 | + dos->sectsize = GSHORT(b->sectsize); | |
| 380 | + dos->clustsize = b->clustsize; | |
| 381 | + dos->clustbytes = dos->sectsize*dos->clustsize; | |
| 382 | + dos->nresrv = GSHORT(b->nresrv); | |
| 383 | + dos->nfats = b->nfats; | |
| 384 | + dos->rootsize = GSHORT(b->rootsize); | |
| 385 | + dos->volsize = GSHORT(b->volsize); | |
| 386 | + if(dos->volsize == 0) | |
| 387 | + dos->volsize = GLONG(b->bigvolsize); | |
| 388 | + dos->mediadesc = b->mediadesc; | |
| 389 | + dos->fatsize = GSHORT(b->fatsize); | |
| 390 | + dos->fataddr = dos->nresrv; | |
| 391 | + dos->rootaddr = dos->fataddr + dos->nfats*dos->fatsize; | |
| 392 | + i = dos->rootsize*sizeof(Dosdir) + dos->sectsize - 1; | |
| 393 | + i = i/dos->sectsize; | |
| 394 | + dos->dataaddr = dos->rootaddr + i; | |
| 395 | + dos->fatclusters = 2+(dos->volsize - dos->dataaddr)/dos->clustsize; | |
| 396 | + if(dos->fatclusters < 4087) | |
| 397 | + dos->fatbits = 12; | |
| 398 | + else | |
| 399 | + dos->fatbits = 16; | |
| 400 | + dos->freeptr = 2; | |
| 401 | + | |
| 402 | + /* | |
| 403 | + * set up the root | |
| 404 | + */ | |
| 405 | + dos->root.dos = dos; | |
| 406 | + dos->root.pstart = 0; | |
| 407 | + dos->root.pcurrent = dos->root.lcurrent = 0; | |
| 408 | + dos->root.offset = 0; | |
| 409 | + dos->root.attr = DDIR; | |
| 410 | + dos->root.length = dos->rootsize*sizeof(Dosdir); | |
| 411 | + | |
| 412 | + return 0; | |
| 413 | +} | |
| 414 | + | |
| 415 | +static void | |
| 416 | +bootdump(Dosboot *b) | |
| 417 | +{ | |
| 418 | + if(chatty == 0) | |
| 419 | + return; | |
| 420 | + print("magic: 0x%2.2x 0x%2.2x 0x%2.2x\n", | |
| 421 | + b->magic[0], b->magic[1], b->magic[2]); | |
| 422 | + print("version: \"%8.8s\"\n", b->version); | |
| 423 | + print("sectsize: %d\n", GSHORT(b->sectsize)); | |
| 424 | + print("allocsize: %d\n", b->clustsize); | |
| 425 | + print("nresrv: %d\n", GSHORT(b->nresrv)); | |
| 426 | + print("nfats: %d\n", b->nfats); | |
| 427 | + print("rootsize: %d\n", GSHORT(b->rootsize)); | |
| 428 | + print("volsize: %d\n", GSHORT(b->volsize)); | |
| 429 | + print("mediadesc: 0x%2.2x\n", b->mediadesc); | |
| 430 | + print("fatsize: %d\n", GSHORT(b->fatsize)); | |
| 431 | + print("trksize: %d\n", GSHORT(b->trksize)); | |
| 432 | + print("nheads: %d\n", GSHORT(b->nheads)); | |
| 433 | + print("nhidden: %d\n", GLONG(b->nhidden)); | |
| 434 | + print("bigvolsize: %d\n", GLONG(b->bigvolsize)); | |
| 435 | + print("driveno: %d\n", b->driveno); | |
| 436 | + print("reserved0: 0x%2.2x\n", b->reserved0); | |
| 437 | + print("bootsig: 0x%2.2x\n", b->bootsig); | |
| 438 | + print("volid: 0x%8.8x\n", GLONG(b->volid)); | |
| 439 | + print("label: \"%11.11s\"\n", b->label); | |
| 440 | +} | |
| 441 | + | |
| 442 | +/* | |
| 443 | + * grab next element from a path, return the pointer to unprocessed portion of | |
| 444 | + * path. | |
| 445 | + */ | |
| 446 | +static char * | |
| 447 | +nextelem(char *path, char *elem) | |
| 448 | +{ | |
| 449 | + int i; | |
| 450 | + | |
| 451 | + while(*path == '/') | |
| 452 | + path++; | |
| 453 | + if(*path==0 || *path==' ') | |
| 454 | + return 0; | |
| 455 | + for(i=0; *path!='\0' && *path!='/' && *path!=' '; i++){ | |
| 456 | + if(i==28){ | |
| 457 | + print("name component too long\n"); | |
| 458 | + return 0; | |
| 459 | + } | |
| 460 | + *elem++ = *path++; | |
| 461 | + } | |
| 462 | + *elem = '\0'; | |
| 463 | + return path; | |
| 464 | +} | |
| 465 | + | |
| 466 | +int | |
| 467 | +dosstat(Dos *dos, char *path, Dosfile *f) | |
| 468 | +{ | |
| 469 | + char element[NAMELEN]; | |
| 470 | + | |
| 471 | + *f = dos->root; | |
| 472 | + while(path = nextelem(path, element)){ | |
| 473 | + switch(doswalk(f, element)){ | |
| 474 | + case -1: | |
| 475 | + return -1; | |
| 476 | + case 0: | |
| 477 | + return 0; | |
| 478 | + } | |
| 479 | + } | |
| 480 | + return 1; | |
| 481 | +} | |
| 482 | + | |
| 483 | +/* | |
| 484 | + * boot | |
| 485 | + */ | |
| 486 | +int | |
| 487 | +dosboot(Dos *dos, char *path) | |
| 488 | +{ | |
| 489 | + Dosfile file; | |
| 490 | + long n; | |
| 491 | + long addr; | |
| 492 | + Exec *ep; | |
| 493 | + void (*b)(void); | |
| 494 | + | |
| 495 | + switch(dosstat(dos, path, &file)){ | |
| 496 | + | |
| 497 | + case -1: | |
| 498 | + print("error walking to %s\n", path); | |
| 499 | + return -1; | |
| 500 | + case 0: | |
| 501 | + print("%s not found\n", path); | |
| 502 | + return -1; | |
| 503 | + case 1: | |
| 504 | + print("found %8.8s.%3.3s attr 0x%ux start 0x%lux len %d\n", file.name, | |
| 505 | + file.ext, file.attr, file.pstart, file.length); | |
| 506 | + break; | |
| 507 | + } | |
| 508 | + | |
| 509 | + /* | |
| 510 | + * read header | |
| 511 | + */ | |
| 512 | + ep = (Exec*)ialloc(sizeof(Exec), 0); | |
| 513 | + n = sizeof(Exec); | |
| 514 | + if(dosreadseg(&file, n, (ulong) ep) != n){ | |
| 515 | + print(premature); | |
| 516 | + return -1; | |
| 517 | + } | |
| 518 | + if(GLLONG(ep->magic) != Q_MAGIC){ | |
| 519 | + print("bad magic 0x%lux not a plan 9 executable!\n", GLLONG(ep->magic)); | |
| 520 | + return -1; | |
| 521 | + } | |
| 522 | + | |
| 523 | + /* | |
| 524 | + * read text | |
| 525 | + */ | |
| 526 | + addr = PADDR(GLLONG(ep->entry)); | |
| 527 | + n = GLLONG(ep->text); | |
| 528 | + print("+%d", n); | |
| 529 | + if(dosreadseg(&file, n, addr) != n){ | |
| 530 | + print(premature); | |
| 531 | + return -1; | |
| 532 | + } | |
| 533 | + | |
| 534 | + /* | |
| 535 | + * read data (starts at first page after kernel) | |
| 536 | + */ | |
| 537 | + addr = PGROUND(addr+n); | |
| 538 | + n = GLLONG(ep->data); | |
| 539 | + print("+%d", n); | |
| 540 | + if(dosreadseg(&file, n, addr) != n){ | |
| 541 | + print(premature); | |
| 542 | + return -1; | |
| 543 | + } | |
| 544 | + | |
| 545 | + /* | |
| 546 | + * bss and entry point | |
| 547 | + */ | |
| 548 | + print("+%d\nstart at 0x%lux\n", GLLONG(ep->bss), GLLONG(ep->entry)); | |
| 549 | + | |
| 550 | + /* | |
| 551 | + * Go to new code. It's up to the program to get its PC relocated to | |
| 552 | + * the right place. | |
| 553 | + */ | |
| 554 | + b = (void (*)(void))(PADDR(GLLONG(ep->entry))); | |
| 555 | + (*b)(); | |
| 556 | + return 0; | |
| 557 | +} | |
| 558 | + | |
| 559 | +/* | |
| 560 | + * read in a segment | |
| 561 | + */ | |
| 562 | +long | |
| 563 | +dosreadseg(Dosfile *fp, long len, long addr) | |
| 564 | +{ | |
| 565 | + char *a; | |
| 566 | + long n, sofar; | |
| 567 | + | |
| 568 | + a = (char *)addr; | |
| 569 | + for(sofar = 0; sofar < len; sofar += n){ | |
| 570 | + n = 8*1024; | |
| 571 | + if(len - sofar < n) | |
| 572 | + n = len - sofar; | |
| 573 | + n = dosread(fp, a + sofar, n); | |
| 574 | + if(n <= 0) | |
| 575 | + break; | |
| 576 | + print("."); | |
| 577 | + } | |
| 578 | + return sofar; | |
| 579 | +} | |
| 580 | + | |
| 581 | +/* | |
| 582 | + * set up a dos file name | |
| 583 | + */ | |
| 584 | +static void | |
| 585 | +setname(Dosfile *fp, char *from) | |
| 586 | +{ | |
| 587 | + char *to; | |
| 588 | + | |
| 589 | + to = fp->name; | |
| 590 | + for(; *from && to-fp->name < 8; from++, to++){ | |
| 591 | + if(*from == '.'){ | |
| 592 | + from++; | |
| 593 | + break; | |
| 594 | + } | |
| 595 | + if(*from >= 'a' && *from <= 'z') | |
| 596 | + *to = *from + 'A' - 'a'; | |
| 597 | + else | |
| 598 | + *to = *from; | |
| 599 | + } | |
| 600 | + while(to - fp->name < 8) | |
| 601 | + *to++ = ' '; | |
| 602 | + | |
| 603 | + to = fp->ext; | |
| 604 | + for(; *from && to-fp->ext < 3; from++, to++){ | |
| 605 | + if(*from >= 'a' && *from <= 'z') | |
| 606 | + *to = *from + 'A' - 'a'; | |
| 607 | + else | |
| 608 | + *to = *from; | |
| 609 | + } | |
| 610 | + while(to-fp->ext < 3) | |
| 611 | + *to++ = ' '; | |
| 612 | + | |
| 613 | + chat("name is %8.8s %3.3s\n", fp->name, fp->ext); | |
| 614 | +} | |
| @@ -0,0 +1,110 @@ | ||
| 1 | +typedef struct Dosboot Dosboot; | |
| 2 | +typedef struct Dos Dos; | |
| 3 | +typedef struct Dosdir Dosdir; | |
| 4 | +typedef struct Dosfile Dosfile; | |
| 5 | +typedef struct Dospart Dospart; | |
| 6 | + | |
| 7 | +struct Dospart | |
| 8 | +{ | |
| 9 | + uchar flag; /* active flag */ | |
| 10 | + uchar shead; /* starting head */ | |
| 11 | + uchar scs[2]; /* starting cylinder/sector */ | |
| 12 | + uchar type; /* partition type */ | |
| 13 | + uchar ehead; /* ending head */ | |
| 14 | + uchar ecs[2]; /* ending cylinder/sector */ | |
| 15 | + uchar start[4]; /* starting sector */ | |
| 16 | + uchar len[4]; /* length in sectors */ | |
| 17 | +}; | |
| 18 | + | |
| 19 | +#define FAT12 0x01 | |
| 20 | +#define FAT16 0x04 | |
| 21 | +#define FATHUGE 0x06 | |
| 22 | +#define DMDDO 0x54 | |
| 23 | + | |
| 24 | +struct Dosboot{ | |
| 25 | + uchar magic[3]; | |
| 26 | + uchar version[8]; | |
| 27 | + uchar sectsize[2]; | |
| 28 | + uchar clustsize; | |
| 29 | + uchar nresrv[2]; | |
| 30 | + uchar nfats; | |
| 31 | + uchar rootsize[2]; | |
| 32 | + uchar volsize[2]; | |
| 33 | + uchar mediadesc; | |
| 34 | + uchar fatsize[2]; | |
| 35 | + uchar trksize[2]; | |
| 36 | + uchar nheads[2]; | |
| 37 | + uchar nhidden[4]; | |
| 38 | + uchar bigvolsize[4]; | |
| 39 | + uchar driveno; | |
| 40 | + uchar reserved0; | |
| 41 | + uchar bootsig; | |
| 42 | + uchar volid[4]; | |
| 43 | + uchar label[11]; | |
| 44 | + uchar reserved1[8]; | |
| 45 | +}; | |
| 46 | + | |
| 47 | +struct Dosfile{ | |
| 48 | + Dos *dos; /* owning dos file system */ | |
| 49 | + char name[8]; | |
| 50 | + char ext[3]; | |
| 51 | + uchar attr; | |
| 52 | + long length; | |
| 53 | + long pstart; /* physical start cluster address */ | |
| 54 | + long pcurrent; /* physical current cluster address */ | |
| 55 | + long lcurrent; /* logical current cluster address */ | |
| 56 | + long offset; | |
| 57 | +}; | |
| 58 | + | |
| 59 | +struct Dos{ | |
| 60 | + int dev; /* device id */ | |
| 61 | + long (*read)(int, void*, long); /* read routine */ | |
| 62 | + long (*seek)(int, long); /* seek routine */ | |
| 63 | + | |
| 64 | + int start; /* start of file system */ | |
| 65 | + int sectsize; /* in bytes */ | |
| 66 | + int clustsize; /* in sectors */ | |
| 67 | + int clustbytes; /* in bytes */ | |
| 68 | + int nresrv; /* sectors */ | |
| 69 | + int nfats; /* usually 2 */ | |
| 70 | + int rootsize; /* number of entries */ | |
| 71 | + int volsize; /* in sectors */ | |
| 72 | + int mediadesc; | |
| 73 | + int fatsize; /* in sectors */ | |
| 74 | + int fatclusters; | |
| 75 | + int fatbits; /* 12 or 16 */ | |
| 76 | + long fataddr; /* sector number */ | |
| 77 | + long rootaddr; | |
| 78 | + long dataaddr; | |
| 79 | + long freeptr; | |
| 80 | + | |
| 81 | + Dosfile root; | |
| 82 | +}; | |
| 83 | + | |
| 84 | +struct Dosdir{ | |
| 85 | + uchar name[8]; | |
| 86 | + uchar ext[3]; | |
| 87 | + uchar attr; | |
| 88 | + uchar reserved[10]; | |
| 89 | + uchar time[2]; | |
| 90 | + uchar date[2]; | |
| 91 | + uchar start[2]; | |
| 92 | + uchar length[4]; | |
| 93 | +}; | |
| 94 | + | |
| 95 | +#define DRONLY 0x01 | |
| 96 | +#define DHIDDEN 0x02 | |
| 97 | +#define DSYSTEM 0x04 | |
| 98 | +#define DVLABEL 0x08 | |
| 99 | +#define DDIR 0x10 | |
| 100 | +#define DARCH 0x20 | |
| 101 | + | |
| 102 | +extern int chatty; | |
| 103 | + | |
| 104 | +extern int dosboot(Dos*, char*); | |
| 105 | +extern int dosinit(Dos*, int, int); | |
| 106 | +extern long dosread(Dosfile*, void*, long); | |
| 107 | +extern int dosstat(Dos*, char*, Dosfile*); | |
| 108 | +extern int doswalk(Dosfile*, char*); | |
| 109 | + | |
| 110 | +extern int plan9ini(Dos*, char*); | |
| @@ -0,0 +1,59 @@ | ||
| 1 | +/* | |
| 2 | + * All the goo for PC ethernet cards. | |
| 3 | + */ | |
| 4 | +typedef struct Card Card; | |
| 5 | +typedef struct Type Type; | |
| 6 | +typedef struct Ctlr Ctlr; | |
| 7 | + | |
| 8 | +/* | |
| 9 | + * Hardware interface. | |
| 10 | + */ | |
| 11 | +struct Card { | |
| 12 | + ISAConf; | |
| 13 | + | |
| 14 | + int (*reset)(Ctlr*); | |
| 15 | + void (*attach)(Ctlr*); | |
| 16 | + | |
| 17 | + void *(*read)(Ctlr*, void*, ulong, ulong); | |
| 18 | + void *(*write)(Ctlr*, ulong, void*, ulong); | |
| 19 | + | |
| 20 | + void (*receive)(Ctlr*); | |
| 21 | + void (*transmit)(Ctlr*); | |
| 22 | + void (*intr)(Ureg*, void*); | |
| 23 | + void (*overflow)(Ctlr*); | |
| 24 | + | |
| 25 | + uchar bit16; /* true if a 16 bit interface */ | |
| 26 | + uchar ram; /* true if card has shared memory */ | |
| 27 | + | |
| 28 | + ulong dp8390; /* I/O address of 8390 (if any) */ | |
| 29 | + ulong data; /* I/O data port if no shared memory */ | |
| 30 | + uchar nxtpkt; /* software bndry */ | |
| 31 | + uchar tstart; /* 8390 ring addresses */ | |
| 32 | + uchar pstart; | |
| 33 | + uchar pstop; | |
| 34 | + | |
| 35 | + uchar dummyrr; /* do dummy remote read */ | |
| 36 | +}; | |
| 37 | + | |
| 38 | +/* | |
| 39 | + * Software controller. | |
| 40 | + */ | |
| 41 | +struct Ctlr { | |
| 42 | + Card card; /* hardware info */ | |
| 43 | + int ctlrno; | |
| 44 | + int present; | |
| 45 | + | |
| 46 | + Queue* iq; | |
| 47 | + Queue* oq; | |
| 48 | + | |
| 49 | + int inpackets; | |
| 50 | + int outpackets; | |
| 51 | + int crcs; /* input crc errors */ | |
| 52 | + int oerrs; /* output errors */ | |
| 53 | + int frames; /* framing errors */ | |
| 54 | + int overflows; /* packet overflows */ | |
| 55 | + int buffs; /* buffering errors */ | |
| 56 | +}; | |
| 57 | + | |
| 58 | +extern int sccethreset(Ctlr*); | |
| 59 | +extern int etheriq(Ctlr*, Block*, int); | |
| @@ -0,0 +1,411 @@ | ||
| 1 | +/* | |
| 2 | + * SCCn ethernet | |
| 3 | + */ | |
| 4 | + | |
| 5 | +#include "u.h" | |
| 6 | +#include "lib.h" | |
| 7 | +#include "mem.h" | |
| 8 | +#include "dat.h" | |
| 9 | +#include "fns.h" | |
| 10 | +#include "io.h" | |
| 11 | + | |
| 12 | +#include "etherif.h" | |
| 13 | + | |
| 14 | +enum { | |
| 15 | + Nrdre = 32, /* receive descriptor ring entries */ | |
| 16 | + Ntdre = 4, /* transmit descriptor ring entries */ | |
| 17 | + | |
| 18 | + Rbsize = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */ | |
| 19 | + Bufsize = (Rbsize+7)&~7, /* aligned */ | |
| 20 | +}; | |
| 21 | + | |
| 22 | +enum { | |
| 23 | + /* ether-specific Rx BD bits */ | |
| 24 | + RxMiss= 1<<8, | |
| 25 | + RxeLG= 1<<5, | |
| 26 | + RxeNO= 1<<4, | |
| 27 | + RxeSH= 1<<3, | |
| 28 | + RxeCR= 1<<2, | |
| 29 | + RxeOV= 1<<1, | |
| 30 | + RxeCL= 1<<0, | |
| 31 | + RxError= (RxeLG|RxeNO|RxeSH|RxeCR|RxeOV|RxeCL), /* various error flags */ | |
| 32 | + | |
| 33 | + /* ether-specific Tx BD bits */ | |
| 34 | + TxPad= 1<<14, /* pad short frames */ | |
| 35 | + TxTC= 1<<10, /* transmit CRC */ | |
| 36 | + TxeDEF= 1<<9, | |
| 37 | + TxeHB= 1<<8, | |
| 38 | + TxeLC= 1<<7, | |
| 39 | + TxeRL= 1<<6, | |
| 40 | + TxeUN= 1<<1, | |
| 41 | + TxeCSL= 1<<0, | |
| 42 | + | |
| 43 | + /* scce */ | |
| 44 | + RXB= 1<<0, | |
| 45 | + TXB= 1<<1, | |
| 46 | + BSY= 1<<2, | |
| 47 | + RXF= 1<<3, | |
| 48 | + TXE= 1<<4, | |
| 49 | + | |
| 50 | + /* gsmrl */ | |
| 51 | + ENR= 1<<5, | |
| 52 | + ENT= 1<<4, | |
| 53 | + | |
| 54 | + /* port A */ | |
| 55 | + RXD1= SIBIT(15), | |
| 56 | + TXD1= SIBIT(14), | |
| 57 | + | |
| 58 | + /* port B */ | |
| 59 | + RTS1= IBIT(19), | |
| 60 | + | |
| 61 | + /* port C */ | |
| 62 | + CTS1= SIBIT(11), | |
| 63 | + CD1= SIBIT(10), | |
| 64 | +}; | |
| 65 | + | |
| 66 | +typedef struct Etherparam Etherparam; | |
| 67 | +struct Etherparam { | |
| 68 | + SCCparam; | |
| 69 | + ulong c_pres; /* preset CRC */ | |
| 70 | + ulong c_mask; /* constant mask for CRC */ | |
| 71 | + ulong crcec; /* CRC error counter */ | |
| 72 | + ulong alec; /* alighnment error counter */ | |
| 73 | + ulong disfc; /* discard frame counter */ | |
| 74 | + ushort pads; /* short frame PAD characters */ | |
| 75 | + ushort ret_lim; /* retry limit threshold */ | |
| 76 | + ushort ret_cnt; /* retry limit counter */ | |
| 77 | + ushort mflr; /* maximum frame length reg */ | |
| 78 | + ushort minflr; /* minimum frame length reg */ | |
| 79 | + ushort maxd1; /* maximum DMA1 length reg */ | |
| 80 | + ushort maxd2; /* maximum DMA2 length reg */ | |
| 81 | + ushort maxd; /* rx max DMA */ | |
| 82 | + ushort dma_cnt; /* rx dma counter */ | |
| 83 | + ushort max_b; /* max bd byte count */ | |
| 84 | + ushort gaddr[4]; /* group address filter */ | |
| 85 | + ulong tbuf0_data0; /* save area 0 - current frm */ | |
| 86 | + ulong tbuf0_data1; /* save area 1 - current frm */ | |
| 87 | + ulong tbuf0_rba0; | |
| 88 | + ulong tbuf0_crc; | |
| 89 | + ushort tbuf0_bcnt; | |
| 90 | + ushort paddr[3]; /* physical address LSB to MSB increasing */ | |
| 91 | + ushort p_per; /* persistence */ | |
| 92 | + ushort rfbd_ptr; /* rx first bd pointer */ | |
| 93 | + ushort tfbd_ptr; /* tx first bd pointer */ | |
| 94 | + ushort tlbd_ptr; /* tx last bd pointer */ | |
| 95 | + ulong tbuf1_data0; /* save area 0 - next frame */ | |
| 96 | + ulong tbuf1_data1; /* save area 1 - next frame */ | |
| 97 | + ulong tbuf1_rba0; | |
| 98 | + ulong tbuf1_crc; | |
| 99 | + ushort tbuf1_bcnt; | |
| 100 | + ushort tx_len; /* tx frame length counter */ | |
| 101 | + ushort iaddr[4]; /* individual address filter*/ | |
| 102 | + ushort boff_cnt; /* back-off counter */ | |
| 103 | + ushort taddr[3]; /* temp address */ | |
| 104 | +}; | |
| 105 | + | |
| 106 | +typedef struct { | |
| 107 | + SCC* scc; | |
| 108 | + int port; | |
| 109 | + int cpm; | |
| 110 | + | |
| 111 | + BD* rdr; /* receive descriptor ring */ | |
| 112 | + void* rrb; /* receive ring buffers */ | |
| 113 | + int rdrx; /* index into rdr */ | |
| 114 | + | |
| 115 | + BD* tdr; /* transmit descriptor ring */ | |
| 116 | + void* trb; /* transmit ring buffers */ | |
| 117 | + int tdrx; /* index into tdr */ | |
| 118 | +} Mot; | |
| 119 | +static Mot mot[MaxEther]; | |
| 120 | + | |
| 121 | +static int sccid[] = {-1, SCC1ID, SCC2ID, SCC3ID, SCC4ID}; | |
| 122 | +static int sccparam[] = {-1, SCC1P, SCC2P, SCC3P, SCC4P}; | |
| 123 | +static int sccreg[] = {-1, 0xA00, 0xA20, 0xA40, 0xA60}; | |
| 124 | +static int sccirq[] = {-1, 0x1E, 0x1D, 0x1C, 0x1B}; | |
| 125 | + | |
| 126 | +static void | |
| 127 | +attach(Ctlr *ctlr) | |
| 128 | +{ | |
| 129 | + mot[ctlr->ctlrno].scc->gsmrl |= ENR|ENT; | |
| 130 | + eieio(); | |
| 131 | +} | |
| 132 | + | |
| 133 | +static void | |
| 134 | +transmit(Ctlr *ctlr) | |
| 135 | +{ | |
| 136 | + int len; | |
| 137 | + Mot *motp; | |
| 138 | + Block *b; | |
| 139 | + BD *tdre; | |
| 140 | + | |
| 141 | + motp = &mot[ctlr->ctlrno]; | |
| 142 | + while(((tdre = &motp->tdr[motp->tdrx])->status & BDReady) == 0){ | |
| 143 | + b = qget(ctlr->oq); | |
| 144 | + if(b == 0) | |
| 145 | + break; | |
| 146 | + | |
| 147 | + /* | |
| 148 | + * Copy the packet to the transmit buffer. | |
| 149 | + */ | |
| 150 | + len = BLEN(b); | |
| 151 | + memmove(KADDR(tdre->addr), b->rp, len); | |
| 152 | + | |
| 153 | + /* | |
| 154 | + * Give ownership of the descriptor to the chip, increment the | |
| 155 | + * software ring descriptor pointer and tell the chip to poll. | |
| 156 | + */ | |
| 157 | + tdre->length = len; | |
| 158 | + eieio(); | |
| 159 | + tdre->status = (tdre->status & BDWrap) | BDReady|TxPad|BDInt|BDLast|TxTC; | |
| 160 | + eieio(); | |
| 161 | + motp->scc->todr = 1<<15; /* transmit now */ | |
| 162 | + eieio(); | |
| 163 | + motp->tdrx = NEXT(motp->tdrx, Ntdre); | |
| 164 | + | |
| 165 | + freeb(b); | |
| 166 | + | |
| 167 | + } | |
| 168 | +} | |
| 169 | + | |
| 170 | +static void | |
| 171 | +interrupt(Ureg*, void *ap) | |
| 172 | +{ | |
| 173 | + int len, events, status; | |
| 174 | + Mot *motp; | |
| 175 | + BD *rdre; | |
| 176 | + Block *b; | |
| 177 | + Ctlr *ctlr; | |
| 178 | + | |
| 179 | + ctlr = ap; | |
| 180 | + motp = &mot[ctlr->ctlrno]; | |
| 181 | + | |
| 182 | + /* | |
| 183 | + * Acknowledge all interrupts and whine about those that shouldn't | |
| 184 | + * happen. | |
| 185 | + */ | |
| 186 | + events = motp->scc->scce; | |
| 187 | + eieio(); | |
| 188 | + motp->scc->scce = events; | |
| 189 | + eieio(); | |
| 190 | + if(events & (TXE|BSY|RXB)) | |
| 191 | + print("ETHER.SCC#%d: scce = 0x%uX\n", ctlr->ctlrno, events); | |
| 192 | + //print(" %ux|", events); | |
| 193 | + /* | |
| 194 | + * Receiver interrupt: run round the descriptor ring logging | |
| 195 | + * errors and passing valid receive data up to the higher levels | |
| 196 | + * until we encounter a descriptor still owned by the chip. | |
| 197 | + */ | |
| 198 | + if(events & (RXF|RXB) || 1){ | |
| 199 | + rdre = &motp->rdr[motp->rdrx]; | |
| 200 | + while(((status = rdre->status) & BDEmpty) == 0){ | |
| 201 | + if(status & RxError || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){ | |
| 202 | + //if(status & RxBuff) | |
| 203 | + // ctlr->buffs++; | |
| 204 | + if(status & (1<<2)) | |
| 205 | + ctlr->crcs++; | |
| 206 | + if(status & (1<<1)) | |
| 207 | + ctlr->overflows++; | |
| 208 | + //print("eth rx: %ux\n", status); | |
| 209 | + if(status & RxError) | |
| 210 | + print("~"); | |
| 211 | + else if((status & BDLast) == 0) | |
| 212 | + print("@"); | |
| 213 | + } | |
| 214 | + else{ | |
| 215 | + /* | |
| 216 | + * We have a packet. Read it into the next | |
| 217 | + * free ring buffer, if any. | |
| 218 | + */ | |
| 219 | + len = rdre->length-4; | |
| 220 | + if((b = iallocb(len)) != 0){ | |
| 221 | + memmove(b->wp, KADDR(rdre->addr), len); | |
| 222 | + b->wp += len; | |
| 223 | + etheriq(ctlr, b, 1); | |
| 224 | + } | |
| 225 | + } | |
| 226 | + | |
| 227 | + /* | |
| 228 | + * Finished with this descriptor, reinitialise it, | |
| 229 | + * give it back to the chip, then on to the next... | |
| 230 | + */ | |
| 231 | + rdre->length = 0; | |
| 232 | + rdre->status = (rdre->status & BDWrap) | BDEmpty | BDInt; | |
| 233 | + eieio(); | |
| 234 | + | |
| 235 | + motp->rdrx = NEXT(motp->rdrx, Nrdre); | |
| 236 | + rdre = &motp->rdr[motp->rdrx]; | |
| 237 | + } | |
| 238 | + } | |
| 239 | + | |
| 240 | + /* | |
| 241 | + * Transmitter interrupt: handle anything queued for a free descriptor. | |
| 242 | + */ | |
| 243 | + if(events & TXB) | |
| 244 | + transmit(ctlr); | |
| 245 | + if(events & TXE) | |
| 246 | + cpmop(RestartTx, motp->cpm, 0); | |
| 247 | +} | |
| 248 | + | |
| 249 | +static void | |
| 250 | +ringinit(Mot* motp) | |
| 251 | +{ | |
| 252 | + int i, x; | |
| 253 | + | |
| 254 | + /* | |
| 255 | + * Initialise the receive and transmit buffer rings. The ring | |
| 256 | + * entries must be aligned on 16-byte boundaries. | |
| 257 | + */ | |
| 258 | + if(motp->rdr == 0) | |
| 259 | + motp->rdr = bdalloc(Nrdre); | |
| 260 | + if(motp->rrb == 0) | |
| 261 | + motp->rrb = ialloc(Nrdre*Bufsize, 0); | |
| 262 | + x = PADDR(motp->rrb); | |
| 263 | + for(i = 0; i < Nrdre; i++){ | |
| 264 | + motp->rdr[i].length = 0; | |
| 265 | + motp->rdr[i].addr = x; | |
| 266 | + motp->rdr[i].status = BDEmpty|BDInt; | |
| 267 | + x += Bufsize; | |
| 268 | + } | |
| 269 | + motp->rdr[i-1].status |= BDWrap; | |
| 270 | + motp->rdrx = 0; | |
| 271 | + | |
| 272 | + if(motp->tdr == 0) | |
| 273 | + motp->tdr = bdalloc(Ntdre); | |
| 274 | + if(motp->trb == 0) | |
| 275 | + motp->trb = ialloc(Ntdre*Bufsize, 0); | |
| 276 | + x = PADDR(motp->trb); | |
| 277 | + for(i = 0; i < Ntdre; i++){ | |
| 278 | + motp->tdr[i].addr = x; | |
| 279 | + motp->tdr[i].length = 0; | |
| 280 | + motp->tdr[i].status = TxPad|BDInt|BDLast|TxTC; | |
| 281 | + x += Bufsize; | |
| 282 | + } | |
| 283 | + motp->tdr[i-1].status |= BDWrap; | |
| 284 | + motp->tdrx = 0; | |
| 285 | +} | |
| 286 | + | |
| 287 | +/* | |
| 288 | + * This follows the MPC823 user guide: section16.9.23.7's initialisation sequence, | |
| 289 | + * except that it sets the right bits for the MPC823ADS board when SCC2 is used, | |
| 290 | + * and those for the 860/821 development board for SCC1. | |
| 291 | + */ | |
| 292 | +static void | |
| 293 | +sccsetup(Mot *ctlr, SCC *scc, uchar *ea) | |
| 294 | +{ | |
| 295 | + int i, rcs, tcs, w; | |
| 296 | + Etherparam *p; | |
| 297 | + IMM *io; | |
| 298 | + | |
| 299 | + | |
| 300 | + i = 2*(ctlr->port-1); | |
| 301 | + io = ioplock(); | |
| 302 | + w = (TXD1|RXD1)<<i; /* TXDn and RXDn in port A */ | |
| 303 | + io->papar |= w; /* enable TXDn and RXDn pins */ | |
| 304 | + io->padir &= ~w; | |
| 305 | + io->paodr &= ~w; /* not open drain */ | |
| 306 | + | |
| 307 | + w = (CD1|CTS1)<<i; /* CLSN and RENA: CDn and CTSn in port C */ | |
| 308 | + io->pcpar &= ~w; /* enable CLSN (CTSn) and RENA (CDn) */ | |
| 309 | + io->pcdir &= ~w; | |
| 310 | + io->pcso |= w; | |
| 311 | + iopunlock(); | |
| 312 | + | |
| 313 | + /* clocks and transceiver control: details depend on the board's wiring */ | |
| 314 | + archetherenable(ctlr->cpm, &rcs, &tcs); | |
| 315 | + | |
| 316 | + sccnmsi(ctlr->port, rcs, tcs); /* connect the clocks */ | |
| 317 | + | |
| 318 | + p = (Etherparam*)KADDR(sccparam[ctlr->port]); | |
| 319 | + memset(p, 0, sizeof(*p)); | |
| 320 | + p->rfcr = 0x18; | |
| 321 | + p->tfcr = 0x18; | |
| 322 | + p->mrblr = Bufsize; | |
| 323 | + p->rbase = PADDR(ctlr->rdr); | |
| 324 | + p->tbase = PADDR(ctlr->tdr); | |
| 325 | + | |
| 326 | + cpmop(InitRxTx, ctlr->cpm, 0); | |
| 327 | + | |
| 328 | + p->c_pres = ~0; | |
| 329 | + p->c_mask = 0xDEBB20E3; | |
| 330 | + p->crcec = 0; | |
| 331 | + p->alec = 0; | |
| 332 | + p->disfc = 0; | |
| 333 | + p->pads = 0x8888; | |
| 334 | + p->ret_lim = 0xF; | |
| 335 | + p->mflr = Rbsize; | |
| 336 | + p->minflr = ETHERMINTU+4; | |
| 337 | + p->maxd1 = Bufsize; | |
| 338 | + p->maxd2 = Bufsize; | |
| 339 | + p->p_per = 0; /* only moderate aggression */ | |
| 340 | + | |
| 341 | + for(i=0; i<Eaddrlen; i+=2) | |
| 342 | + p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i]; /* it's not the obvious byte order */ | |
| 343 | + | |
| 344 | + scc->psmr = (2<<10)|(5<<1); /* 32-bit CRC, ignore 22 bits before SFD */ | |
| 345 | + scc->dsr = 0xd555; | |
| 346 | + scc->gsmrh = 0; /* normal operation */ | |
| 347 | + scc->gsmrl = (1<<28)|(4<<21)|(1<<19)|0xC; /* transmit clock invert, 48 bit preamble, repetitive 10 preamble, ethernet */ | |
| 348 | + eieio(); | |
| 349 | + scc->scce = ~0; /* clear all events */ | |
| 350 | + eieio(); | |
| 351 | + scc->sccm = TXE | RXF | TXB; /* enable interrupts */ | |
| 352 | + eieio(); | |
| 353 | + | |
| 354 | + io = ioplock(); | |
| 355 | + w = RTS1<<(ctlr->port-1); /* enable TENA pin (RTSn) */ | |
| 356 | + io->pbpar |= w; | |
| 357 | + io->pbdir |= w; | |
| 358 | + iopunlock(); | |
| 359 | + | |
| 360 | + /* gsmrl enable is deferred until attach */ | |
| 361 | +} | |
| 362 | + | |
| 363 | +/* | |
| 364 | + * Prepare the SCCx ethernet for booting. | |
| 365 | + */ | |
| 366 | +int | |
| 367 | +sccethreset(Ctlr* ctlr) | |
| 368 | +{ | |
| 369 | + uchar ea[Eaddrlen]; | |
| 370 | + Mot *motp; | |
| 371 | + SCC *scc; | |
| 372 | + char line[50], def[50]; | |
| 373 | + | |
| 374 | + /* | |
| 375 | + * Since there's no EPROM, insist that the configuration entry | |
| 376 | + * (see conf.c and flash.c) holds the Ethernet address. | |
| 377 | + */ | |
| 378 | + memset(ea, 0, Eaddrlen); | |
| 379 | + if(memcmp(ea, ctlr->card.ea, Eaddrlen) == 0){ | |
| 380 | + print("no preset Ether address\n"); | |
| 381 | + for(;;){ | |
| 382 | + strcpy(def, "00108bf12900"); /* valid MAC address to be used only for initial configuration */ | |
| 383 | + if(getstr("ether MAC address", line, sizeof(line), def) < 0) | |
| 384 | + return -1; | |
| 385 | + if(parseether(ctlr->card.ea, line) >= 0 || ctlr->card.ea[0] == 0xFF) | |
| 386 | + break; | |
| 387 | + print("invalid MAC address\n"); | |
| 388 | + } | |
| 389 | + } | |
| 390 | + | |
| 391 | + scc = IOREGS(sccreg[ctlr->card.port], SCC); | |
| 392 | + ctlr->card.irq = VectorCPIC+sccirq[ctlr->card.port]; | |
| 393 | + | |
| 394 | + motp = &mot[ctlr->ctlrno]; | |
| 395 | + motp->scc = scc; | |
| 396 | + motp->port = ctlr->card.port; | |
| 397 | + motp->cpm = sccid[ctlr->card.port]; | |
| 398 | + | |
| 399 | + ringinit(motp); | |
| 400 | + | |
| 401 | + sccsetup(motp, scc, ctlr->card.ea); | |
| 402 | + | |
| 403 | + /* enable is deferred until attach */ | |
| 404 | + | |
| 405 | + ctlr->card.reset = sccethreset; | |
| 406 | + ctlr->card.attach = attach; | |
| 407 | + ctlr->card.transmit = transmit; | |
| 408 | + ctlr->card.intr = interrupt; | |
| 409 | + | |
| 410 | + return 0; | |
| 411 | +} | |
| @@ -0,0 +1,531 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <libg.h> | |
| 4 | +#include <gnot.h> | |
| 5 | + | |
| 6 | +/* | |
| 7 | + * bitblt operates a 'word' at a time. | |
| 8 | + * WBITS is the number of bits in a word | |
| 9 | + * LWBITS=log2(WBITS), | |
| 10 | + * W2L is the number of words in a long | |
| 11 | + * WMASK has bits set for the low order word of a long | |
| 12 | + * WType is a pointer to a word | |
| 13 | + */ | |
| 14 | +#ifndef WBITS | |
| 15 | +#define WBITS 32 | |
| 16 | +#define LWBITS 5 | |
| 17 | +#define W2L 1 | |
| 18 | +#define WMASK ~0UL | |
| 19 | +typedef ulong *WType; | |
| 20 | +#endif | |
| 21 | + | |
| 22 | +#define DEBUG | |
| 23 | + | |
| 24 | +#ifdef TEST | |
| 25 | +/* | |
| 26 | + * globals used for testing | |
| 27 | + */ | |
| 28 | +int FORCEFORW; | |
| 29 | +int FORCEBAKW; | |
| 30 | +GBitmap *curdm, *cursm; | |
| 31 | +Point curpt; | |
| 32 | +Rectangle curr; | |
| 33 | +Fcode curf; | |
| 34 | +void *mem; | |
| 35 | +#endif | |
| 36 | + | |
| 37 | +static void | |
| 38 | +gbitexplode(ulong sw, ulong *buf, int sdep, int x) | |
| 39 | +{ | |
| 40 | + int j, o, q, n, nw, inc, qinc; | |
| 41 | + ulong s, dw, pix; | |
| 42 | + | |
| 43 | + inc = 1 << sdep; | |
| 44 | + pix = (1 << inc) - 1; | |
| 45 | + nw = 1 << x; | |
| 46 | + n = 32 >> x; | |
| 47 | + qinc = (nw << sdep) - inc; | |
| 48 | + for(o = 32 - n; o >= 0; o -= n){ | |
| 49 | + dw = 0; | |
| 50 | + s = sw >> o; | |
| 51 | + q = 0; | |
| 52 | + for(j = 0; j < n; j += inc){ | |
| 53 | + dw |= (s & (pix << j)) << q; | |
| 54 | + q += qinc; | |
| 55 | + } | |
| 56 | + for(j = 0; j < x; j++) | |
| 57 | + dw |= dw << (inc << j); | |
| 58 | + *buf++ = dw; | |
| 59 | + } | |
| 60 | +} | |
| 61 | + | |
| 62 | +/* | |
| 63 | +void | |
| 64 | +main(void) | |
| 65 | +{ | |
| 66 | + ulong buf[128]; | |
| 67 | + | |
| 68 | + gbitexplode(0x7777, buf, 0, 3); | |
| 69 | + exits(0); | |
| 70 | +} | |
| 71 | +*/ | |
| 72 | + | |
| 73 | +void | |
| 74 | +gbitblt(GBitmap *dm, Point pt, GBitmap *sm, Rectangle r, Fcode fcode) | |
| 75 | +{ | |
| 76 | + int width; /* width in bits of dst */ | |
| 77 | + int wwidth; /* floor width in words */ | |
| 78 | + int height; /* height in pixels minus 1 */ | |
| 79 | + int sdep; /* src ldepth */ | |
| 80 | + int ddep; /* dst ldepth */ | |
| 81 | + int deltadep; /* diff between ldepths */ | |
| 82 | + int sspan; /* words between scanlines in src */ | |
| 83 | + int dspan; /* words between scanlines in dst */ | |
| 84 | + int soff; /* bit offset of src start point */ | |
| 85 | + int sdest; /* bit offset of src start point that matches doff when expanded */ | |
| 86 | + int doff; /* bit offset of dst start point */ | |
| 87 | + int delta; /* amount to shift src by */ | |
| 88 | + int sign; /* of delta */ | |
| 89 | + ulong *saddr; | |
| 90 | + ulong *daddr; | |
| 91 | + ulong *s; | |
| 92 | + ulong *d; | |
| 93 | + ulong mask; | |
| 94 | + ulong tmp; /* temp storage source word */ | |
| 95 | + ulong sw; /* source word constructed */ | |
| 96 | + ulong dw; /* dest word fetched */ | |
| 97 | + ulong lmask; /* affected pixels in leftmost dst word */ | |
| 98 | + ulong rmask; /* affected pixels in rightmost dst word */ | |
| 99 | + int i; | |
| 100 | + int j; | |
| 101 | + ulong buf[32]; /* for expanding a source */ | |
| 102 | + ulong *p; /* pointer into buf */ | |
| 103 | + int spare; /* number of words already converted */ | |
| 104 | + | |
| 105 | + | |
| 106 | +#ifdef TEST | |
| 107 | + curdm = dm; | |
| 108 | + cursm = sm; | |
| 109 | + curpt = pt; | |
| 110 | + curr = r; | |
| 111 | + curf = fcode; | |
| 112 | +#endif | |
| 113 | + | |
| 114 | + gbitbltclip(&dm); | |
| 115 | + | |
| 116 | + width = r.max.x - r.min.x; | |
| 117 | + if(width <= 0) | |
| 118 | + return; | |
| 119 | + height = r.max.y - r.min.y - 1; | |
| 120 | + if(height < 0) | |
| 121 | + return; | |
| 122 | + | |
| 123 | + ddep = dm->ldepth; | |
| 124 | + pt.x <<= ddep; | |
| 125 | + width <<= ddep; | |
| 126 | + | |
| 127 | + sdep = sm->ldepth; | |
| 128 | + r.min.x <<= sdep; | |
| 129 | + r.max.x <<= sdep; | |
| 130 | + | |
| 131 | + dspan = dm->width * W2L; | |
| 132 | + sspan = sm->width * W2L; | |
| 133 | + | |
| 134 | + daddr = (ulong*)((WType)dm->base | |
| 135 | + + dm->zero*W2L + pt.y*dspan | |
| 136 | + + (pt.x >> LWBITS)); | |
| 137 | + saddr = (ulong*)((WType)sm->base | |
| 138 | + + sm->zero*W2L + r.min.y*sspan | |
| 139 | + + (r.min.x >> LWBITS)); | |
| 140 | + | |
| 141 | + doff = pt.x & (WBITS - 1); | |
| 142 | + lmask = WMASK >> doff; | |
| 143 | + rmask = (WMASK << (WBITS - ((doff+width) & (WBITS-1))))&WMASK; | |
| 144 | + if(!rmask) | |
| 145 | + rmask = WMASK; | |
| 146 | + soff = r.min.x & (WBITS-1); | |
| 147 | + wwidth = ((pt.x+width-1)>>LWBITS) - (pt.x>>LWBITS); | |
| 148 | + | |
| 149 | + if(sm == dm){ | |
| 150 | +#ifdef TEST | |
| 151 | + if(!FORCEBAKW && | |
| 152 | + (FORCEFORW || sm != dm || saddr > daddr || | |
| 153 | + (saddr == daddr && soff > doff))) | |
| 154 | + ; | |
| 155 | + else{ | |
| 156 | + daddr += height * dspan; | |
| 157 | + saddr += height * sspan; | |
| 158 | + sspan -= 2 * W2L * sm->width; | |
| 159 | + dspan -= 2 * W2L * dm->width; | |
| 160 | + } | |
| 161 | +#else | |
| 162 | + if(r.min.y < pt.y){ /* bottom to top */ | |
| 163 | + daddr += height * dspan; | |
| 164 | + saddr += height * sspan; | |
| 165 | + sspan -= 2 * W2L * sm->width; | |
| 166 | + dspan -= 2 * W2L * dm->width; | |
| 167 | + }else if(r.min.y == pt.y && r.min.x < pt.x) | |
| 168 | + abort()/*goto right*/; | |
| 169 | +#endif | |
| 170 | + } | |
| 171 | + if(wwidth == 0) /* collapse masks for narrow cases */ | |
| 172 | + lmask &= rmask; | |
| 173 | + fcode &= F; | |
| 174 | + | |
| 175 | + deltadep = ddep - sdep; | |
| 176 | + sdest = doff >> deltadep; | |
| 177 | + delta = soff - sdest; | |
| 178 | + sign = 0; | |
| 179 | + if(delta < 0){ | |
| 180 | + sign = 1; | |
| 181 | + delta = -delta; | |
| 182 | + } | |
| 183 | + | |
| 184 | + p = 0; | |
| 185 | + for(j = 0; j <= height; j++){ | |
| 186 | + d = daddr; | |
| 187 | + s = saddr; | |
| 188 | + mask = lmask; | |
| 189 | + tmp = 0; | |
| 190 | + if(!sign) | |
| 191 | + tmp = *s++; | |
| 192 | + spare = 0; | |
| 193 | + for(i = wwidth; i >= 0; i--){ | |
| 194 | + if(spare) | |
| 195 | + sw = *p++; | |
| 196 | + else{ | |
| 197 | + if(sign){ | |
| 198 | + sw = tmp << (WBITS-delta); | |
| 199 | + tmp = *s++; | |
| 200 | + sw |= tmp >> delta; | |
| 201 | + }else{ | |
| 202 | + sw = tmp << delta; | |
| 203 | + tmp = *s++; | |
| 204 | + if(delta) | |
| 205 | + sw |= tmp >> (WBITS-delta); | |
| 206 | + } | |
| 207 | + spare = 1 << deltadep; | |
| 208 | + if(deltadep >= 1){ | |
| 209 | + gbitexplode(sw, buf, sdep, deltadep); | |
| 210 | + p = buf; | |
| 211 | + sw = *p++; | |
| 212 | + } | |
| 213 | + } | |
| 214 | + | |
| 215 | + dw = *d; | |
| 216 | + switch(fcode){ /* ltor bit aligned */ | |
| 217 | + case Zero: *d = dw & ~mask; break; | |
| 218 | + case DnorS: *d = dw ^ ((~sw | dw) & mask); break; | |
| 219 | + case DandnotS: *d = dw ^ ((sw & dw) & mask); break; | |
| 220 | + case notS: *d = dw ^ ((~sw ^ dw) & mask); break; | |
| 221 | + case notDandS: *d = dw ^ ((sw | dw) & mask); break; | |
| 222 | + case notD: *d = dw ^ mask; break; | |
| 223 | + case DxorS: *d = dw ^ (sw & mask); break; | |
| 224 | + case DnandS: *d = dw ^ ((sw | ~dw) & mask); break; | |
| 225 | + case DandS: *d = dw ^ ((~sw & dw) & mask); break; | |
| 226 | + case DxnorS: *d = dw ^ (~sw & mask); break; | |
| 227 | + case D: break; | |
| 228 | + case DornotS: *d = dw | (~sw & mask); break; | |
| 229 | + case S: *d = dw ^ ((sw ^ dw) & mask); break; | |
| 230 | + case notDorS: *d = dw ^ (~(sw & dw) & mask); break; | |
| 231 | + case DorS: *d = dw | (sw & mask); break; | |
| 232 | + case F: *d = dw | mask; break; | |
| 233 | + } | |
| 234 | + d++; | |
| 235 | + | |
| 236 | + mask = WMASK; | |
| 237 | + if(i == 1) | |
| 238 | + mask = rmask; | |
| 239 | + spare--; | |
| 240 | + } | |
| 241 | + saddr += sspan; | |
| 242 | + daddr += dspan; | |
| 243 | + } | |
| 244 | +} | |
| 245 | + | |
| 246 | +#ifdef TEST | |
| 247 | +void prprog(void); | |
| 248 | +GBitmap *bb1, *bb2; | |
| 249 | +ulong *src, *dst, *xdst, *xans; | |
| 250 | +int swds, dwds; | |
| 251 | +long ticks; | |
| 252 | +int timeit; | |
| 253 | + | |
| 254 | +long | |
| 255 | +func(int f, long s, int sld, long d, int dld) | |
| 256 | +{ | |
| 257 | + long a; | |
| 258 | + int sh, i, db, sb; | |
| 259 | + | |
| 260 | + db = 1 << dld; | |
| 261 | + sb = 1 << sld; | |
| 262 | + sh = db - sb; | |
| 263 | + if(sh > 0) { | |
| 264 | + a = s; | |
| 265 | + for(i = sb; i<db; i += sb){ | |
| 266 | + a <<= sb; | |
| 267 | + s |= a; | |
| 268 | + } | |
| 269 | + } else if(sh < 0) | |
| 270 | + s >>= -sh; | |
| 271 | + | |
| 272 | + switch(f){ | |
| 273 | + case Zero: d = 0; break; | |
| 274 | + case DnorS: d = ~(d|s); break; | |
| 275 | + case DandnotS: d = d & ~s; break; | |
| 276 | + case notS: d = ~s; break; | |
| 277 | + case notDandS: d = ~d & s; break; | |
| 278 | + case notD: d = ~d; break; | |
| 279 | + case DxorS: d = d ^ s; break; | |
| 280 | + case DnandS: d = ~(d&s); break; | |
| 281 | + case DandS: d = d & s; break; | |
| 282 | + case DxnorS: d = ~(d^s); break; | |
| 283 | + case S: d = s; break; | |
| 284 | + case DornotS: d = d | ~s; break; | |
| 285 | + case D: d = d; break; | |
| 286 | + case notDorS: d = ~d | s; break; | |
| 287 | + case DorS: d = d | s; break; | |
| 288 | + case F: d = ~0; break; | |
| 289 | + } | |
| 290 | + | |
| 291 | + d &= ((1<<db)-1); | |
| 292 | + return d; | |
| 293 | +} | |
| 294 | + | |
| 295 | +void | |
| 296 | +run(int fr, int to, int w, int op) | |
| 297 | +{ | |
| 298 | + int i, j, f, t, fy, ty; | |
| 299 | + extern long *_clock; | |
| 300 | + | |
| 301 | + fr += bb2->r.min.x; | |
| 302 | + to += bb1->r.min.x; | |
| 303 | + fy = bb2->r.min.y + 1; | |
| 304 | + ty = bb1->r.min.y + 1; | |
| 305 | + if(timeit) { | |
| 306 | + memcpy(dst, xdst, dwds * sizeof(long)); | |
| 307 | + ticks -= *_clock; | |
| 308 | + gbitblt(bb1, Pt(to,ty), bb2, Rect(fr,fy,fr+w,fy+2), op); | |
| 309 | + ticks += *_clock; | |
| 310 | + return; | |
| 311 | + } | |
| 312 | + f = fr; | |
| 313 | + t = to; | |
| 314 | + memcpy(dst, xdst, dwds * sizeof(long)); | |
| 315 | + for(i=0; i<w; i++) { | |
| 316 | + gbitblt(bb1, Pt(t,ty), bb2, Rect(f,fy,f+1,fy+1), op); | |
| 317 | + gbitblt(bb1, Pt(t,ty+1), bb2, Rect(f,fy+1,f+1,fy+2), op); | |
| 318 | + f++; | |
| 319 | + t++; | |
| 320 | + } | |
| 321 | + memcpy(xans, dst, dwds * sizeof(long)); | |
| 322 | + | |
| 323 | + memcpy(dst, xdst, dwds * sizeof(long)); | |
| 324 | + gbitblt(bb1, Pt(to,ty), bb2, Rect(fr,fy,fr+w,fy+2), op); | |
| 325 | + | |
| 326 | + if(memcmp(xans, dst, dwds * sizeof(long))) { | |
| 327 | + /* | |
| 328 | + * print src and dst row offset, width in bits, and forw/back | |
| 329 | + * then print for each of the four rows: the source (s), | |
| 330 | + * the dest (d), the good value of the answer (g), | |
| 331 | + * and the actual bad value of the answer (b) | |
| 332 | + */ | |
| 333 | + print("fr=%d to=%d w=%d fb=%d%d\n", | |
| 334 | + fr, to, w, FORCEFORW, FORCEBAKW); | |
| 335 | + print("dst bitmap b %#lux, z %d, w %d, ld %d, r [%d,%d][%d,%d]\n", | |
| 336 | + bb1->base, bb1->zero, bb1->width, bb1->ldepth, | |
| 337 | + bb1->r.min.x, bb1->r.min.y, bb1->r.max.x, bb1->r.max.y); | |
| 338 | + print("src bitmap b %#lux, z %d, w %d, ld %d, r [%d,%d][%d,%d]\n", | |
| 339 | + bb2->base, bb2->zero, bb2->width, bb2->ldepth, | |
| 340 | + bb2->r.min.x, bb2->r.min.y, bb2->r.max.x, bb2->r.max.y); | |
| 341 | + for(j=0; 7*j < dwds; j++) { | |
| 342 | + print("\ns"); | |
| 343 | + for(i=0; i<7 && 7*j+i < dwds; i++) | |
| 344 | + print(" %.8lux", src[7*j + i]); | |
| 345 | + print("\nd"); | |
| 346 | + for(i=0; i<7 && 7*j+i < dwds; i++) | |
| 347 | + print(" %.8lux", xdst[7*j + i]); | |
| 348 | + print("\ng"); | |
| 349 | + for(i=0; i<7 && 7*j+i < dwds; i++) | |
| 350 | + print(" %.8lux", xans[7*j + i]); | |
| 351 | + print("\nb"); | |
| 352 | + for(i=0; i<7 && 7*j+i < dwds; i++) | |
| 353 | + print(" %.8lux", dst[7*j + i]); | |
| 354 | + print("\n"); | |
| 355 | + } | |
| 356 | + prprog(); | |
| 357 | + } | |
| 358 | +} | |
| 359 | + | |
| 360 | +void | |
| 361 | +prprog(void) | |
| 362 | +{ | |
| 363 | + exits(0); | |
| 364 | +} | |
| 365 | + | |
| 366 | +int | |
| 367 | +main(int argc, char *argv[]) | |
| 368 | +{ | |
| 369 | + int f, t, w, i, sld, dld, op, iters, simple; | |
| 370 | + ulong s, d, spix, dpix, apix, fpix, m, *ps, *pd; | |
| 371 | + Point sorg, dorg; | |
| 372 | + GBitmap *bs, *bd; | |
| 373 | + long seed; | |
| 374 | + char *ct; | |
| 375 | + | |
| 376 | + sld = 0; | |
| 377 | + dld = 0; | |
| 378 | + timeit = 0; | |
| 379 | + iters = 200; | |
| 380 | + simple = 0; | |
| 381 | + ARGBEGIN { | |
| 382 | + case 'i': | |
| 383 | + iters = atoi(ARGF()); | |
| 384 | + break; | |
| 385 | + case 's': | |
| 386 | + simple = 1; | |
| 387 | + break; | |
| 388 | + case 't': | |
| 389 | + timeit = 1; | |
| 390 | + ct = ARGF(); | |
| 391 | + if(ct) | |
| 392 | + iters = atoi(ct); | |
| 393 | + break; | |
| 394 | + } ARGEND | |
| 395 | + if(argc > 0) | |
| 396 | + sld = atoi(argv[0]); | |
| 397 | + if(argc > 1) | |
| 398 | + dld = atoi(argv[1]); | |
| 399 | + if(!timeit && !simple) { | |
| 400 | + seed = time(0); | |
| 401 | + print("seed %lux\n", seed); srand(seed); /**/ | |
| 402 | + } | |
| 403 | + | |
| 404 | + print("sld %d dld %d\n", sld, dld); | |
| 405 | + op = 1; | |
| 406 | + | |
| 407 | + /* bitmaps for 1-bit tests */ | |
| 408 | + bd = gballoc(Rect(0,0,32,1), dld); | |
| 409 | + bs = gballoc(Rect(0,0,32,1), sld); | |
| 410 | + for(i=0; i<bs->width; i++) | |
| 411 | + bs->base[i] = lrand(); | |
| 412 | + | |
| 413 | + /* bitmaps for rect tests */ | |
| 414 | + if(simple) { | |
| 415 | + dorg = Pt(0,0); | |
| 416 | + sorg = Pt(0,0); | |
| 417 | + } else { | |
| 418 | + dorg = Pt(nrand(63)-31,nrand(63)-31); | |
| 419 | + sorg = Pt(nrand(63)-31,nrand(63)-31); | |
| 420 | + } | |
| 421 | + bb1 = gballoc(Rpt(dorg,add(dorg,Pt(200,4))), dld); | |
| 422 | + bb2 = gballoc(Rpt(sorg,add(sorg,Pt(200,4))), sld); | |
| 423 | + dwds = bb1->width * Dy(bb1->r); | |
| 424 | + swds = bb2->width * Dy(bb2->r); | |
| 425 | + dst = bb1->base; | |
| 426 | + src = bb2->base; | |
| 427 | + xdst = malloc(dwds * sizeof(long)); | |
| 428 | + xans = malloc(dwds * sizeof(long)); | |
| 429 | + for(i=0; i<swds; i++) | |
| 430 | + src[i] = lrand(); | |
| 431 | + for(i=0; i<dwds; i++) | |
| 432 | + xdst[i] = lrand(); | |
| 433 | + | |
| 434 | +loop: | |
| 435 | + print("Op %d\n", op); | |
| 436 | + if(!timeit) { | |
| 437 | + print("one pixel\n"); | |
| 438 | + ps = bs->base; | |
| 439 | + pd = bd->base; | |
| 440 | + FORCEFORW = 1; | |
| 441 | + FORCEBAKW = 0; | |
| 442 | + for(i=0; i<1000; i++, FORCEFORW = !FORCEFORW, FORCEBAKW = !FORCEBAKW) { | |
| 443 | + f = nrand(32 >> sld); | |
| 444 | + t = nrand(32 >> dld); | |
| 445 | + s = lrand(); | |
| 446 | + d = lrand(); | |
| 447 | + ps[0] = s; | |
| 448 | + pd[0] = d; | |
| 449 | +#ifdef T386 | |
| 450 | + spix = (byterev(s) >> (32 - ((f+1)<<sld))) & ((1 << (1<<sld)) - 1); | |
| 451 | + dpix = (byterev(d) >> (32 - ((t+1)<<dld))) & ((1 << (1<<dld)) - 1); | |
| 452 | +#else | |
| 453 | + spix = (s >> (32 - ((f+1)<<sld))) & ((1 << (1<<sld)) - 1); | |
| 454 | + dpix = (d >> (32 - ((t+1)<<dld))) & ((1 << (1<<dld)) - 1); | |
| 455 | +#endif | |
| 456 | +#ifdef T386 | |
| 457 | + apix = byterev(func(op, spix, sld, dpix, dld) << (32 - ((t+1)<<dld))); | |
| 458 | +#else | |
| 459 | + apix = func(op, spix, sld, dpix, dld) << (32 - ((t+1)<<dld)); | |
| 460 | +#endif | |
| 461 | + gbitblt(bd, Pt(t,0), bs, Rect(f,0,f+1,1), op); | |
| 462 | + if(ps[0] != s) { | |
| 463 | + print("bb src %.8lux %.8lux %d %d\n", ps[0], s, f, t); | |
| 464 | + exits("error"); | |
| 465 | + } | |
| 466 | + m = ((1 << (1<<dld)) - 1) << (32 - ((t+1)<<dld)); | |
| 467 | +#ifdef T386 | |
| 468 | + m = byterev(m); | |
| 469 | +#endif | |
| 470 | + if((pd[0] & ~m) != (d & ~m)) { | |
| 471 | + print("bb dst1 %.8lux %.8lux\n", | |
| 472 | + s, d); | |
| 473 | + print("bb %.8lux %.8lux %d %d\n", | |
| 474 | + ps[0], pd[0], f, t); | |
| 475 | + prprog(); | |
| 476 | + exits("error"); | |
| 477 | + } | |
| 478 | + if((pd[0] & m) != apix) { | |
| 479 | + spix <<= 32 - ((f+1)<<sld); | |
| 480 | + dpix <<= 32 - ((t+1)<<dld); | |
| 481 | +#ifdef T386 | |
| 482 | + spix = byterev(spix); | |
| 483 | + dpix = byterev(dpix); | |
| 484 | +#endif | |
| 485 | + print("bb dst2 %.8lux %.8lux\n", | |
| 486 | + s, d); | |
| 487 | + print("bb %.8lux %.8lux %d %d\n", | |
| 488 | + ps[0], pd[0], f, t); | |
| 489 | + print("bb %.8lux %.8lux %.8lux %.8lux\n", | |
| 490 | + spix, dpix, apix, pd[0] & m); | |
| 491 | + prprog(); | |
| 492 | + exits("error"); | |
| 493 | + } | |
| 494 | + } | |
| 495 | + } | |
| 496 | + | |
| 497 | + print("for\n"); | |
| 498 | + FORCEFORW = 1; | |
| 499 | + FORCEBAKW = 0; | |
| 500 | + | |
| 501 | + for(i=0; i<iters; i++) { | |
| 502 | + f = nrand(64); | |
| 503 | + t = nrand(64); | |
| 504 | + w = nrand(130); | |
| 505 | + run(f, t, w, op); | |
| 506 | + } | |
| 507 | + | |
| 508 | + if(sld == dld) { | |
| 509 | + print("bak\n"); | |
| 510 | + FORCEFORW = 0; | |
| 511 | + FORCEBAKW = 1; | |
| 512 | + | |
| 513 | + for(i=0; i<iters; i++) { | |
| 514 | + f = nrand(64); | |
| 515 | + t = nrand(64); | |
| 516 | + w = nrand(130); | |
| 517 | + run(f, t, w, op); | |
| 518 | + } | |
| 519 | + } | |
| 520 | + | |
| 521 | + if(op < F) { | |
| 522 | + op++; | |
| 523 | + goto loop; | |
| 524 | + } | |
| 525 | + if(timeit) | |
| 526 | + print("time: %d ticks\n", ticks); | |
| 527 | + exits(0); | |
| 528 | +} | |
| 529 | + | |
| 530 | + | |
| 531 | +#endif | |
| @@ -0,0 +1,212 @@ | ||
| 1 | +#include "boot.h" | |
| 2 | + | |
| 3 | +typedef struct Flashdev Flashdev; | |
| 4 | +struct Flashdev { | |
| 5 | + uchar* base; | |
| 6 | + int size; | |
| 7 | + uchar* exec; | |
| 8 | + char* config; | |
| 9 | + int conflen; | |
| 10 | +}; | |
| 11 | + | |
| 12 | +enum { | |
| 13 | + FLASHSEG = 256*1024, | |
| 14 | + CONFIGLIM = FLASHSEG, | |
| 15 | + BOOTOFF = FLASHSEG, | |
| 16 | + BOOTLEN = 3*FLASHSEG, /* third segment might be filsys */ | |
| 17 | + /* rest of flash is free */ | |
| 18 | +}; | |
| 19 | + | |
| 20 | +static Flashdev flash; | |
| 21 | + | |
| 22 | +/* | |
| 23 | + * configuration data is written between the bootstrap and | |
| 24 | + * the end of region 0. the region ends with allocation descriptors | |
| 25 | + * of the following form: | |
| 26 | + * | |
| 27 | + * byte order is big endian | |
| 28 | + * | |
| 29 | + * the last valid region found that starts with the string "#plan9.ini\n" is plan9.ini | |
| 30 | + */ | |
| 31 | +typedef struct Flalloc Flalloc; | |
| 32 | +struct Flalloc { | |
| 33 | + ulong check; /* checksum of data, or ~0 */ | |
| 34 | + ulong base; /* base of region; ~0 if unallocated, 0 if deleted */ | |
| 35 | + uchar len[3]; | |
| 36 | + uchar tag; /* see below */ | |
| 37 | + uchar sig[4]; | |
| 38 | +}; | |
| 39 | + | |
| 40 | +enum { | |
| 41 | + /* tags */ | |
| 42 | + Tdead= 0, | |
| 43 | + Tboot= 0x01, /* space reserved for boot */ | |
| 44 | + Tconf= 0x02, /* configuration data */ | |
| 45 | + Tnone= 0xFF, | |
| 46 | + | |
| 47 | + Noval= ~0, | |
| 48 | +}; | |
| 49 | + | |
| 50 | +static char flashsig[] = {0xF1, 0xA5, 0x5A, 0x1F}; | |
| 51 | +static char conftag[] = "#plan9.ini\n"; | |
| 52 | + | |
| 53 | +static ulong | |
| 54 | +checksum(uchar* p, int n) | |
| 55 | +{ | |
| 56 | + ulong s; | |
| 57 | + | |
| 58 | + for(s=0; --n >= 0;) | |
| 59 | + s += *p++; | |
| 60 | + return s; | |
| 61 | +} | |
| 62 | + | |
| 63 | +static int | |
| 64 | +validptr(Flalloc *ap, uchar *p) | |
| 65 | +{ | |
| 66 | + return p > (uchar*)&end && p < (uchar*)ap; | |
| 67 | +} | |
| 68 | + | |
| 69 | +static int | |
| 70 | +flashcheck(Flalloc *ap, char **val, int *len) | |
| 71 | +{ | |
| 72 | + uchar *base; | |
| 73 | + int n; | |
| 74 | + | |
| 75 | + if(ap->base == Noval || ap->base >= FLASHSEG || ap->tag == Tnone) | |
| 76 | + return 0; | |
| 77 | + base = flash.base+ap->base; | |
| 78 | + if(!validptr(ap, base)) | |
| 79 | + return 0; | |
| 80 | + n = (((ap->len[0]<<8)|ap->len[1])<<8)|ap->len[2]; | |
| 81 | + if(n == 0xFFFFFF) | |
| 82 | + n = 0; | |
| 83 | + if(n < 0) | |
| 84 | + return 0; | |
| 85 | + if(n > 0 && !validptr(ap, base+n-1)) | |
| 86 | + return 0; | |
| 87 | + if(ap->check != Noval && checksum(base, n) != ap->check){ | |
| 88 | + print("flash: bad checksum\n"); | |
| 89 | + return 0; | |
| 90 | + } | |
| 91 | + *val = (char*)base; | |
| 92 | + *len = n; | |
| 93 | + return 1; | |
| 94 | +} | |
| 95 | + | |
| 96 | +int | |
| 97 | +flashinit(void) | |
| 98 | +{ | |
| 99 | + int len; | |
| 100 | + char *val; | |
| 101 | + Flalloc *ap; | |
| 102 | + void *addr; | |
| 103 | + long mbytes; | |
| 104 | + char type[20]; | |
| 105 | + | |
| 106 | + flash.base = 0; | |
| 107 | + flash.exec = 0; | |
| 108 | + flash.size = 0; | |
| 109 | + if(archflashreset(type, &addr, &mbytes) < 0){ | |
| 110 | + print("flash: flash not present or not enabled\n"); /* shouldn't happen */ | |
| 111 | + return 0; | |
| 112 | + } | |
| 113 | + flash.size = mbytes; | |
| 114 | + flash.base = addr; | |
| 115 | + flash.exec = flash.base + BOOTOFF; | |
| 116 | + flash.config = nil; | |
| 117 | + flash.conflen = 0; | |
| 118 | + | |
| 119 | + for(ap = (Flalloc*)(flash.base+CONFIGLIM)-1; memcmp(ap->sig, flashsig, 4) == 0; ap--){ | |
| 120 | + if(0) | |
| 121 | + print("conf #%8.8lux: #%x #%6.6lux\n", ap, ap->tag, ap->base); | |
| 122 | + if(ap->tag == Tconf && | |
| 123 | + flashcheck(ap, &val, &len) && | |
| 124 | + len >= sizeof(conftag)-1 && | |
| 125 | + memcmp(val, conftag, sizeof(conftag)-1) == 0){ | |
| 126 | + flash.config = val; | |
| 127 | + flash.conflen = len; | |
| 128 | + if(0) | |
| 129 | + print("flash: found config %8.8lux(%d):\n%s\n", val, len, val); | |
| 130 | + } | |
| 131 | + } | |
| 132 | + if(flash.config == nil) | |
| 133 | + print("flash: no config\n"); | |
| 134 | + else | |
| 135 | + print("flash config %8.8lux(%d):\n%s\n", flash.config, flash.conflen, flash.config); | |
| 136 | + if(issqueezed(flash.exec) == Q_MAGIC){ | |
| 137 | + print("flash: squeezed powerpc kernel installed\n"); | |
| 138 | + return 1<<0; | |
| 139 | + } | |
| 140 | + if(GLLONG(flash.exec) == Q_MAGIC){ | |
| 141 | + print("flash: unsqueezed powerpc kernel installed\n"); | |
| 142 | + return 1<<0; | |
| 143 | + } | |
| 144 | + flash.exec = 0; | |
| 145 | + print("flash: no powerpc kernel in Flash\n"); | |
| 146 | + return 0; | |
| 147 | +} | |
| 148 | + | |
| 149 | +char* | |
| 150 | +flashconfig(int) | |
| 151 | +{ | |
| 152 | + return flash.config; | |
| 153 | +} | |
| 154 | + | |
| 155 | +int | |
| 156 | +flashbootable(int) | |
| 157 | +{ | |
| 158 | + return flash.exec != nil && (issqueezed(flash.exec) || GLLONG(flash.exec) == Q_MAGIC); | |
| 159 | +} | |
| 160 | + | |
| 161 | +int | |
| 162 | +flashboot(int) | |
| 163 | +{ | |
| 164 | + ulong entry, addr; | |
| 165 | + void (*b)(void); | |
| 166 | + Exec *ep; | |
| 167 | + Block in; | |
| 168 | + long n; | |
| 169 | + uchar *p; | |
| 170 | + | |
| 171 | + if(flash.exec == 0) | |
| 172 | + return -1; | |
| 173 | + p = flash.exec; | |
| 174 | + if(GLLONG(p) == Q_MAGIC){ | |
| 175 | + /* unsqueezed: copy data and perhaps text, then jump to it */ | |
| 176 | + ep = (Exec*)p; | |
| 177 | + entry = PADDR(GLLONG(ep->entry)); | |
| 178 | + p += sizeof(Exec); | |
| 179 | + addr = entry; | |
| 180 | + n = GLLONG(ep->text); | |
| 181 | + if(addr != (ulong)p){ | |
| 182 | + memmove((void*)addr, p, n); | |
| 183 | + print("text: %8.8lux <- %8.8lux [%ld]\n", addr, p, n); | |
| 184 | + } | |
| 185 | + p += n; | |
| 186 | + if(entry >= FLASHMEM) | |
| 187 | + addr = 3*BY2PG; /* kernel text is in Flash, data in RAM */ | |
| 188 | + else | |
| 189 | + addr = PGROUND(addr+n); | |
| 190 | + n = GLLONG(ep->data); | |
| 191 | + memmove((void*)addr, p, n); | |
| 192 | + print("data: %8.8lux <- %8.8lux [%ld]\n", addr, p, n); | |
| 193 | + }else{ | |
| 194 | + in.data = p; | |
| 195 | + in.rp = in.data; | |
| 196 | + in.lim = p+BOOTLEN; | |
| 197 | + in.wp = in.lim; | |
| 198 | + n = unsqueezef(&in, &entry); | |
| 199 | + if(n < 0) | |
| 200 | + return -1; | |
| 201 | + } | |
| 202 | + print("entry=0x%lux\n", entry); | |
| 203 | + uartwait(); | |
| 204 | + scc2stop(); | |
| 205 | + /* | |
| 206 | + * Go to new code. It's up to the program to get its PC relocated to | |
| 207 | + * the right place. | |
| 208 | + */ | |
| 209 | + b = (void (*)(void))KADDR(PADDR(entry)); | |
| 210 | + (*b)(); | |
| 211 | + return -1; | |
| 212 | +} | |
| @@ -0,0 +1,117 @@ | ||
| 1 | +Alarm* alarm(int, void (*)(Alarm*), void*); | |
| 2 | +void alarminit(void); | |
| 3 | +void archbacklight(int); | |
| 4 | +char* archconfig(void); | |
| 5 | +void archdisableuart(int); | |
| 6 | +void archenableuart(int, int); | |
| 7 | +void archenableusb(int); | |
| 8 | +void archetherdisable(int); | |
| 9 | +int archetherenable(int, int*, int*); | |
| 10 | +int archflashreset(char*, void**, long*); | |
| 11 | +void archinit(void); | |
| 12 | +int archoptionsw(void); | |
| 13 | +int bootp(int, char*); | |
| 14 | +void cancel(Alarm*); | |
| 15 | +void checkalarms(void); | |
| 16 | +void clockinit(void); | |
| 17 | +void clockintr(Ureg*, void*); | |
| 18 | +void consinit(void); | |
| 19 | +void cpminit(void); | |
| 20 | +void cpuidprint(void); | |
| 21 | +#define dcflush(a,b) | |
| 22 | +void delay(int); | |
| 23 | +void eieio(void); | |
| 24 | +uchar* etheraddr(int); | |
| 25 | +int etherinit(void); | |
| 26 | +int etherrxpkt(int, Etherpkt*, int); | |
| 27 | +int ethertxpkt(int, Etherpkt*, int, int); | |
| 28 | +void exception(void); | |
| 29 | +int flashboot(int); | |
| 30 | +int flashbootable(int); | |
| 31 | +char* flashconfig(int); | |
| 32 | +int flashinit(void); | |
| 33 | +void free(void*); | |
| 34 | +void freeb(Block*); | |
| 35 | +int getcfields(char*, char**, int, char*); | |
| 36 | +char* getconf(char*); | |
| 37 | +ulong getdec(void); | |
| 38 | +ulong gethid0(void); | |
| 39 | +ulong getimmr(void); | |
| 40 | +ulong getmsr(void); | |
| 41 | +ulong getpvr(void); | |
| 42 | +int getstr(char*, char*, int, char*); | |
| 43 | +ulong gettbl(void); | |
| 44 | +ulong gettbu(void); | |
| 45 | +int hardinit(void); | |
| 46 | +long hardread(int, void*, long); | |
| 47 | +long hardseek(int, long); | |
| 48 | +long hardwrite(int, void*, long); | |
| 49 | +long i2csend(int, void*, long); | |
| 50 | +void i2csetup(void); | |
| 51 | +void* ialloc(ulong, int); | |
| 52 | +Block* iallocb(int); | |
| 53 | +void idle(void); | |
| 54 | +int isaconfig(char*, int, ISAConf*); | |
| 55 | +int issqueezed(uchar*); | |
| 56 | +void kbdchar(Queue*, int); | |
| 57 | +void kbdinit(void); | |
| 58 | +void kbdreset(void); | |
| 59 | +void machinit(void); | |
| 60 | +void* malloc(ulong); | |
| 61 | +ulong mapalloc(RMap*, ulong, int, int); | |
| 62 | +void mapfree(RMap*, ulong, int); | |
| 63 | +void mapinit(RMap*, Map*, int); | |
| 64 | +void meminit(void); | |
| 65 | +void microdelay(int); | |
| 66 | +void mmuinit(void); | |
| 67 | +int optionsw(void); | |
| 68 | +void panic(char*, ...); | |
| 69 | +int parseether(uchar*, char*); | |
| 70 | +int plan9boot(int, long (*)(int, long), long (*)(int, void*, long)); | |
| 71 | +void putdec(ulong); | |
| 72 | +void puthid0(ulong); | |
| 73 | +void putmsr(ulong); | |
| 74 | +int qbgetc(Queue*); | |
| 75 | +void qbputc(Queue*, int); | |
| 76 | +void qbwrite(Queue*, Block*); | |
| 77 | +Block* qget(Queue*); | |
| 78 | +long qlen(Queue*); | |
| 79 | +Queue* qopen(int, int, void (*)(void*), void*); | |
| 80 | +#define qpass qbwrite | |
| 81 | +void scc2stop(void); | |
| 82 | +void sccnmsi(int, int, int); | |
| 83 | +void sched(void); | |
| 84 | +void screeninit(void); | |
| 85 | +void screenputs(char*, int); | |
| 86 | +void sdraminit(ulong); | |
| 87 | +Partition* sethardpart(int, char*); | |
| 88 | +Partition* setscsipart(int, char*); | |
| 89 | +void setvec(int, void (*)(Ureg*, void*), void*); | |
| 90 | +int splhi(void); | |
| 91 | +int spllo(void); | |
| 92 | +void splx(int); | |
| 93 | +void trapinit(void); | |
| 94 | +void uartputs(char*, int); | |
| 95 | +void uartsetboot(void (*f)(uchar*, int)); | |
| 96 | +void uartspecial(int, int, Queue**, Queue**, void(*)(Queue*,int)); | |
| 97 | +void uartwait(void); | |
| 98 | +long unsqueezef(Block*, ulong*); | |
| 99 | + | |
| 100 | +#define GSHORT(p) (((p)[1]<<8)|(p)[0]) | |
| 101 | +#define GLONG(p) ((GSHORT(p+2)<<16)|GSHORT(p)) | |
| 102 | +#define GLSHORT(p) (((p)[0]<<8)|(p)[1]) | |
| 103 | +#define GLLONG(p) ((GLSHORT(p)<<16)|GLSHORT(p+2)) | |
| 104 | + | |
| 105 | +#define KADDR(a) ((void*)((ulong)(a)|KZERO)) | |
| 106 | +#define PADDR(a) ((ulong)(a)&~KSEGM) | |
| 107 | + | |
| 108 | +/* IBM bit field order */ | |
| 109 | +#define IBIT(b) ((ulong)1<<(31-(b))) | |
| 110 | +#define SIBIT(n) ((ushort)1<<(15-(n))) | |
| 111 | + | |
| 112 | +#define IOREGS(x, T) ((T*)((char*)m->iomem+(x))) | |
| 113 | + | |
| 114 | +int uartinit(void); | |
| 115 | +Partition* setuartpart(int, char*); | |
| 116 | +long uartread(int, void*, long); | |
| 117 | +long uartseek(int, long); | |
| @@ -0,0 +1,52 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <libg.h> | |
| 4 | +#include <gnot.h> | |
| 5 | + | |
| 6 | +void | |
| 7 | +gbitbltclip(void *vp) | |
| 8 | +{ | |
| 9 | + int dx, dy; | |
| 10 | + int i; | |
| 11 | + struct{ | |
| 12 | + GBitmap *dm; | |
| 13 | + Point p; | |
| 14 | + GBitmap *sm; | |
| 15 | + Rectangle r; | |
| 16 | + Fcode f; | |
| 17 | + }*bp; | |
| 18 | + | |
| 19 | + bp = vp; | |
| 20 | + dx = Dx(bp->r); | |
| 21 | + dy = Dy(bp->r); | |
| 22 | + if(bp->p.x < bp->dm->clipr.min.x){ | |
| 23 | + i = bp->dm->clipr.min.x-bp->p.x; | |
| 24 | + bp->r.min.x += i; | |
| 25 | + bp->p.x += i; | |
| 26 | + dx -= i; | |
| 27 | + } | |
| 28 | + if(bp->p.y < bp->dm->clipr.min.y){ | |
| 29 | + i = bp->dm->clipr.min.y-bp->p.y; | |
| 30 | + bp->r.min.y += i; | |
| 31 | + bp->p.y += i; | |
| 32 | + dy -= i; | |
| 33 | + } | |
| 34 | + if(bp->p.x+dx > bp->dm->clipr.max.x) | |
| 35 | + bp->r.max.x -= bp->p.x+dx-bp->dm->clipr.max.x; | |
| 36 | + if(bp->p.y+dy > bp->dm->clipr.max.y) | |
| 37 | + bp->r.max.y -= bp->p.y+dy-bp->dm->clipr.max.y; | |
| 38 | + if(bp->r.min.x < bp->sm->clipr.min.x){ | |
| 39 | + i = bp->sm->clipr.min.x-bp->r.min.x; | |
| 40 | + bp->p.x += i; | |
| 41 | + bp->r.min.x += i; | |
| 42 | + } | |
| 43 | + if(bp->r.min.y < bp->sm->clipr.min.y){ | |
| 44 | + i = bp->sm->clipr.min.y-bp->r.min.y; | |
| 45 | + bp->p.y += i; | |
| 46 | + bp->r.min.y += i; | |
| 47 | + } | |
| 48 | + if(bp->r.max.x > bp->sm->clipr.max.x) | |
| 49 | + bp->r.max.x = bp->sm->clipr.max.x; | |
| 50 | + if(bp->r.max.y > bp->sm->clipr.max.y) | |
| 51 | + bp->r.max.y = bp->sm->clipr.max.y; | |
| 52 | +} | |
| @@ -0,0 +1,71 @@ | ||
| 1 | + | |
| 2 | +extern void *bbmalloc(int); | |
| 3 | +extern void bbfree(void *, int); | |
| 4 | +extern int bbonstack(void); | |
| 5 | +extern void bbexec(void(*)(void), int, int); | |
| 6 | + | |
| 7 | +/* | |
| 8 | + * Graphics types | |
| 9 | + */ | |
| 10 | + | |
| 11 | +typedef struct GBitmap GBitmap; | |
| 12 | +typedef struct GFont GFont; | |
| 13 | +typedef struct GSubfont GSubfont; | |
| 14 | +typedef struct GCacheinfo GCacheinfo; | |
| 15 | + | |
| 16 | +struct GBitmap | |
| 17 | +{ | |
| 18 | + ulong *base; /* pointer to start of data */ | |
| 19 | + long zero; /* base+zero=&word containing (0,0) */ | |
| 20 | + ulong width; /* width in 32 bit words of total data area */ | |
| 21 | + int ldepth; /* log base 2 of number of bits per pixel */ | |
| 22 | + Rectangle r; /* rectangle in data area, local coords */ | |
| 23 | + Rectangle clipr; /* clipping region */ | |
| 24 | + GBitmap *cache; /* zero; distinguishes bitmap from layer */ | |
| 25 | +}; | |
| 26 | + | |
| 27 | + | |
| 28 | +/* | |
| 29 | + * GFont etc. are not used in the library, only in devbit.c. | |
| 30 | + * GSubfont is only barely used. | |
| 31 | + */ | |
| 32 | +struct GSubfont | |
| 33 | +{ | |
| 34 | + short n; /* number of chars in font */ | |
| 35 | + char height; /* height of bitmap */ | |
| 36 | + char ascent; /* top of bitmap to baseline */ | |
| 37 | + Fontchar *info; /* n+1 character descriptors */ | |
| 38 | + GBitmap *bits; /* where the characters are */ | |
| 39 | +}; | |
| 40 | +struct GCacheinfo | |
| 41 | +{ | |
| 42 | + ulong xright; /* right edge of bits */ | |
| 43 | + Fontchar; | |
| 44 | +}; | |
| 45 | + | |
| 46 | +struct GFont | |
| 47 | +{ | |
| 48 | + uchar height; /* max height of bitmap, interline spacing */ | |
| 49 | + char ascent; /* top of bitmap to baseline */ | |
| 50 | + char width; /* widest so far; used in caching only */ | |
| 51 | + char ldepth; /* of images */ | |
| 52 | + short id; /* of font */ | |
| 53 | + int ncache; /* number of entries in cache */ | |
| 54 | + GCacheinfo *cache; /* cached characters */ | |
| 55 | + GBitmap *b; /* cached images */ | |
| 56 | +}; | |
| 57 | + | |
| 58 | +extern ulong *gaddr(GBitmap*, Point); | |
| 59 | +extern uchar *gbaddr(GBitmap*, Point); | |
| 60 | +extern void gbitblt(GBitmap*, Point, GBitmap*, Rectangle, Fcode); | |
| 61 | +extern void gbitbltclip(void*); | |
| 62 | +extern void gtexture(GBitmap*, Rectangle, GBitmap*, Fcode); | |
| 63 | +extern Point gsubfstrsize(GSubfont*, char*); | |
| 64 | +extern int gsubfstrwidth(GSubfont*, char*); | |
| 65 | +extern Point gsubfstring(GBitmap*, Point, GSubfont*, char*, Fcode); | |
| 66 | +extern Point gbitbltstring(GBitmap*, Point, GSubfont*, char*, Fcode); | |
| 67 | +extern void gsegment(GBitmap*, Point, Point, int, Fcode); | |
| 68 | +extern void gpoint(GBitmap*, Point, int, Fcode); | |
| 69 | +extern void gflushcpucache(void); | |
| 70 | +extern GBitmap* gballoc(Rectangle, int); | |
| 71 | +extern void gbfree(GBitmap*); | |
| @@ -0,0 +1,351 @@ | ||
| 1 | +#include "boot.h" | |
| 2 | + | |
| 3 | +/* | |
| 4 | + * basic read/write interface to mpc8xx I2C bus (master mode) | |
| 5 | + */ | |
| 6 | + | |
| 7 | +typedef struct I2C I2C; | |
| 8 | + | |
| 9 | +struct I2C { | |
| 10 | + uchar i2mod; | |
| 11 | + uchar rsv12a[3]; | |
| 12 | + uchar i2add; | |
| 13 | + uchar rsv12b[3]; | |
| 14 | + uchar i2brg; | |
| 15 | + uchar rsv12c[3]; | |
| 16 | + uchar i2com; | |
| 17 | + uchar rsv12d[3]; | |
| 18 | + uchar i2cer; | |
| 19 | + uchar rsv12e[3]; | |
| 20 | + uchar i2cmr; | |
| 21 | +}; | |
| 22 | + | |
| 23 | +enum { | |
| 24 | + /* i2c-specific BD flags */ | |
| 25 | + RxeOV= 1<<1, /* overrun */ | |
| 26 | + TxS= 1<<10, /* transmit start condition */ | |
| 27 | + TxeNAK= 1<<2, /* last transmitted byte not acknowledged */ | |
| 28 | + TxeUN= 1<<1, /* underflow */ | |
| 29 | + TxeCL= 1<<0, /* collision */ | |
| 30 | + TxERR= (TxeNAK|TxeUN|TxeCL), | |
| 31 | + | |
| 32 | + /* i2cmod */ | |
| 33 | + REVD= 1<<5, /* =1, LSB first */ | |
| 34 | + GCD= 1<<4, /* =1, general call address disabled */ | |
| 35 | + FLT= 1<<3, /* =0, not filtered; =1, filtered */ | |
| 36 | + PDIV= 3<<1, /* predivisor field */ | |
| 37 | + EN= 1<<0, /* enable */ | |
| 38 | + | |
| 39 | + /* i2com */ | |
| 40 | + STR= 1<<7, /* start transmit */ | |
| 41 | + I2CM= 1<<0, /* master */ | |
| 42 | + I2CS= 0<<0, /* slave */ | |
| 43 | + | |
| 44 | + /* i2cer */ | |
| 45 | + TXE = 1<<4, | |
| 46 | + BSY = 1<<2, | |
| 47 | + TXB = 1<<1, | |
| 48 | + RXB = 1<<0, | |
| 49 | + | |
| 50 | + /* port B bits */ | |
| 51 | + I2CSDA = IBIT(27), | |
| 52 | + I2CSCL = IBIT(26), | |
| 53 | + | |
| 54 | + Rbit = 1<<0, /* bit in address byte denoting read */ | |
| 55 | + | |
| 56 | + /* maximum I2C I/O (can change) */ | |
| 57 | + Bufsize = 64, | |
| 58 | + Tbuflen= Bufsize+4, /* extra address bytes and alignment */ | |
| 59 | + Freq = 100000, | |
| 60 | + I2CTimeout = 250, /* msec */ | |
| 61 | +}; | |
| 62 | + | |
| 63 | +/* data cache needn't be flushed if buffers allocated in uncached INTMEM */ | |
| 64 | +#define DCFLUSH(a,n) | |
| 65 | + | |
| 66 | +/* | |
| 67 | + * I2C software structures | |
| 68 | + */ | |
| 69 | + | |
| 70 | +struct Ctlr { | |
| 71 | + Lock; | |
| 72 | + QLock io; | |
| 73 | + int init; | |
| 74 | + I2C* i2c; | |
| 75 | + IOCparam* sp; | |
| 76 | + | |
| 77 | + BD* rd; | |
| 78 | + BD* td; | |
| 79 | + int phase; | |
| 80 | + char* addr; | |
| 81 | + char* txbuf; | |
| 82 | + char* rxbuf; | |
| 83 | +}; | |
| 84 | +typedef struct Ctlr Ctlr; | |
| 85 | + | |
| 86 | +static Ctlr i2ctlr[1]; | |
| 87 | +extern int predawn; | |
| 88 | + | |
| 89 | +static void interrupt(Ureg*, void*); | |
| 90 | + | |
| 91 | +static void | |
| 92 | +enable(void) | |
| 93 | +{ | |
| 94 | + I2C *i2c; | |
| 95 | + | |
| 96 | + i2c = i2ctlr->i2c; | |
| 97 | + i2c->i2cer = ~0; /* clear events */ | |
| 98 | + eieio(); | |
| 99 | + i2c->i2mod |= EN; | |
| 100 | + eieio(); | |
| 101 | + i2c->i2cmr = TXE|BSY|TXB|RXB; /* enable all interrupts */ | |
| 102 | + eieio(); | |
| 103 | +} | |
| 104 | + | |
| 105 | +static void | |
| 106 | +disable(void) | |
| 107 | +{ | |
| 108 | + I2C *i2c; | |
| 109 | + | |
| 110 | + i2c = i2ctlr->i2c; | |
| 111 | + i2c->i2cmr = 0; /* mask all interrupts */ | |
| 112 | + i2c->i2mod &= ~EN; | |
| 113 | +} | |
| 114 | + | |
| 115 | +/* | |
| 116 | + * called by the reset routine of any driver using the I2C | |
| 117 | + */ | |
| 118 | +void | |
| 119 | +i2csetup(void) | |
| 120 | +{ | |
| 121 | + IMM *io; | |
| 122 | + I2C *i2c; | |
| 123 | + IOCparam *sp; | |
| 124 | + Ctlr *ctlr; | |
| 125 | + long f, e, emin; | |
| 126 | + int p, d, dmax; | |
| 127 | + | |
| 128 | + ctlr = i2ctlr; | |
| 129 | + if(ctlr->init) | |
| 130 | + return; | |
| 131 | + print("i2c setup...\n"); | |
| 132 | + ctlr->init = 1; | |
| 133 | + i2c = KADDR(INTMEM+0x860); | |
| 134 | + ctlr->i2c = i2c; | |
| 135 | + sp = KADDR(INTMEM+0x3c80); | |
| 136 | + ctlr->sp = sp; | |
| 137 | + disable(); | |
| 138 | + | |
| 139 | + if(ctlr->txbuf == nil){ | |
| 140 | + ctlr->txbuf = ialloc(Tbuflen, 2); | |
| 141 | + ctlr->addr = ctlr->txbuf+Bufsize; | |
| 142 | + } | |
| 143 | + if(ctlr->rxbuf == nil) | |
| 144 | + ctlr->rxbuf = ialloc(Bufsize, 2); | |
| 145 | + if(ctlr->rd == nil){ | |
| 146 | + ctlr->rd = bdalloc(1); | |
| 147 | + ctlr->rd->addr = PADDR(ctlr->rxbuf); | |
| 148 | + ctlr->rd->length = 0; | |
| 149 | + ctlr->rd->status = BDWrap; | |
| 150 | + } | |
| 151 | + if(ctlr->td == nil){ | |
| 152 | + ctlr->td = bdalloc(2); | |
| 153 | + ctlr->td->addr = PADDR(ctlr->txbuf); | |
| 154 | + ctlr->td->length = 0; | |
| 155 | + ctlr->td->status = BDWrap|BDLast; | |
| 156 | + } | |
| 157 | + | |
| 158 | + /* select port pins */ | |
| 159 | + io = ioplock(); | |
| 160 | + io->pbdir |= I2CSDA | I2CSCL; | |
| 161 | + io->pbodr |= I2CSDA | I2CSCL; | |
| 162 | + io->pbpar |= I2CSDA | I2CSCL; | |
| 163 | + iopunlock(); | |
| 164 | + | |
| 165 | + /* explicitly initialise parameters, because InitRxTx can't be used (see i2c/spi relocation errata) */ | |
| 166 | + sp = ctlr->sp; | |
| 167 | + sp->rbase = PADDR(ctlr->rd); | |
| 168 | + sp->tbase = PADDR(ctlr->td); | |
| 169 | + sp->rfcr = 0x18; | |
| 170 | + sp->tfcr = 0x18; | |
| 171 | + sp->mrblr = Bufsize; | |
| 172 | + sp->rstate = 0; | |
| 173 | + sp->rptr = 0; | |
| 174 | + sp->rbptr = sp->rbase; | |
| 175 | + sp->rcnt = 0; | |
| 176 | + sp->tstate = 0; | |
| 177 | + sp->tbptr = sp->tbase; | |
| 178 | + sp->tptr = 0; | |
| 179 | + sp->tcnt = 0; | |
| 180 | + eieio(); | |
| 181 | + | |
| 182 | + i2c->i2com = I2CM; | |
| 183 | + i2c->i2mod = 0; /* normal mode */ | |
| 184 | + i2c->i2add = 0; | |
| 185 | + | |
| 186 | + emin = Freq; | |
| 187 | + dmax = (m->cpuhz/Freq)/2-3; | |
| 188 | + for(d=0; d < dmax; d++){ | |
| 189 | + for(p=3; p>=0; p--){ | |
| 190 | + f = (m->cpuhz>>(p+2))/(2*(d+3)); | |
| 191 | + e = Freq - f; | |
| 192 | + if(e < 0) | |
| 193 | + e = -e; | |
| 194 | + if(e < emin){ | |
| 195 | + emin = e; | |
| 196 | + i2c->i2brg = d; | |
| 197 | + i2c->i2mod = (i2c->i2mod&~PDIV)|((3-p)<<1); /* set PDIV */ | |
| 198 | + } | |
| 199 | + } | |
| 200 | + } | |
| 201 | + //print("i2brg=%d i2mod=#%2.2ux\n", i2c->i2brg, i2c->i2mod); | |
| 202 | + setvec(VectorCPIC+0x10, interrupt, i2ctlr); | |
| 203 | +} | |
| 204 | + | |
| 205 | +enum { | |
| 206 | + Idling, | |
| 207 | + Done, | |
| 208 | + Busy, | |
| 209 | + Sending, | |
| 210 | + Recving, | |
| 211 | +}; | |
| 212 | + | |
| 213 | +static void | |
| 214 | +interrupt(Ureg*, void *arg) | |
| 215 | +{ | |
| 216 | + int events; | |
| 217 | + Ctlr *ctlr; | |
| 218 | + I2C *i2c; | |
| 219 | + | |
| 220 | + ctlr = arg; | |
| 221 | + i2c = ctlr->i2c; | |
| 222 | + events = i2c->i2cer; | |
| 223 | + eieio(); | |
| 224 | + i2c->i2cer = events; | |
| 225 | + if(events & (BSY|TXE)){ | |
| 226 | + //print("I2C#%x\n", events); | |
| 227 | + if(ctlr->phase != Idling){ | |
| 228 | + ctlr->phase = Idling; | |
| 229 | + } | |
| 230 | + }else{ | |
| 231 | + if(events & TXB){ | |
| 232 | + //print("i2c: xmt %d %4.4ux %4.4ux\n", ctlr->phase, ctlr->td->status, ctlr->td[1].status); | |
| 233 | + if(ctlr->phase == Sending){ | |
| 234 | + ctlr->phase = Done; | |
| 235 | + } | |
| 236 | + } | |
| 237 | + if(events & RXB){ | |
| 238 | + //print("i2c: rcv %d %4.4ux %d\n", ctlr->phase, ctlr->rd->status, ctlr->rd->length); | |
| 239 | + if(ctlr->phase == Recving){ | |
| 240 | + ctlr->phase = Done; | |
| 241 | + } | |
| 242 | + } | |
| 243 | + } | |
| 244 | +} | |
| 245 | + | |
| 246 | +static int | |
| 247 | +done(void *a) | |
| 248 | +{ | |
| 249 | + return ((Ctlr*)a)->phase < Busy; | |
| 250 | +} | |
| 251 | + | |
| 252 | +static void | |
| 253 | +i2cwait(Ctlr *ctlr) | |
| 254 | +{ | |
| 255 | + /* TO DO: timeout */ | |
| 256 | + while(!done(ctlr)){ | |
| 257 | + if(predawn) | |
| 258 | + interrupt(nil, ctlr); | |
| 259 | + } | |
| 260 | +} | |
| 261 | + | |
| 262 | +long | |
| 263 | +i2csend(int addr, void *buf, long n) | |
| 264 | +{ | |
| 265 | + Ctlr *ctlr; | |
| 266 | + int i, p, s; | |
| 267 | + | |
| 268 | + ctlr = i2ctlr; | |
| 269 | + if(n > Bufsize) | |
| 270 | + return -1; | |
| 271 | + i = 1; | |
| 272 | + ctlr->txbuf[0] = addr & ~1; | |
| 273 | + if(addr & 1){ | |
| 274 | + ctlr->txbuf[1] = addr>>8; | |
| 275 | + i++; | |
| 276 | + } | |
| 277 | + memmove(ctlr->txbuf+i, buf, n); | |
| 278 | + DCFLUSH(ctlr->txbuf, Tbuflen); | |
| 279 | + ctlr->phase = Sending; | |
| 280 | + ctlr->rd->status = BDEmpty|BDWrap|BDInt; | |
| 281 | + ctlr->td->addr = PADDR(ctlr->txbuf); | |
| 282 | + ctlr->td->length = n+i; | |
| 283 | + ctlr->td->status = BDReady|BDWrap|BDLast|BDInt; | |
| 284 | + enable(); | |
| 285 | + ctlr->i2c->i2com = STR|I2CM; | |
| 286 | + eieio(); | |
| 287 | + i2cwait(ctlr); | |
| 288 | + disable(); | |
| 289 | + p = ctlr->phase; | |
| 290 | + s = ctlr->td->status; | |
| 291 | + if(s & BDReady || s & TxERR || p != Done) | |
| 292 | + return -1; | |
| 293 | + return n; | |
| 294 | +} | |
| 295 | + | |
| 296 | +long | |
| 297 | +i2crecv(int addr, void *buf, long n) | |
| 298 | +{ | |
| 299 | + Ctlr *ctlr; | |
| 300 | + int p, s, flag; | |
| 301 | + BD *td; | |
| 302 | + long nr; | |
| 303 | + | |
| 304 | + ctlr = i2ctlr; | |
| 305 | + if(n > Bufsize) | |
| 306 | + return -1; | |
| 307 | + ctlr->txbuf[0] = addr|Rbit; | |
| 308 | + if(addr & 1){ /* special select sequence */ | |
| 309 | + ctlr->addr[0] = addr &~ 1; | |
| 310 | + ctlr->addr[1] = addr>>8; | |
| 311 | + } | |
| 312 | + DCFLUSH(ctlr->txbuf, Tbuflen); | |
| 313 | + DCFLUSH(ctlr->rxbuf, Bufsize); | |
| 314 | + ctlr->phase = Recving; | |
| 315 | + ctlr->rd->addr = PADDR(ctlr->rxbuf); | |
| 316 | + ctlr->rd->status = BDEmpty|BDWrap|BDInt; | |
| 317 | + flag = 0; | |
| 318 | + td = ctlr->td; | |
| 319 | + td[1].status = 0; | |
| 320 | + if(addr & 1){ | |
| 321 | + /* special select sequence */ | |
| 322 | + td->addr = PADDR(ctlr->addr); | |
| 323 | + td->length = 2; | |
| 324 | + /* td->status made BDReady below */ | |
| 325 | + td++; | |
| 326 | + flag = TxS; | |
| 327 | + } | |
| 328 | + td->addr = PADDR(ctlr->txbuf); | |
| 329 | + td->length = n+1; | |
| 330 | + td->status = BDReady|BDWrap|BDLast | flag; /* not BDInt: leave that to receive */ | |
| 331 | + if(flag) | |
| 332 | + ctlr->td->status = BDReady; | |
| 333 | + enable(); | |
| 334 | + ctlr->i2c->i2com = STR|I2CM; | |
| 335 | + eieio(); | |
| 336 | + i2cwait(ctlr); | |
| 337 | + disable(); | |
| 338 | + p = ctlr->phase; | |
| 339 | + s = ctlr->td->status; | |
| 340 | + if(flag) | |
| 341 | + s |= ctlr->td[1].status; | |
| 342 | + nr = ctlr->rd->length; | |
| 343 | + if(nr > n) | |
| 344 | + nr = n; /* shouldn't happen */ | |
| 345 | + if(s & TxERR || s & BDReady || ctlr->rd->status & BDEmpty) | |
| 346 | + return -1; | |
| 347 | + if(p != Done) | |
| 348 | + return -1; | |
| 349 | + memmove(buf, ctlr->rxbuf, nr); | |
| 350 | + return nr; | |
| 351 | +} | |
| @@ -0,0 +1,187 @@ | ||
| 1 | +/* | |
| 2 | + * Called from l.s in EPROM to set up a minimal working environment. | |
| 3 | + * Since there is no DRAM yet, and therefore no stack, no function | |
| 4 | + * calls may be made from sysinit0, and values can't be stored, | |
| 5 | + * except to INTMEM. Global values are accessed by offset from SB, | |
| 6 | + * which has been set by l.s to point into EPROM. | |
| 7 | + * | |
| 8 | + * This is FADS-specific in CS assignment and access of the FADS BCSR | |
| 9 | + * to discover memory size and speed. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include "u.h" | |
| 13 | +#include "lib.h" | |
| 14 | +#include "mem.h" | |
| 15 | +#include "dat.h" | |
| 16 | +#include "fns.h" | |
| 17 | +#include "io.h" | |
| 18 | + | |
| 19 | +#include "archfads.h" | |
| 20 | + | |
| 21 | +#define MB (1024*1024) | |
| 22 | + | |
| 23 | +enum { | |
| 24 | + UPMSIZE = 64, /* memory controller instruction RAM */ | |
| 25 | + SPEED = 50, /* maximum memory clock in MHz */ | |
| 26 | + SDRAMSIZE = 4*MB, | |
| 27 | + | |
| 28 | + /* mcr */ | |
| 29 | + WriteRAM = 0<<30, | |
| 30 | + ReadRAM = 1<<30, | |
| 31 | + ExecRAM = 2<<30, | |
| 32 | + | |
| 33 | + SelUPMA = 0<<23, | |
| 34 | + SelUPMB = 1<<23, | |
| 35 | + | |
| 36 | + Once = 1<<8, | |
| 37 | +}; | |
| 38 | + | |
| 39 | +/* | |
| 40 | + * mpc8bug uses the following for 60ns EDO DRAMs 32-50MHz | |
| 41 | + */ | |
| 42 | +static ulong upma50[UPMSIZE] = { | |
| 43 | + 0x8FFFEC24, 0xFFFEC04, 0xCFFEC04, 0xFFEC04, | |
| 44 | + 0xFFEC00, 0x37FFEC47, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 45 | + 0x8FFFEC24, 0xFFFEC04, 0x8FFEC04, 0xFFEC0C, | |
| 46 | + 0x3FFEC00, 0xFFEC44, 0xFFCC08, 0xCFFCC44, | |
| 47 | + 0xFFEC0C, 0x3FFEC00, 0xFFEC44, 0xFFCC00, | |
| 48 | + 0x3FFFC847, 0x3FFFEC47, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 49 | + 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x11BFCC47, | |
| 50 | + 0xC0FFCC84, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 51 | + 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x3AFCC4C, | |
| 52 | + 0xCAFCC00, 0x3AFCC4C, 0xCAFCC00, 0x3AFCC4C, | |
| 53 | + 0xCAFCC00, 0x33BFCC4F, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 54 | + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 55 | + 0xC0FFCC84, 0xFFCC04, 0x7FFCC04, 0x3FFFCC06, | |
| 56 | + 0xFFFFCC85, 0xFFFFCC05, 0xFFFFCC05, 0xFFFFFFFF, | |
| 57 | + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 58 | + 0x33FFCC07, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 59 | +}; | |
| 60 | + | |
| 61 | +/* | |
| 62 | + * the FADS manual table 3-7 suggests the following for 60ns EDO DRAMs at 20MHz | |
| 63 | + */ | |
| 64 | +static ulong upma20[UPMSIZE] = { | |
| 65 | + 0x8FFFCC04, 0x08FFCC00, 0x33FFCC47, ~0, ~0, ~0, ~0, ~0, | |
| 66 | + [0x08] 0x8FFFCC04, 0x08FFCC08, 0x08FFCC08, 0x08FFCC08, 0x08FFCC00, 0x3FFFCC47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, | |
| 67 | + [0x18] 0x8FEFCC00, 0x39BFCC47, ~0, ~0, ~0, ~0, ~0, ~0, | |
| 68 | + [0x20] 0x8FEFCC00, 0x09AFCC48, 0x09AFCC48, 0x08AFCC48, 0x39BFCC47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, | |
| 69 | + [0x30] 0x80FFCC84, 0x17FFCC04, 0xFFFFCC86, 0xFFFFCC05, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, | |
| 70 | + [0x3C] 0x33FFCC07, ~0, ~0, ~0, | |
| 71 | +}; | |
| 72 | + | |
| 73 | +void | |
| 74 | +sysinit0(int inrom) | |
| 75 | +{ | |
| 76 | + ulong *upm, *bcsr; | |
| 77 | + IMM *io; | |
| 78 | + int i, mb; | |
| 79 | + | |
| 80 | + io = (IMM*)INTMEM; /* running before maps, no KADDR */ | |
| 81 | + | |
| 82 | + /* system interface unit initialisation, FADS manual table 3-2, except as noted */ | |
| 83 | + io->siumcr = 0x01012440; | |
| 84 | + io->sypcr = 0xFFFFFF88; | |
| 85 | + io->tbscrk = KEEP_ALIVE_KEY; | |
| 86 | + io->tbscr = 0xC3; /* time base enabled */ | |
| 87 | + io->rtcsck = KEEP_ALIVE_KEY; | |
| 88 | + io->rtcsc = 0xC1; /* don't FRZ, real-time clock enabled */ | |
| 89 | + io->rtcsck = ~KEEP_ALIVE_KEY; | |
| 90 | + io->piscrk = KEEP_ALIVE_KEY; | |
| 91 | + io->piscr = 0x82; | |
| 92 | + | |
| 93 | + io->memc[BCSRCS].option = 0xFFFF8110; /* 32k block, all types access, CS early negate, 1 ws */ | |
| 94 | + io->memc[BCSRCS].base = BCSRMEM | 1; /* base, 32-bit port, no parity, GPCM */ | |
| 95 | + | |
| 96 | + io->memc[BOOTCS].base = FLASHMEM | 1; | |
| 97 | + io->memc[BOOTCS].option = 0xFF800D54; | |
| 98 | + | |
| 99 | + if(!inrom) | |
| 100 | + return; /* can't initialise DRAM controller from DRAM */ | |
| 101 | + | |
| 102 | + bcsr = (ulong*)BCSRMEM; | |
| 103 | +// bcsr[1] &= ~DisableDRAM; | |
| 104 | + /* could check DRAM speed here; assume 60ns */ | |
| 105 | + switch((bcsr[2]>>23)&3){ | |
| 106 | + default: return; /* can't happen; for the compiler */ | |
| 107 | + case 0: mb = 4; break; | |
| 108 | + case 1: mb = 32; break; | |
| 109 | + case 2: mb = 16; break; | |
| 110 | + case 3: mb = 8; break; | |
| 111 | + } | |
| 112 | + | |
| 113 | + upm = upma50; | |
| 114 | + for(i=0; i<UPMSIZE; i++){ | |
| 115 | + io->mdr = upm[i]; | |
| 116 | + io->mcr = WriteRAM | SelUPMA | i; | |
| 117 | + } | |
| 118 | + io->mptpr = 0x0400; | |
| 119 | + if(SPEED >= 32) | |
| 120 | + io->mamr = (0x9C<<24) | 0xA21114; /* 50MHz BRGCLK; FADS manual says 0xC0, mpc8bug sets 0x9C */ | |
| 121 | + else if(SPEED >= 20) | |
| 122 | + io->mamr = (0x60<<24) | 0xA21114; /* 25MHz BRGCLK */ | |
| 123 | + else | |
| 124 | + io->mamr = (0x40<<24) | 0xA21114; /* 16.67MHz BRGCLK */ | |
| 125 | + io->memc[DRAM1].option = ~((mb<<20)-1)|0x0800; /* address mask, SAM=1 */ | |
| 126 | + io->memc[DRAM1].base = 0 | 0x81; /* base at 0, 32-bit port size, no parity, UPMA */ | |
| 127 | +} | |
| 128 | + | |
| 129 | +/* | |
| 130 | + * the FADS manual table 3-9's suggestion for MB811171622A-100 32+MHz-50MHz | |
| 131 | + */ | |
| 132 | +static ulong upmb50[UPMSIZE] = { | |
| 133 | + [0x00] 0x1F07FC04, 0xEEAEFC04, 0x11ADFC04, 0xEFBBBC00, 0x1FF77C47, | |
| 134 | + [0x05] 0x1FF77C34, 0xEFEABC34, 0x1FB57C35, | |
| 135 | + [0x08] 0x1F07FC04, 0xEEAEFC04, 0x10ADFC04, 0xF0AFFC00, 0xF0AFFC00, 0xF1AFFC00, 0xEFBBBC00, 0x1FF77C47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, | |
| 136 | + [0x18] 0x1F27FC04, 0xEEAEBC00, 0x01B93C04, 0x1FF77C47, ~0, ~0, ~0, ~0, | |
| 137 | + [0x20] 0x1F07FC04, 0xEEAEBC00, 0x10AD7C00, 0xF0AFFC00, 0xF0AFFC00, 0xE1BBBC04, 0x1FF77C47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, | |
| 138 | + [0x30] 0x1FF5FC84, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC84, 0xFFFFFC07, ~0, ~0, ~0, ~0, ~0, ~0, | |
| 139 | + [0x3C] 0x7FFFFC07, ~0, ~0, ~0, | |
| 140 | +}; | |
| 141 | + | |
| 142 | +/* | |
| 143 | + * the FADS manual table 3-8's suggestion for MB811171622A-100 up to 32MHz | |
| 144 | + */ | |
| 145 | +static ulong upmb32[UPMSIZE] = { | |
| 146 | + [0x00] 0x126CC04, 0xFB98C00, 0x1FF74C45, ~0, ~0, | |
| 147 | + [0x05] 0x1FE77C34, 0xEFAABC34, 0x1FA57C35, | |
| 148 | + [0x08] 0x0026FC04, 0x10ADFC00, 0xF0AFFC00, 0xF1AFFC00, 0xEFBBBC00, 0x1FF77C45, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, | |
| 149 | + [0x18] 0x0E26BC04, 0x01B93C00, 0x1FF77C45, ~0, ~0, ~0, ~0, ~0, | |
| 150 | + [0x20] 0x0E26BC00, 0x10AD7C00, 0xF0AFFC00, 0xF0AFFC00, 0xE1BBBC04, 0x1FF77C45, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, | |
| 151 | + [0x30] 0x1FF5FC84, 0xFFFFFC04, 0xFFFFFC84, 0xFFFFFC05, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, | |
| 152 | + [0x3C] 0x7FFFFC07, ~0, ~0, ~0, | |
| 153 | +}; | |
| 154 | + | |
| 155 | +/* | |
| 156 | + * optionally called by archfads.c:/^archinit to initialise access to SDRAM | |
| 157 | + */ | |
| 158 | +void | |
| 159 | +sdraminit(ulong base) | |
| 160 | +{ | |
| 161 | + ulong *upm; | |
| 162 | + IMM *io; | |
| 163 | + int i; | |
| 164 | + | |
| 165 | + io = (IMM*)INTMEM; /* running before maps, no KADDR */ | |
| 166 | + if(SPEED > 32) | |
| 167 | + upm = upmb50; | |
| 168 | + else | |
| 169 | + upm = upmb32; | |
| 170 | + for(i=0; i<UPMSIZE; i++){ | |
| 171 | + io->mdr = upm[i]; | |
| 172 | + io->mcr = WriteRAM | SelUPMB | i; | |
| 173 | + } | |
| 174 | + io->memc[SDRAM].option = ~(SDRAMSIZE-1)|0x0A00; /* address mask, SAM=1, G5LS=1 */ | |
| 175 | + io->memc[SDRAM].base = base | 0xC1; | |
| 176 | + if(SPEED > 32){ | |
| 177 | + io->mbmr = 0xD0802114; /* 50MHz BRGCLK */ | |
| 178 | + io->mar = 0x88; | |
| 179 | + }else{ | |
| 180 | + io->mbmr = 0x80802114; /* 32MHz BRGCLK */ | |
| 181 | + io->mar = 0x48; | |
| 182 | + } | |
| 183 | + io->mcr = ExecRAM | SelUPMB | (SDRAM<<13) | Once | 5; /* run MRS command in locations 5-8 of UPMB */ | |
| 184 | + io->mbmr = (io->mbmr & ~0xF) | 8; | |
| 185 | + io->mcr = ExecRAM | SelUPMB | (SDRAM<<13) | Once | 0x30; /* run refresh sequence */ | |
| 186 | + io->mbmr = (io->mbmr & ~0xF) | 4; /* 4-beat refresh bursts */ | |
| 187 | +} | |
| @@ -0,0 +1,101 @@ | ||
| 1 | +/* | |
| 2 | + * Called from l.s in EPROM to set up a minimal working environment. | |
| 3 | + * Since there is no DRAM yet, and therefore no stack, no function | |
| 4 | + * calls may be made from sysinit0, and values can't be stored, | |
| 5 | + * except to INTMEM. Global values are accessed by offset from SB, | |
| 6 | + * which has been set by l.s to point into EPROM. | |
| 7 | + * | |
| 8 | + * This is PowerPAQ-specific: | |
| 9 | + * - assumes 8mbytes | |
| 10 | + * - powerpaq CS assignment | |
| 11 | + */ | |
| 12 | + | |
| 13 | +#include "u.h" | |
| 14 | +#include "lib.h" | |
| 15 | +#include "mem.h" | |
| 16 | +#include "dat.h" | |
| 17 | +#include "fns.h" | |
| 18 | +#include "io.h" | |
| 19 | + | |
| 20 | +#include "archpaq.h" | |
| 21 | + | |
| 22 | +#define MB (1024*1024) | |
| 23 | + | |
| 24 | +enum { | |
| 25 | + DRAMSIZE = 8*MB, | |
| 26 | + FLASHSIZE = 8*MB, | |
| 27 | + | |
| 28 | + UPMSIZE = 64, /* memory controller instruction RAM */ | |
| 29 | + SPEED = 50, /* maximum memory clock in MHz */ | |
| 30 | + | |
| 31 | + /* mcr */ | |
| 32 | + WriteRAM = 0<<30, | |
| 33 | + ReadRAM = 1<<30, | |
| 34 | + ExecRAM = 2<<30, | |
| 35 | + | |
| 36 | + SelUPMA = 0<<23, | |
| 37 | + SelUPMB = 1<<23, | |
| 38 | + | |
| 39 | + Once = 1<<8, | |
| 40 | +}; | |
| 41 | + | |
| 42 | +/* | |
| 43 | + * mpc8bug uses the following for 60ns EDO DRAMs 32-50MHz | |
| 44 | + */ | |
| 45 | +static ulong upmb50[UPMSIZE] = { | |
| 46 | + 0x8FFFEC24, 0xFFFEC04, 0xCFFEC04, 0xFFEC04, | |
| 47 | + 0xFFEC00, 0x37FFEC47, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 48 | + 0x8FFFEC24, 0xFFFEC04, 0x8FFEC04, 0xFFEC0C, | |
| 49 | + 0x3FFEC00, 0xFFEC44, 0xFFCC08, 0xCFFCC44, | |
| 50 | + 0xFFEC0C, 0x3FFEC00, 0xFFEC44, 0xFFCC00, | |
| 51 | + 0x3FFFC847, 0x3FFFEC47, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 52 | + 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x11BFCC47, | |
| 53 | + 0xC0FFCC84, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 54 | + 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x3AFCC4C, | |
| 55 | + 0xCAFCC00, 0x3AFCC4C, 0xCAFCC00, 0x3AFCC4C, | |
| 56 | + 0xCAFCC00, 0x33BFCC4F, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 57 | + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 58 | + 0xC0FFCC84, 0xFFCC04, 0x7FFCC04, 0x3FFFCC06, | |
| 59 | + 0xFFFFCC85, 0xFFFFCC05, 0xFFFFCC05, 0xFFFFFFFF, | |
| 60 | + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 61 | + 0x33FFCC07, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, | |
| 62 | +}; | |
| 63 | + | |
| 64 | +void | |
| 65 | +sysinit0(int inrom) | |
| 66 | +{ | |
| 67 | + ulong *upm; | |
| 68 | + IMM *io; | |
| 69 | + int i; | |
| 70 | + | |
| 71 | + io = (IMM*)INTMEM; /* running before maps, no KADDR */ | |
| 72 | + | |
| 73 | + /* system interface unit initialisation, FADS manual table 3-2, except as noted */ | |
| 74 | + io->siumcr = 0x01012440; | |
| 75 | + io->sypcr = 0xFFFFFF88; | |
| 76 | + io->tbscrk = KEEP_ALIVE_KEY; | |
| 77 | + io->tbscr = 0xC3; /* time base enabled */ | |
| 78 | + io->rtcsck = KEEP_ALIVE_KEY; | |
| 79 | + io->rtcsc = 0xC1; /* don't FRZ, real-time clock enabled */ | |
| 80 | + io->rtcsck = ~KEEP_ALIVE_KEY; | |
| 81 | + io->piscrk = KEEP_ALIVE_KEY; | |
| 82 | + io->piscr = 0x82; | |
| 83 | + | |
| 84 | + io->memc[BOOTCS].base = FLASHMEM | 1; | |
| 85 | + io->memc[BOOTCS].option = ~(FLASHSIZE-1)|(1<<8)|(2<<4); /* mask, BIH, 2 wait states */ | |
| 86 | + | |
| 87 | + if(!inrom) | |
| 88 | + return; /* can't initialise DRAM controller from DRAM */ | |
| 89 | + | |
| 90 | + /* could check DRAM speed here; assume 60ns */ | |
| 91 | + /* could probe DRAM for size here; assume DRAMSIZE */ | |
| 92 | + io->mptpr = 0x400; /* powerpaq flash has 0x1000 */ | |
| 93 | + io->mbmr = (0xC0<<24) | 0xA21114; /* 50MHz BRGCLK */ | |
| 94 | + upm = upmb50; | |
| 95 | + for(i=0; i<UPMSIZE; i++){ | |
| 96 | + io->mdr = upm[i]; | |
| 97 | + io->mcr = WriteRAM | SelUPMB | i; | |
| 98 | + } | |
| 99 | + io->memc[DRAM1].option = ~(DRAMSIZE-1)|0x0800; /* address mask, SAM=1 */ | |
| 100 | + io->memc[DRAM1].base = 0 | 0xC1; /* base at 0, 32-bit port size, no parity, UPMB */ | |
| 101 | +} | |
| @@ -0,0 +1,91 @@ | ||
| 1 | + | |
| 2 | +/* | |
| 3 | + * Called from l.s in EPROM to set up a minimal working environment. | |
| 4 | + * Since there is no DRAM yet, and therefore no stack, no function | |
| 5 | + * calls may be made from sysinit, and values can't be stored, | |
| 6 | + * except to INTMEM. Global values are accessed by offset from SB, | |
| 7 | + * which has been set by l.s to point into EPROM. | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#include "u.h" | |
| 11 | +#include "lib.h" | |
| 12 | +#include "mem.h" | |
| 13 | +#include "dat.h" | |
| 14 | +#include "fns.h" | |
| 15 | +#include "io.h" | |
| 16 | + | |
| 17 | +#include "archrpcg.h" | |
| 18 | + | |
| 19 | +#define MB (1024*1024) | |
| 20 | + | |
| 21 | +enum { | |
| 22 | + UPMSIZE = 64, /* memory controller instruction RAM */ | |
| 23 | + DRAMSIZE = 16*MB, | |
| 24 | + FLASHSIZE = 4*MB, | |
| 25 | + | |
| 26 | + WriteRAM = 0<<30, | |
| 27 | + ReadRAM = 1<<30, | |
| 28 | + ExecRAM = 2<<30, | |
| 29 | + | |
| 30 | + SelUPMA = 0<<23, | |
| 31 | + SelUPMB = 1<<23, | |
| 32 | +}; | |
| 33 | +/* RPCG values for RPXLite AW */ | |
| 34 | +static ulong upma50[UPMSIZE] = { | |
| 35 | + 0xCFFFCC24, 0x0FFFCC04, 0x0CAFCC04, 0x03AFCC08, | |
| 36 | + 0x3FBFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, | |
| 37 | + 0xCFFFCC24, 0x0FFFCC04, 0x0CAFCC84, 0x03AFCC88, | |
| 38 | + 0x3FBFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, | |
| 39 | + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, | |
| 40 | + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, | |
| 41 | + 0xCFFFCC24, 0x0FFFCC04, 0x0CFFCC04, 0x03FFCC00, | |
| 42 | + 0x3FFFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, | |
| 43 | + 0xCFFFCC24, 0x0FFFCC04, 0x0CFFCC84, 0x03FFCC84, | |
| 44 | + 0x0CFFCC00, 0x33FFCC27, 0xFFFFCC25, 0xFFFFCC25, | |
| 45 | + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, | |
| 46 | + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, | |
| 47 | + 0xC0FFCC24, 0x03FFCC24, 0x0FFFCC24, 0x0FFFCC24, | |
| 48 | + 0x3FFFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, | |
| 49 | + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, | |
| 50 | + 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, | |
| 51 | +}; | |
| 52 | + | |
| 53 | +void | |
| 54 | +sysinit0(int inrom) | |
| 55 | +{ | |
| 56 | + ulong *upm; | |
| 57 | + IMM *io; | |
| 58 | + int i; | |
| 59 | + | |
| 60 | + io = (IMM*)INTMEM; /* running before maps, no KADDR */ | |
| 61 | + io->siumcr = 0x01012440; | |
| 62 | + io->sypcr = 0xFFFFFF88; | |
| 63 | + io->tbscrk = KEEP_ALIVE_KEY; | |
| 64 | + io->tbscr = 0xC3; | |
| 65 | + io->rtcsck = KEEP_ALIVE_KEY; | |
| 66 | + io->rtcsc = 0xC1; | |
| 67 | + io->rtcsck = ~KEEP_ALIVE_KEY; | |
| 68 | + io->piscrk = KEEP_ALIVE_KEY; | |
| 69 | + io->piscr = 0x82; | |
| 70 | +return; | |
| 71 | + io->memc[BCSRCS].option = 0xFFFF8910; /* 32k block, all types access, CSNT, CS early negate, burst inhibit, 1 ws */ | |
| 72 | + io->memc[BCSRCS].base = BCSRMEM | 1; /* base, 32-bit port, no parity, GPCM */ | |
| 73 | + | |
| 74 | + io->memc[BOOTCS].base = FLASHMEM | 0x801; /* base, 16 bit port */ | |
| 75 | + io->memc[BOOTCS].option = ~(FLASHSIZE-1)|(1<<8)|(4<<4); /* mask, BIH, 4 wait states */ | |
| 76 | + | |
| 77 | + if(1||!inrom) | |
| 78 | + return; /* can't initialise DRAM controller from DRAM */ | |
| 79 | + | |
| 80 | + /* TO DO: could check DRAM size and speed now */ | |
| 81 | + | |
| 82 | + upm = upma50; | |
| 83 | + for(i=0; i<nelem(upma50); i++){ | |
| 84 | + io->mdr = upm[i]; | |
| 85 | + io->mcr = WriteRAM | SelUPMA | i; | |
| 86 | + } | |
| 87 | + io->mptpr = 0x0800; /* divide by 8 */ | |
| 88 | + io->mamr = (0x58<<24) | 0xA01430; /* 40MHz BRGCLK */ | |
| 89 | + io->memc[DRAM1].option = ~(DRAMSIZE-1)|0x0E00; /* address mask, SAM=1, G5LA/S=3 */ | |
| 90 | + io->memc[DRAM1].base = 0 | 0x81; /* base at 0, 32-bit port size, no parity, UPMA */ | |
| 91 | +} | |
| @@ -0,0 +1,463 @@ | ||
| 1 | +enum | |
| 2 | +{ | |
| 3 | + /* software interrupt vectors (SIU and CPM) */ | |
| 4 | + VectorPIC= 0, /* level 0 to level 7, assigned by software */ | |
| 5 | + CPIClevel= 4, | |
| 6 | + VectorIRQ= VectorPIC+8, /* IRQ0 to IRQ7 */ | |
| 7 | + VectorCPIC= VectorIRQ+8, /* 32 CPM interrupts: 0 (error) to 0x1F (PC15) */ | |
| 8 | +}; | |
| 9 | + | |
| 10 | +enum | |
| 11 | +{ | |
| 12 | + BUSUNKNOWN = 0, | |
| 13 | +}; | |
| 14 | + | |
| 15 | +/* | |
| 16 | + * Buffer Descriptors and IO Rings | |
| 17 | + */ | |
| 18 | + | |
| 19 | +typedef struct BD BD; | |
| 20 | +struct BD { | |
| 21 | + ushort status; | |
| 22 | + ushort length; | |
| 23 | + ulong addr; | |
| 24 | +}; | |
| 25 | + | |
| 26 | +BD* bdalloc(int); | |
| 27 | +void bdfree(BD*, int); | |
| 28 | + | |
| 29 | +enum { | |
| 30 | + /* Rx BDs, bits common to all protocols */ | |
| 31 | + BDEmpty= 1<<15, | |
| 32 | + BDWrap= 1<<13, | |
| 33 | + BDInt= 1<<12, | |
| 34 | + BDLast= 1<<11, | |
| 35 | + BDFirst= 1<<10, | |
| 36 | + | |
| 37 | + /* Tx BDs */ | |
| 38 | + BDReady= 1<<15, | |
| 39 | + /* BDWrap, BDInt, BDLast */ | |
| 40 | +}; | |
| 41 | + | |
| 42 | +typedef struct Ring Ring; | |
| 43 | +struct Ring { | |
| 44 | + BD* rdr; /* receive descriptor ring */ | |
| 45 | + void* rrb; /* receive ring buffers */ | |
| 46 | + int rdrx; /* index into rdr */ | |
| 47 | + int nrdre; /* length of rdr */ | |
| 48 | + | |
| 49 | + BD* tdr; /* transmit descriptor ring */ | |
| 50 | + Block** txb; /* corresponding transmit ring buffers */ | |
| 51 | + int tdrh; /* host index into tdr */ | |
| 52 | + int tdri; /* interface index into tdr */ | |
| 53 | + int ntdre; /* length of tdr */ | |
| 54 | + int ntq; /* pending transmit requests */ | |
| 55 | +}; | |
| 56 | + | |
| 57 | +#define NEXT(x, l) (((x)+1)%(l)) | |
| 58 | +#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1) | |
| 59 | +#define HOWMANY(x, y) (((x)+((y)-1))/(y)) | |
| 60 | +#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) | |
| 61 | + | |
| 62 | +int ioringinit(Ring*, int, int, int); | |
| 63 | + | |
| 64 | +/* | |
| 65 | + * CPM | |
| 66 | + */ | |
| 67 | +enum { | |
| 68 | + /* commands */ | |
| 69 | + InitRxTx = 0, | |
| 70 | + InitRx = 1, | |
| 71 | + InitTx = 2, | |
| 72 | + EnterHunt= 3, | |
| 73 | + StopTx= 4, | |
| 74 | + GracefulStopTx = 5, | |
| 75 | + InitIDMA = 5, | |
| 76 | + RestartTx = 6, | |
| 77 | + CloseRxBD = 7, | |
| 78 | + SetGroupAddr = 8, | |
| 79 | + SetTimer = 8, | |
| 80 | + GCITimeout = 9, | |
| 81 | + GCIAbort = 10, | |
| 82 | + StopIDMA = 11, | |
| 83 | + StartDSP = 12, | |
| 84 | + ArmIDMA = 13, | |
| 85 | + InitDSP = 13, | |
| 86 | + USBCmd = 15, | |
| 87 | + | |
| 88 | + /* channel IDs */ | |
| 89 | + SCC1ID= 0, | |
| 90 | + USBID= 0, | |
| 91 | + I2CID= 1, | |
| 92 | + IDMA1ID= 1, | |
| 93 | + SCC2ID= 4, | |
| 94 | + SPIID= 5, | |
| 95 | + IDMA2ID= 5, | |
| 96 | + TIMERID= 5, | |
| 97 | + SCC3ID= 8, | |
| 98 | + SMC1ID= 9, | |
| 99 | + DSP1ID=9, | |
| 100 | + SCC4ID= 12, | |
| 101 | + SMC2ID= 13, | |
| 102 | + DSP2ID= 13, | |
| 103 | + | |
| 104 | + BaudEnable = 1<<16, | |
| 105 | + | |
| 106 | + /* sicr */ | |
| 107 | + CLK1 = 4, /* SCC1,2 */ | |
| 108 | + CLK2 = 5, | |
| 109 | + CLK3 = 6, | |
| 110 | + CLK4 = 7, | |
| 111 | + CLK5 = CLK1, /* SCC3,4 */ | |
| 112 | + CLK6 = CLK2, | |
| 113 | + CLK7 = CLK3, | |
| 114 | + CLK8 = CLK4, | |
| 115 | +}; | |
| 116 | + | |
| 117 | +void cpmop(int, int, int); | |
| 118 | +#define ioplock() (m->iomem) | |
| 119 | +#define iopunlock() | |
| 120 | + | |
| 121 | +/* | |
| 122 | + * the structures below follow hardware/firmware layouts in the 8xx manuals: | |
| 123 | + * mind the data types, offsets and alignment | |
| 124 | + */ | |
| 125 | + | |
| 126 | +/* | |
| 127 | + * basic IO controller parameters (SMC and SCC) | |
| 128 | + */ | |
| 129 | +typedef struct IOCparam IOCparam; | |
| 130 | +struct IOCparam { | |
| 131 | + ushort rbase; | |
| 132 | + ushort tbase; | |
| 133 | + uchar rfcr; | |
| 134 | + uchar tfcr; | |
| 135 | + ushort mrblr; | |
| 136 | + ulong rstate; | |
| 137 | + ulong rptr; | |
| 138 | + ushort rbptr; | |
| 139 | + ushort rcnt; | |
| 140 | + ulong rtmp; | |
| 141 | + ulong tstate; | |
| 142 | + ulong tptr; | |
| 143 | + ushort tbptr; | |
| 144 | + ushort tcnt; | |
| 145 | + ulong ttmp; | |
| 146 | +}; | |
| 147 | + | |
| 148 | +typedef struct SCCparam SCCparam; | |
| 149 | +struct SCCparam { | |
| 150 | + IOCparam; | |
| 151 | + ulong rcrc; | |
| 152 | + ulong tcrc; | |
| 153 | +}; | |
| 154 | + | |
| 155 | +typedef struct SCC SCC; | |
| 156 | +struct SCC { | |
| 157 | + ulong gsmrl; | |
| 158 | + ulong gsmrh; | |
| 159 | + ushort psmr; | |
| 160 | + uchar rsvscc0[2]; | |
| 161 | + ushort todr; | |
| 162 | + ushort dsr; | |
| 163 | + ushort scce; | |
| 164 | + uchar rsvscc1[2]; | |
| 165 | + ushort sccm; | |
| 166 | + uchar rsvscc3; | |
| 167 | + uchar sccs; | |
| 168 | + ushort irmode; | |
| 169 | + ushort irsip; | |
| 170 | +}; | |
| 171 | + | |
| 172 | +typedef struct SMC SMC; | |
| 173 | +struct SMC { | |
| 174 | + uchar pad1[2]; | |
| 175 | + ushort smcmr; | |
| 176 | + uchar pad2[2]; | |
| 177 | + uchar smce; | |
| 178 | + uchar pad3[3]; | |
| 179 | + uchar smcm; | |
| 180 | + uchar pad4[5]; | |
| 181 | +}; | |
| 182 | + | |
| 183 | +typedef struct SPI SPI; | |
| 184 | +struct SPI { | |
| 185 | + ushort spmode; | |
| 186 | + uchar res1[4]; | |
| 187 | + uchar spie; | |
| 188 | + uchar res2[3]; | |
| 189 | + uchar spim; | |
| 190 | + uchar res3[2]; | |
| 191 | + uchar spcom; | |
| 192 | + uchar res4[10]; | |
| 193 | +}; | |
| 194 | + | |
| 195 | +typedef struct USB USB; | |
| 196 | +struct USB { /* 823 only */ | |
| 197 | + uchar usmod; | |
| 198 | + uchar usadr; | |
| 199 | + uchar uscom; | |
| 200 | + uchar rsvu1; | |
| 201 | + ushort usep[4]; | |
| 202 | + uchar rsvu2[4]; | |
| 203 | + ushort usber; | |
| 204 | + uchar rsvu3[2]; | |
| 205 | + ushort usbmr; | |
| 206 | + uchar rsvu4; | |
| 207 | + uchar usbs; | |
| 208 | + uchar rsvu5[8]; | |
| 209 | +}; | |
| 210 | + | |
| 211 | +typedef struct IMM IMM; | |
| 212 | +struct IMM { | |
| 213 | + struct { /* general SIU */ | |
| 214 | + ulong siumcr; | |
| 215 | + ulong sypcr; | |
| 216 | + uchar rsv0[0xE-0x8]; | |
| 217 | + ushort swsr; | |
| 218 | + ulong sipend; | |
| 219 | + ulong simask; | |
| 220 | + ulong siel; | |
| 221 | + uchar sivec; | |
| 222 | + uchar padv[3]; | |
| 223 | + ulong tesr; | |
| 224 | + uchar rsv1[0x30-0x24]; | |
| 225 | + ulong sdcr; | |
| 226 | + uchar rsv2[0x80-0x34]; | |
| 227 | + }; | |
| 228 | + struct { /* PCMCIA */ | |
| 229 | + struct { | |
| 230 | + ulong base; | |
| 231 | + ulong option; | |
| 232 | + } pcmr[8]; | |
| 233 | + uchar rsv3[0xe0-0xc0]; | |
| 234 | + ulong pgcra; | |
| 235 | + ulong pgcrb; | |
| 236 | + ulong pscr; | |
| 237 | + uchar rsv4[0xf0-0xec]; | |
| 238 | + ulong pipr; | |
| 239 | + uchar rsv5[4]; | |
| 240 | + ulong per; | |
| 241 | + uchar rsv6[4]; | |
| 242 | + }; | |
| 243 | + struct { /* MEMC */ | |
| 244 | + struct { | |
| 245 | + ulong base; | |
| 246 | + ulong option; | |
| 247 | + } memc[8]; | |
| 248 | + uchar rsv7a[0x24]; | |
| 249 | + ulong mar; | |
| 250 | + ulong mcr; | |
| 251 | + uchar rsv7b[4]; | |
| 252 | + ulong mamr; | |
| 253 | + ulong mbmr; | |
| 254 | + ushort mstat; | |
| 255 | + ushort mptpr; | |
| 256 | + ulong mdr; | |
| 257 | + uchar rsv7c[0x80]; | |
| 258 | + }; | |
| 259 | + struct { /* system integration timers */ | |
| 260 | + ushort tbscr; | |
| 261 | + uchar rsv8a[2]; | |
| 262 | + ulong tbrefu; | |
| 263 | + ulong tbrefl; | |
| 264 | + uchar rsv8b[0x14]; | |
| 265 | + ushort rtcsc; | |
| 266 | + uchar rsv8c[2]; | |
| 267 | + ulong rtc; | |
| 268 | + ulong rtsec; | |
| 269 | + ulong rtcal; | |
| 270 | + uchar rsv8d[0x10]; | |
| 271 | + ushort piscr; | |
| 272 | + ushort rsv8e; | |
| 273 | + ulong pitc; | |
| 274 | + ulong pitr; | |
| 275 | + uchar rsv8f[0x34]; | |
| 276 | + }; | |
| 277 | + struct { /* 280: clocks and resets */ | |
| 278 | + ulong sccr; | |
| 279 | + ulong plprcr; | |
| 280 | + ulong rsr; | |
| 281 | + uchar rsv9[0x300-0x28c]; | |
| 282 | + }; | |
| 283 | + struct { /* 300: system integration timers keys */ | |
| 284 | + ulong tbscrk; | |
| 285 | + ulong tbrefuk; | |
| 286 | + ulong tbreflk; | |
| 287 | + ulong tbk; | |
| 288 | + uchar rsv10a[0x10]; | |
| 289 | + ulong rtcsck; | |
| 290 | + ulong rtck; | |
| 291 | + ulong rtseck; | |
| 292 | + ulong rtcalk; | |
| 293 | + uchar rsv10b[0x10]; | |
| 294 | + ulong piscrk; | |
| 295 | + ulong pitck; | |
| 296 | + uchar rsv10c[0x38]; | |
| 297 | + }; | |
| 298 | + struct { /* 380: clocks and resets keys */ | |
| 299 | + ulong sccrk; | |
| 300 | + ulong plprcrk; | |
| 301 | + ulong rsrk; | |
| 302 | + uchar rsv11[0x800-0x38C]; | |
| 303 | + }; | |
| 304 | + struct { /* 800: video controller */ | |
| 305 | + ushort vccr; | |
| 306 | + ushort pad11a; | |
| 307 | + uchar vsr; | |
| 308 | + uchar pad11b; | |
| 309 | + uchar vcmr; | |
| 310 | + uchar pad11c; | |
| 311 | + ulong vbcb; | |
| 312 | + ulong pad11d; | |
| 313 | + ulong vfcr0; | |
| 314 | + ulong vfaa0; | |
| 315 | + ulong vfba0; | |
| 316 | + ulong vfcr1; | |
| 317 | + ulong vfaa1; | |
| 318 | + ulong vfba1; | |
| 319 | + uchar rsv11a[0x840-0x828]; | |
| 320 | + }; | |
| 321 | + struct { /* 840: LCD */ | |
| 322 | + ulong lccr; | |
| 323 | + ulong lchcr; | |
| 324 | + ulong lcvcr; | |
| 325 | + ulong rsv11b; | |
| 326 | + ulong lcfaa; | |
| 327 | + ulong lcfba; | |
| 328 | + uchar lcsr; | |
| 329 | + uchar rsv11c[0x860-0x859]; | |
| 330 | + }; | |
| 331 | + struct { /* 860: I2C */ | |
| 332 | + uchar i2mod; | |
| 333 | + uchar rsv12a[3]; | |
| 334 | + uchar i2add; | |
| 335 | + uchar rsv12b[3]; | |
| 336 | + uchar i2brg; | |
| 337 | + uchar rsv12c[3]; | |
| 338 | + uchar i2com; | |
| 339 | + uchar rsv12d[3]; | |
| 340 | + uchar i2cer; | |
| 341 | + uchar rsv12e[3]; | |
| 342 | + uchar i2cmr; | |
| 343 | + uchar rsv12[0x900-0x875]; | |
| 344 | + }; | |
| 345 | + struct { /* 900: DMA */ | |
| 346 | + uchar rsv13[4]; | |
| 347 | + ulong sdar; | |
| 348 | + uchar sdsr; | |
| 349 | + uchar pad1[3]; | |
| 350 | + uchar sdmr; | |
| 351 | + uchar pad2[3]; | |
| 352 | + uchar idsr1; | |
| 353 | + uchar pad3[3]; | |
| 354 | + uchar idmr1; | |
| 355 | + uchar pad4[3]; | |
| 356 | + uchar idsr2; | |
| 357 | + uchar pad5[3]; | |
| 358 | + uchar idmr2; | |
| 359 | + uchar pad6[0x930-0x91D]; | |
| 360 | + }; | |
| 361 | + struct { /* CPM interrupt control */ | |
| 362 | + ushort civr; | |
| 363 | + uchar pad7[0x940-0x932]; | |
| 364 | + ulong cicr; | |
| 365 | + ulong cipr; | |
| 366 | + ulong cimr; | |
| 367 | + ulong cisr; | |
| 368 | + }; | |
| 369 | + struct { /* input/output port */ | |
| 370 | + ushort padir; | |
| 371 | + ushort papar; | |
| 372 | + ushort paodr; | |
| 373 | + ushort padat; | |
| 374 | + uchar pad8[8]; | |
| 375 | + ushort pcdir; | |
| 376 | + ushort pcpar; | |
| 377 | + ushort pcso; | |
| 378 | + ushort pcdat; | |
| 379 | + ushort pcint; | |
| 380 | + uchar pad9[6]; | |
| 381 | + ushort pddir; | |
| 382 | + ushort pdpar; | |
| 383 | + ushort rsv14a; | |
| 384 | + ushort pddat; | |
| 385 | + uchar rsv14[0x980-0x978]; | |
| 386 | + }; | |
| 387 | + struct { /* CPM timers */ | |
| 388 | + ushort tgcr; | |
| 389 | + uchar rsv15a[0x990-0x982]; | |
| 390 | + ushort tmr1; | |
| 391 | + ushort tmr2; | |
| 392 | + ushort trr1; | |
| 393 | + ushort trr2; | |
| 394 | + ushort tcr1; | |
| 395 | + ushort tcr2; | |
| 396 | + ushort tcn1; | |
| 397 | + ushort tcn2; | |
| 398 | + ushort tmr3; | |
| 399 | + ushort tmr4; | |
| 400 | + ushort trr3; | |
| 401 | + ushort trr4; | |
| 402 | + ushort tcr3; | |
| 403 | + ushort tcr4; | |
| 404 | + ushort tcn3; | |
| 405 | + ushort tcn4; | |
| 406 | + ushort ter1; | |
| 407 | + ushort ter2; | |
| 408 | + ushort ter3; | |
| 409 | + ushort ter4; | |
| 410 | + uchar rsv15[0x9C0-0x9B8]; | |
| 411 | + }; | |
| 412 | + struct { /* CPM */ | |
| 413 | + ushort cpcr; | |
| 414 | + uchar res0[2]; | |
| 415 | + ushort rccr; | |
| 416 | + uchar res1; | |
| 417 | + uchar rmds; | |
| 418 | + uchar res2a[4]; | |
| 419 | + ushort rctr1; | |
| 420 | + ushort rctr2; | |
| 421 | + ushort rctr3; | |
| 422 | + ushort rctr4; | |
| 423 | + uchar res2[2]; | |
| 424 | + ushort rter; | |
| 425 | + uchar res3[2]; | |
| 426 | + ushort rtmr; | |
| 427 | + uchar rsv16[0x9F0-0x9DC]; | |
| 428 | + }; | |
| 429 | + union { /* BRG */ | |
| 430 | + struct { | |
| 431 | + ulong brgc1; | |
| 432 | + ulong brgc2; | |
| 433 | + ulong brgc3; | |
| 434 | + ulong brgc4; | |
| 435 | + }; | |
| 436 | + ulong brgc[4]; | |
| 437 | + }; | |
| 438 | + uchar skip0[0xAB2-0xA00]; /* USB, SCC, SMC, SPI: address using cpmdev(CP...)->regs */ | |
| 439 | + struct { /* PIP */ | |
| 440 | + ushort pipc; /* not 823 */ | |
| 441 | + ushort ptpr; /* not 823 */ | |
| 442 | + ulong pbdir; | |
| 443 | + ulong pbpar; | |
| 444 | + uchar pad10[2]; | |
| 445 | + ushort pbodr; | |
| 446 | + ulong pbdat; | |
| 447 | + uchar pad11[0xAE0-0xAC8]; | |
| 448 | + }; | |
| 449 | + struct { /* SI */ | |
| 450 | + ulong simode; | |
| 451 | + uchar sigmr; | |
| 452 | + uchar pad12; | |
| 453 | + uchar sistr; | |
| 454 | + uchar sicmr; | |
| 455 | + uchar pad13[4]; | |
| 456 | + ulong sicr; | |
| 457 | + ulong sirp; | |
| 458 | + uchar pad14[0xB00-0xAF4]; | |
| 459 | + }; | |
| 460 | + ulong vcram[64]; | |
| 461 | + ushort siram[256]; | |
| 462 | + ushort lcdmap[256]; | |
| 463 | +}; | |
| @@ -0,0 +1,98 @@ | ||
| 1 | +typedef struct Udphdr Udphdr; | |
| 2 | +struct Udphdr | |
| 3 | +{ | |
| 4 | + uchar d[6]; /* Ethernet destination */ | |
| 5 | + uchar s[6]; /* Ethernet source */ | |
| 6 | + uchar type[2]; /* Ethernet packet type */ | |
| 7 | + | |
| 8 | + uchar vihl; /* Version and header length */ | |
| 9 | + uchar tos; /* Type of service */ | |
| 10 | + uchar length[2]; /* packet length */ | |
| 11 | + uchar id[2]; /* Identification */ | |
| 12 | + uchar frag[2]; /* Fragment information */ | |
| 13 | + | |
| 14 | + /* Udp pseudo ip really starts here */ | |
| 15 | + uchar ttl; | |
| 16 | + uchar udpproto; /* Protocol */ | |
| 17 | + uchar udpplen[2]; /* Header plus data length */ | |
| 18 | + uchar udpsrc[4]; /* Ip source */ | |
| 19 | + uchar udpdst[4]; /* Ip destination */ | |
| 20 | + uchar udpsport[2]; /* Source port */ | |
| 21 | + uchar udpdport[2]; /* Destination port */ | |
| 22 | + uchar udplen[2]; /* data length */ | |
| 23 | + uchar udpcksum[2]; /* Checksum */ | |
| 24 | +}; | |
| 25 | + | |
| 26 | +typedef struct Etherhdr Etherhdr; | |
| 27 | +struct Etherhdr | |
| 28 | +{ | |
| 29 | + uchar d[6]; | |
| 30 | + uchar s[6]; | |
| 31 | + uchar type[2]; | |
| 32 | + | |
| 33 | + /* Now we have the ip fields */ | |
| 34 | + uchar vihl; /* Version and header length */ | |
| 35 | + uchar tos; /* Type of service */ | |
| 36 | + uchar length[2]; /* packet length */ | |
| 37 | + uchar id[2]; /* Identification */ | |
| 38 | + uchar frag[2]; /* Fragment information */ | |
| 39 | + uchar ttl; /* Time to live */ | |
| 40 | + uchar proto; /* Protocol */ | |
| 41 | + uchar cksum[2]; /* Header checksum */ | |
| 42 | + uchar src[4]; /* Ip source */ | |
| 43 | + uchar dst[4]; /* Ip destination */ | |
| 44 | +}; | |
| 45 | + | |
| 46 | +enum | |
| 47 | +{ | |
| 48 | + IP_VER = 0x40, | |
| 49 | + IP_HLEN = 0x05, | |
| 50 | + UDP_EHSIZE = 22, | |
| 51 | + UDP_PHDRSIZE = 12, | |
| 52 | + UDP_HDRSIZE = 20, | |
| 53 | + ETHER_HDR = 14, | |
| 54 | + IP_UDPPROTO = 17, | |
| 55 | + ET_IP = 0x800, | |
| 56 | + Bcastip = 0xffffffff, | |
| 57 | + BPportsrc = 68, | |
| 58 | + BPportdst = 67, | |
| 59 | + TFTPport = 69, | |
| 60 | + Timeout = 5000, /* milliseconds */ | |
| 61 | + Bootrequest = 1, | |
| 62 | + Bootreply = 2, | |
| 63 | + Tftp_READ = 1, | |
| 64 | + Tftp_WRITE = 2, | |
| 65 | + Tftp_DATA = 3, | |
| 66 | + Tftp_ACK = 4, | |
| 67 | + Tftp_ERROR = 5, | |
| 68 | + Segsize = 512, | |
| 69 | + TFTPSZ = Segsize+10, | |
| 70 | +}; | |
| 71 | + | |
| 72 | +typedef struct Bootp Bootp; | |
| 73 | +struct Bootp | |
| 74 | +{ | |
| 75 | + uchar op; /* opcode */ | |
| 76 | + uchar htype; /* hardware type */ | |
| 77 | + uchar hlen; /* hardware address len */ | |
| 78 | + uchar hops; /* hops */ | |
| 79 | + uchar xid[4]; /* a random number */ | |
| 80 | + uchar secs[2]; /* elapsed snce client started booting */ | |
| 81 | + uchar pad[2]; | |
| 82 | + uchar ciaddr[4]; /* client IP address (client tells server) */ | |
| 83 | + uchar yiaddr[4]; /* client IP address (server tells client) */ | |
| 84 | + uchar siaddr[4]; /* server IP address */ | |
| 85 | + uchar giaddr[4]; /* gateway IP address */ | |
| 86 | + uchar chaddr[16]; /* client hardware address */ | |
| 87 | + char sname[64]; /* server host name (optional) */ | |
| 88 | + char file[128]; /* boot file name */ | |
| 89 | + char vend[128]; /* vendor-specific goo */ | |
| 90 | +}; | |
| 91 | + | |
| 92 | +typedef struct Netaddr Netaddr; | |
| 93 | +struct Netaddr | |
| 94 | +{ | |
| 95 | + ulong ip; | |
| 96 | + ushort port; | |
| 97 | + char ea[Eaddrlen]; | |
| 98 | +}; | |
| @@ -0,0 +1,370 @@ | ||
| 1 | +#include "mem.h" | |
| 2 | + | |
| 3 | +/* special instruction definitions */ | |
| 4 | +#define BDNE BC 0,2, | |
| 5 | +#define BDNZ BC 16,0, | |
| 6 | +#define NOOP OR R0,R0,R0 | |
| 7 | + | |
| 8 | +/* | |
| 9 | + * common ppc special purpose registers | |
| 10 | + */ | |
| 11 | +#define DSISR 18 | |
| 12 | +#define DAR 19 /* Data Address Register */ | |
| 13 | +#define DEC 22 /* Decrementer */ | |
| 14 | +#define SRR0 26 /* Saved Registers (exception) */ | |
| 15 | +#define SRR1 27 | |
| 16 | +#define SPRG0 272 /* Supervisor Private Registers */ | |
| 17 | +#define SPRG1 273 | |
| 18 | +#define SPRG2 274 | |
| 19 | +#define SPRG3 275 | |
| 20 | +#define TBRU 269 /* Time base Upper/Lower (Reading) */ | |
| 21 | +#define TBRL 268 | |
| 22 | +#define TBWU 285 /* Time base Upper/Lower (Writing) */ | |
| 23 | +#define TBWL 284 | |
| 24 | +#define PVR 287 /* Processor Version */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * mpc82x-specific special purpose registers of interest here | |
| 28 | + */ | |
| 29 | +#define EIE 80 | |
| 30 | +#define EID 81 | |
| 31 | +#define NRI 82 | |
| 32 | +#define IMMR 638 | |
| 33 | +#define IC_CST 560 | |
| 34 | +#define IC_ADR 561 | |
| 35 | +#define IC_DAT 562 | |
| 36 | +#define DC_CST 568 | |
| 37 | +#define DC_ADR 569 | |
| 38 | +#define DC_DAT 570 | |
| 39 | +#define MI_CTR 784 | |
| 40 | +#define MI_AP 786 | |
| 41 | +#define MI_EPN 787 | |
| 42 | +#define MI_TWC 789 | |
| 43 | +#define MI_RPN 790 | |
| 44 | +#define MI_DBCAM 816 | |
| 45 | +#define MI_DBRAM0 817 | |
| 46 | +#define MI_DBRAM1 818 | |
| 47 | +#define MD_CTR 792 | |
| 48 | +#define M_CASID 793 | |
| 49 | +#define MD_AP 794 | |
| 50 | +#define MD_EPN 795 | |
| 51 | +#define M_TWB 796 | |
| 52 | +#define MD_TWC 797 | |
| 53 | +#define MD_RPN 798 | |
| 54 | +#define M_TW 799 | |
| 55 | +#define MD_DBCAM 824 | |
| 56 | +#define MD_DBRAM0 825 | |
| 57 | +#define MD_DBRAM1 826 | |
| 58 | + | |
| 59 | +/* as on 603e, apparently mtmsr needs help in some chip revisions */ | |
| 60 | +#define WAITMSR SYNC; ISYNC | |
| 61 | + | |
| 62 | +/* use of SPRG registers in save/restore */ | |
| 63 | +#define SAVER0 SPRG0 | |
| 64 | +#define SAVER1 SPRG1 | |
| 65 | +#define SAVELR SPRG2 | |
| 66 | +#define SAVECR SPRG3 | |
| 67 | + | |
| 68 | +#define UREGSIZE ((8+32)*4) | |
| 69 | +#define UREGSPACE (UREGSIZE+8) /* allow for arg to trap, and align */ | |
| 70 | + | |
| 71 | +/* | |
| 72 | + * This code is loaded by the ROM loader at location 0x3000, | |
| 73 | + * or lives in flash memory at 0x2800100. | |
| 74 | + * Move it to high memory so that it can load the kernel at 0x0000. | |
| 75 | + */ | |
| 76 | + | |
| 77 | +#define LOADCODEBASE 0x3000 /* when downloaded in S records */ | |
| 78 | +#define FLASHCODEBASE (FLASHMEM+0x100) /* when in flash */ | |
| 79 | + | |
| 80 | + TEXT start(SB), $-4 | |
| 81 | + MOVW MSR, R3 | |
| 82 | + MOVW $(EE|IP|RI), R4 | |
| 83 | + ANDN R4, R3 | |
| 84 | + OR $ME, R3 | |
| 85 | + SYNC | |
| 86 | + MOVW R3, MSR /* turn off interrupts but enable traps */ | |
| 87 | + WAITMSR | |
| 88 | + | |
| 89 | +/* | |
| 90 | + * reset the caches and disable them for now | |
| 91 | + */ | |
| 92 | + MOVW SPR(IC_CST), R4 /* read and clear */ | |
| 93 | + MOVW $(5<<25), R4 | |
| 94 | + MOVW R4, SPR(IC_CST) /* unlock all */ | |
| 95 | + ISYNC | |
| 96 | + MOVW $(6<<25), R4 | |
| 97 | + MOVW R4, SPR(IC_CST) /* invalidate all */ | |
| 98 | + ISYNC | |
| 99 | + MOVW $(2<<25), R4 | |
| 100 | + MOVW R4, SPR(IC_CST) /* disable i-cache */ | |
| 101 | + ISYNC | |
| 102 | + | |
| 103 | + SYNC | |
| 104 | + MOVW SPR(DC_CST), R4 /* read and clear */ | |
| 105 | + MOVW $(10<<24), R4 | |
| 106 | + MOVW R4, SPR(DC_CST) /* unlock all */ | |
| 107 | + ISYNC | |
| 108 | + MOVW $(12<<24), R4 | |
| 109 | + MOVW R4, SPR(DC_CST) /* invalidate all */ | |
| 110 | + ISYNC | |
| 111 | + MOVW $(4<<24), R4 | |
| 112 | + MOVW R4, SPR(DC_CST) /* disable i-cache */ | |
| 113 | + ISYNC | |
| 114 | + | |
| 115 | + MOVW $7, R4 | |
| 116 | +ANDN R4, R4, R4 | |
| 117 | + MOVW R4, SPR(158) /* cancel `show cycle' for normal instruction execution */ | |
| 118 | + | |
| 119 | +/* | |
| 120 | + * set other system configuration values | |
| 121 | + */ | |
| 122 | + MOVW SPR(IMMR), R5 /* save initial space pointer */ | |
| 123 | + MOVW $INTMEM, R4 | |
| 124 | + MOVW R4, SPR(IMMR) /* set internal memory base */ | |
| 125 | + MOVW $0xFFFFFF88, R3 | |
| 126 | + MOVW R3, 4(R4) /* disable watchdog in sypcr */ | |
| 127 | + MOVW $0x01012440, R3 | |
| 128 | + MOVW R3, 0(R4) /* siumcr */ | |
| 129 | + | |
| 130 | +/* | |
| 131 | + * system initialisation (init and map DRAM) | |
| 132 | + */ | |
| 133 | + MOVW $0, R0 | |
| 134 | + MOVW $setSB(SB), R2 | |
| 135 | + MOVW $(0xF000<<16), R3 | |
| 136 | +/*MOVW R0, R3*/ | |
| 137 | + ANDCC R5, R3 /* initial space is high? */ | |
| 138 | + BEQ notrom | |
| 139 | + MOVW $FLASHCODEBASE, R5 /* where $start(SB) actually is now */ | |
| 140 | + MOVW $start(SB), R4 /* logical start address */ | |
| 141 | + SUB R4, R5, R6 /* text relocation value */ | |
| 142 | + MOVW $etext(SB), R7 | |
| 143 | + SUB R4, R7 | |
| 144 | + ADD R5, R7 /* data address in ROM */ | |
| 145 | + MOVW $bdata(SB), R8 | |
| 146 | + SUB R8, R2 | |
| 147 | + ADD R7, R2 /* relocate SB: SB' = romdata+(SB-bdata) */ | |
| 148 | + MOVW $sysinit0(SB), R4 | |
| 149 | + ADD R6, R4 /* relocate sysinit0's address */ | |
| 150 | + MOVW R4, CTR | |
| 151 | + MOVW $inmem(SB), R4 | |
| 152 | + ADD R6, R4 | |
| 153 | + MOVW R4, LR /* and the return address */ | |
| 154 | + BR (CTR) /* call sysinit0 */ | |
| 155 | + TEXT inmem(SB), $-4 | |
| 156 | + MOVW $FLASHCODEBASE, R3 | |
| 157 | + BR cpu0 | |
| 158 | +notrom: | |
| 159 | + MOVW $start(SB), R6 | |
| 160 | + SUB R6, R2 | |
| 161 | + ADD $LOADCODEBASE, R2 | |
| 162 | + BL sysinit0(SB) | |
| 163 | + MOVW $LOADCODEBASE, R3 | |
| 164 | + | |
| 165 | +/* | |
| 166 | + * cpu 0 | |
| 167 | + * relocate bootstrap to our link addresses for text and data | |
| 168 | + * set new PC | |
| 169 | + */ | |
| 170 | +cpu0: | |
| 171 | + MOVW $setSB(SB), R2 /* set correct static base register */ | |
| 172 | + MOVW $start(SB), R4 | |
| 173 | + MOVW $etext(SB), R5 | |
| 174 | + SUB R4, R5 | |
| 175 | + CMP R4, R3 /* already there? */ | |
| 176 | + BNE copytext | |
| 177 | + ADD R5, R3 /* start of data image */ | |
| 178 | + BR copydata | |
| 179 | + | |
| 180 | +copytext: | |
| 181 | + ADD $3, R5 | |
| 182 | + SRAW $2, R5 | |
| 183 | + MOVW R5, CTR | |
| 184 | + SUB $4, R4 | |
| 185 | + SUB $4, R3 | |
| 186 | +copyt: /* copy text */ | |
| 187 | + MOVWU 4(R3), R5 | |
| 188 | + MOVWU R5, 4(R4) | |
| 189 | + BDNZ copyt | |
| 190 | + ADD $4, R3 | |
| 191 | + | |
| 192 | +copydata: | |
| 193 | + /* copy data */ | |
| 194 | + MOVW $bdata(SB), R4 | |
| 195 | + CMP R4, R3 /* already there? */ | |
| 196 | + BEQ loadkpc | |
| 197 | + MOVW $edata(SB), R5 | |
| 198 | + SUB R4, R5 | |
| 199 | + ADD $3, R5 | |
| 200 | + SRAW $2, R5 | |
| 201 | + MOVW R5, CTR | |
| 202 | + SUB $4, R4 | |
| 203 | + SUB $4, R3 | |
| 204 | +copyd: | |
| 205 | + MOVWU 4(R3), R5 | |
| 206 | + MOVWU R5, 4(R4) | |
| 207 | + BDNZ copyd | |
| 208 | + | |
| 209 | + /* load correct PC */ | |
| 210 | +loadkpc: | |
| 211 | + MOVW $start1(SB), R3 | |
| 212 | + MOVW R3, LR | |
| 213 | + BR (LR) | |
| 214 | +TEXT start1(SB), $-4 | |
| 215 | + MOVW $edata(SB), R3 | |
| 216 | + MOVW $end(SB), R4 | |
| 217 | + SUBCC R3, R4 | |
| 218 | + BLE skipz | |
| 219 | + SRAW $2, R4 | |
| 220 | + MOVW R4, CTR | |
| 221 | + SUB $4, R3 | |
| 222 | + MOVW $0, R0 | |
| 223 | +zero: | |
| 224 | + MOVWU R0, 4(R3) | |
| 225 | + BDNZ zero | |
| 226 | +skipz: | |
| 227 | + MOVW $mach0(SB), R1 | |
| 228 | + MOVW R1, m(SB) | |
| 229 | + ADD $(MACHSIZE-8), R1 | |
| 230 | + MOVW $0, R0 | |
| 231 | + BL main(SB) | |
| 232 | + BR 0(PC) | |
| 233 | + | |
| 234 | +TEXT getmsr(SB), $0 | |
| 235 | + MOVW MSR, R3 | |
| 236 | + RETURN | |
| 237 | + | |
| 238 | +TEXT putmsr(SB), $0 | |
| 239 | + SYNC | |
| 240 | + MOVW R3, MSR | |
| 241 | + WAITMSR | |
| 242 | + RETURN | |
| 243 | + | |
| 244 | +TEXT eieio(SB), $0 | |
| 245 | + EIEIO | |
| 246 | + RETURN | |
| 247 | + | |
| 248 | +TEXT idle(SB), $0 | |
| 249 | + RETURN | |
| 250 | + | |
| 251 | +TEXT spllo(SB), $0 | |
| 252 | + MOVW MSR, R3 | |
| 253 | + OR $EE, R3, R4 | |
| 254 | + SYNC | |
| 255 | + MOVW R4, MSR | |
| 256 | + WAITMSR | |
| 257 | + RETURN | |
| 258 | + | |
| 259 | +TEXT splhi(SB), $0 | |
| 260 | + MOVW MSR, R3 | |
| 261 | + RLWNM $0, R3, $~EE, R4 | |
| 262 | + SYNC | |
| 263 | + MOVW R4, MSR | |
| 264 | + WAITMSR | |
| 265 | + RETURN | |
| 266 | + | |
| 267 | +TEXT splx(SB), $0 | |
| 268 | + MOVW MSR, R4 | |
| 269 | + RLWMI $0, R3, $EE, R4 | |
| 270 | + SYNC | |
| 271 | + MOVW R4, MSR | |
| 272 | + WAITMSR | |
| 273 | + RETURN | |
| 274 | + | |
| 275 | +TEXT gettbl(SB), $0 | |
| 276 | +/* MOVW SPR(TBRL), R3 */ | |
| 277 | + WORD $0x7c6c42e6 /* mftbl on 8xx series */ | |
| 278 | + RETURN | |
| 279 | + | |
| 280 | +TEXT getpvr(SB), $0 | |
| 281 | + MOVW SPR(PVR), R3 | |
| 282 | + RETURN | |
| 283 | + | |
| 284 | +TEXT getimmr(SB), $0 | |
| 285 | + MOVW SPR(IMMR), R3 | |
| 286 | + RETURN | |
| 287 | + | |
| 288 | +TEXT getdec(SB), $0 | |
| 289 | + MOVW SPR(DEC), R3 | |
| 290 | + RETURN | |
| 291 | + | |
| 292 | +TEXT putdec(SB), $0 | |
| 293 | + MOVW R3, SPR(DEC) | |
| 294 | + RETURN | |
| 295 | + | |
| 296 | +/* | |
| 297 | + * save state in Ureg on kernel stack. | |
| 298 | + * enter with R0 giving the PC from the call to `exception' from the vector. | |
| 299 | + * on return, SB (R2) has been set, and R3 has the Ureg* | |
| 300 | + */ | |
| 301 | +TEXT saveureg(SB), $-4 | |
| 302 | + SUB $UREGSPACE, R1 | |
| 303 | + MOVMW R2, 48(R1) /* r2:r31 */ | |
| 304 | + MOVW $setSB(SB), R2 | |
| 305 | + MOVW SPR(SAVER1), R4 | |
| 306 | + MOVW R4, 44(R1) | |
| 307 | + MOVW SPR(SAVER0), R5 | |
| 308 | + MOVW R5, 40(R1) | |
| 309 | + MOVW CTR, R6 | |
| 310 | + MOVW R6, 36(R1) | |
| 311 | + MOVW XER, R4 | |
| 312 | + MOVW R4, 32(R1) | |
| 313 | + MOVW SPR(SAVECR), R5 /* CR */ | |
| 314 | + MOVW R5, 28(R1) | |
| 315 | + MOVW SPR(SAVELR), R6 /* LR */ | |
| 316 | + MOVW R6, 24(R1) | |
| 317 | + /* pad at 20(R1) */ | |
| 318 | + MOVW SPR(SRR0), R4 | |
| 319 | + MOVW R4, 16(R1) /* old PC */ | |
| 320 | + MOVW SPR(SRR1), R5 | |
| 321 | + MOVW R5, 12(R1) | |
| 322 | + MOVW R0, 8(R1) /* cause/vector, encoded in LR from vector */ | |
| 323 | + ADD $8, R1, R3 /* Ureg* */ | |
| 324 | + STWCCC R3, (R1) /* break any pending reservations */ | |
| 325 | + MOVW $0, R0 /* R0ISZERO */ | |
| 326 | + BR (LR) | |
| 327 | + | |
| 328 | +/* | |
| 329 | + * restore state from Ureg | |
| 330 | + * SB (R2) is unusable on return | |
| 331 | + */ | |
| 332 | +TEXT restoreureg(SB), $-4 | |
| 333 | + MOVMW 48(R1), R2 /* r2:r31 */ | |
| 334 | + /* defer R1 */ | |
| 335 | + MOVW 40(R1), R0 | |
| 336 | + MOVW R0, SPR(SAVER0) | |
| 337 | + MOVW 36(R1), R0 | |
| 338 | + MOVW R0, CTR | |
| 339 | + MOVW 32(R1), R0 | |
| 340 | + MOVW R0, XER | |
| 341 | + MOVW 28(R1), R0 | |
| 342 | + MOVW R0, CR /* CR */ | |
| 343 | + MOVW 24(R1), R0 | |
| 344 | + MOVW R0, SPR(SAVELR) /* LR */ | |
| 345 | + /* pad, skip */ | |
| 346 | + MOVW 16(R1), R0 | |
| 347 | + MOVW R0, SPR(SRR0) /* old PC */ | |
| 348 | + MOVW 12(R1), R0 | |
| 349 | + MOVW R0, SPR(SRR1) /* old MSR */ | |
| 350 | + /* cause, skip */ | |
| 351 | + MOVW 44(R1), R1 /* old SP */ | |
| 352 | + BR (LR) | |
| 353 | + | |
| 354 | +TEXT exception(SB), $-4 | |
| 355 | + MOVW R1, SPR(SAVER1) | |
| 356 | + MOVW CR, R0 | |
| 357 | + MOVW R0, SPR(SAVECR) | |
| 358 | + MOVW LR, R0 | |
| 359 | + BL saveureg(SB) | |
| 360 | + MOVW $0, R0 | |
| 361 | + BL trap(SB) | |
| 362 | + BL restoreureg(SB) | |
| 363 | + MOVW SPR(SAVELR), R0 | |
| 364 | + MOVW R0, LR | |
| 365 | + MOVW SPR(SAVER0), R0 | |
| 366 | + ISYNC | |
| 367 | + RFI | |
| 368 | + | |
| 369 | +GLOBL mach0+0(SB), $MACHSIZE | |
| 370 | +GLOBL m(SB), $4 | |
| @@ -0,0 +1,106 @@ | ||
| 1 | +/* | |
| 2 | + * functions (possibly) linked in, complete, from libc. | |
| 3 | + */ | |
| 4 | + | |
| 5 | +/* | |
| 6 | + * mem routines | |
| 7 | + */ | |
| 8 | +extern void* memccpy(void*, void*, int, long); | |
| 9 | +extern void* memset(void*, int, long); | |
| 10 | +extern int memcmp(void*, void*, long); | |
| 11 | +extern void* memmove(void*, void*, long); | |
| 12 | +extern void* memchr(void*, int, long); | |
| 13 | + | |
| 14 | +/* | |
| 15 | + * string routines | |
| 16 | + */ | |
| 17 | +extern char* strcat(char*, char*); | |
| 18 | +extern char* strchr(char*, char); | |
| 19 | +extern int strcmp(char*, char*); | |
| 20 | +extern char* strcpy(char*, char*); | |
| 21 | +extern char* strncat(char*, char*, long); | |
| 22 | +extern char* strncpy(char*, char*, long); | |
| 23 | +extern int strncmp(char*, char*, long); | |
| 24 | +extern long strlen(char*); | |
| 25 | +extern char* strrchr(char*, char); | |
| 26 | +extern char* strstr(char*, char*); | |
| 27 | + | |
| 28 | +/* | |
| 29 | + * print routines | |
| 30 | + * Fconv isn't used but is defined to satisfy prototypes in libg.h | |
| 31 | + * that are never called. | |
| 32 | + */ | |
| 33 | +typedef struct Fconv Fconv; | |
| 34 | + | |
| 35 | +extern char* donprint(char*, char*, char*, void*); | |
| 36 | +extern int sprint(char*, char*, ...); | |
| 37 | +extern int print(char*, ...); | |
| 38 | + | |
| 39 | +#define PRINTSIZE 256 | |
| 40 | + | |
| 41 | +/* | |
| 42 | + * one-of-a-kind | |
| 43 | + */ | |
| 44 | +extern int atoi(char*); | |
| 45 | +extern long strtol(char*, char**, int); | |
| 46 | +extern ulong strtoul(char*, char**, int); | |
| 47 | +extern long end; | |
| 48 | + | |
| 49 | +/* | |
| 50 | + * Syscall data structures | |
| 51 | + */ | |
| 52 | + | |
| 53 | +#define MORDER 0x0003 /* mask for bits defining order of mounting */ | |
| 54 | +#define MREPL 0x0000 /* mount replaces object */ | |
| 55 | +#define MBEFORE 0x0001 /* mount goes before others in union directory */ | |
| 56 | +#define MAFTER 0x0002 /* mount goes after others in union directory */ | |
| 57 | +#define MCREATE 0x0004 /* permit creation in mounted directory */ | |
| 58 | +#define MMASK 0x0007 /* all bits on */ | |
| 59 | + | |
| 60 | +#define OREAD 0 /* open for read */ | |
| 61 | +#define OWRITE 1 /* write */ | |
| 62 | +#define ORDWR 2 /* read and write */ | |
| 63 | +#define OEXEC 3 /* execute, == read but check execute permission */ | |
| 64 | +#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ | |
| 65 | +#define OCEXEC 32 /* or'ed in, close on exec */ | |
| 66 | +#define ORCLOSE 64 /* or'ed in, remove on close */ | |
| 67 | + | |
| 68 | +#define NCONT 0 /* continue after note */ | |
| 69 | +#define NDFLT 1 /* terminate after note */ | |
| 70 | + | |
| 71 | +typedef struct Qid Qid; | |
| 72 | +typedef struct Dir Dir; | |
| 73 | +typedef struct Waitmsg Waitmsg; | |
| 74 | + | |
| 75 | +#define ERRLEN 64 | |
| 76 | +#define DIRLEN 116 | |
| 77 | +#define NAMELEN 28 | |
| 78 | + | |
| 79 | +struct Qid | |
| 80 | +{ | |
| 81 | + ulong path; | |
| 82 | + ulong vers; | |
| 83 | +}; | |
| 84 | + | |
| 85 | +struct Dir | |
| 86 | +{ | |
| 87 | + char name[NAMELEN]; | |
| 88 | + char uid[NAMELEN]; | |
| 89 | + char gid[NAMELEN]; | |
| 90 | + Qid qid; | |
| 91 | + ulong mode; | |
| 92 | + long atime; | |
| 93 | + long mtime; | |
| 94 | + vlong length; | |
| 95 | + short type; | |
| 96 | + short dev; | |
| 97 | +}; | |
| 98 | + | |
| 99 | +struct Waitmsg | |
| 100 | +{ | |
| 101 | + int pid; /* of loved one */ | |
| 102 | + int status; /* unused; a placeholder */ | |
| 103 | + ulong time[3]; /* of loved one */ | |
| 104 | + char msg[ERRLEN]; | |
| 105 | +}; | |
| 106 | +#define nelem(x) (sizeof(x)/sizeof((x)[0])) | |
| @@ -0,0 +1,524 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +#include "dosfs.h" | |
| 9 | + | |
| 10 | +typedef struct Type Type; | |
| 11 | +typedef struct Medium Medium; | |
| 12 | +typedef struct Mode Mode; | |
| 13 | + | |
| 14 | +enum { | |
| 15 | + Dany = -1, | |
| 16 | + Nmedia = 16, | |
| 17 | + | |
| 18 | + /* DS1 switch options */ | |
| 19 | + Sflashfs = 1<<0, /* take local fs from flash */ | |
| 20 | + Snotflash = 1<<1, /* don't boot from flash */ | |
| 21 | +}; | |
| 22 | + | |
| 23 | +enum { /* type */ | |
| 24 | + Tflash, | |
| 25 | + Tuart, | |
| 26 | + Tether, | |
| 27 | + Thard, | |
| 28 | + | |
| 29 | + Tany = -1, | |
| 30 | +}; | |
| 31 | + | |
| 32 | +enum { /* flag and name */ | |
| 33 | + Fnone = 0x00, | |
| 34 | + | |
| 35 | + Fdos = 0x01, | |
| 36 | + Ndos = 0x00, | |
| 37 | + Fboot = 0x02, | |
| 38 | + Nboot = 0x01, | |
| 39 | + Fbootp = 0x04, | |
| 40 | + Nbootp = 0x02, | |
| 41 | + Fflash = 0x08, | |
| 42 | + Fuart = 0x10, | |
| 43 | + NName = 0x03, | |
| 44 | + | |
| 45 | + Fany = Fbootp|Fboot|Fdos|Fflash|Fuart, | |
| 46 | + | |
| 47 | + Fini = 0x10, | |
| 48 | + Fprobe = 0x80, | |
| 49 | +}; | |
| 50 | + | |
| 51 | +enum { /* mode */ | |
| 52 | + Mauto = 0x00, | |
| 53 | + Mlocal = 0x01, | |
| 54 | + Manual = 0x02, | |
| 55 | + NMode = 0x03, | |
| 56 | +}; | |
| 57 | + | |
| 58 | +typedef struct Type { | |
| 59 | + int type; | |
| 60 | + char *cname; | |
| 61 | + int flag; | |
| 62 | + int (*init)(void); | |
| 63 | + long (*read)(int, void*, long); | |
| 64 | + long (*seek)(int, long); | |
| 65 | + Partition* (*setpart)(int, char*); | |
| 66 | + char* name[NName]; | |
| 67 | + | |
| 68 | + int mask; | |
| 69 | + Medium* media; | |
| 70 | +} Type; | |
| 71 | + | |
| 72 | +typedef struct Medium { | |
| 73 | + Type* type; | |
| 74 | + int flag; | |
| 75 | + Partition* partition; | |
| 76 | + Dos; | |
| 77 | + | |
| 78 | + Medium* next; | |
| 79 | +} Medium; | |
| 80 | + | |
| 81 | +typedef struct Mode { | |
| 82 | + char* name; | |
| 83 | + int mode; | |
| 84 | +} Mode; | |
| 85 | + | |
| 86 | +static Type types[] = { | |
| 87 | + { Tflash, "flash", | |
| 88 | + Fflash, | |
| 89 | + flashinit, 0, 0, 0, | |
| 90 | + { 0, "F", 0, } | |
| 91 | + }, | |
| 92 | +/* | |
| 93 | + { Tuart, "uart", | |
| 94 | + Fuart|Fboot, | |
| 95 | + uartinit, uartread, uartseek, setuartpart, | |
| 96 | + { 0, "u", 0, } | |
| 97 | + }, | |
| 98 | +*/ | |
| 99 | + { Tether, "ether", | |
| 100 | + Fbootp, | |
| 101 | + etherinit, 0, 0, 0, | |
| 102 | + { 0, 0, "e", }, | |
| 103 | + }, | |
| 104 | + { Thard, "ata", | |
| 105 | + Fini|Fboot|Fdos, | |
| 106 | + 0, 0, 0, 0, /* not used now, will be later with PCMCIA */ | |
| 107 | + { "hd", "h", 0, }, | |
| 108 | + }, | |
| 109 | + {-1}, | |
| 110 | +}; | |
| 111 | + | |
| 112 | +static Medium media[Nmedia]; | |
| 113 | +static Medium *curmedium = media; | |
| 114 | + | |
| 115 | +static Mode modes[NMode+1] = { | |
| 116 | + [Mauto] { "auto", Mauto, }, | |
| 117 | + [Mlocal] { "local", Mlocal, }, | |
| 118 | + [Manual] { "manual", Manual, }, | |
| 119 | +}; | |
| 120 | + | |
| 121 | +static char *inis[] = { | |
| 122 | + "inferno/inferno.ini", | |
| 123 | + "inferno.ini", | |
| 124 | + "plan9/plan9.ini", | |
| 125 | + "plan9.ini", | |
| 126 | + 0, | |
| 127 | +}; | |
| 128 | +char **ini; | |
| 129 | +int predawn; | |
| 130 | + | |
| 131 | +static int | |
| 132 | +parse(char *line, int *type, int *flag, int *dev, char *file) | |
| 133 | +{ | |
| 134 | + Type *tp; | |
| 135 | + char buf[2*NAMELEN], *v[4], *p; | |
| 136 | + int i; | |
| 137 | + | |
| 138 | + strcpy(buf, line); | |
| 139 | + switch(getcfields(buf, v, 4, "!")){ | |
| 140 | + | |
| 141 | + case 3: | |
| 142 | + break; | |
| 143 | + | |
| 144 | + case 2: | |
| 145 | + v[2] = ""; | |
| 146 | + break; | |
| 147 | + | |
| 148 | + default: | |
| 149 | + return 0; | |
| 150 | + } | |
| 151 | + | |
| 152 | + *flag = 0; | |
| 153 | + for(tp = types; tp->cname; tp++){ | |
| 154 | + for(i = 0; i < NName; i++){ | |
| 155 | + | |
| 156 | + if(tp->name[i] == 0 || strcmp(v[0], tp->name[i])) | |
| 157 | + continue; | |
| 158 | + *type = tp->type; | |
| 159 | + *flag |= 1<<i; | |
| 160 | + | |
| 161 | + if((*dev = strtoul(v[1], &p, 0)) == 0 && p == v[1]) | |
| 162 | + return 0; | |
| 163 | + | |
| 164 | + strcpy(file, v[2]); | |
| 165 | + | |
| 166 | + return 1; | |
| 167 | + } | |
| 168 | + } | |
| 169 | + | |
| 170 | + return 0; | |
| 171 | + | |
| 172 | +} | |
| 173 | + | |
| 174 | +static int | |
| 175 | +boot(Medium *mp, int flag, char *file) | |
| 176 | +{ | |
| 177 | + Dosfile df; | |
| 178 | + char ixdos[128], *p; | |
| 179 | + int r; | |
| 180 | + | |
| 181 | + uartsetboot(0); | |
| 182 | + if(flag & Fbootp){ | |
| 183 | + sprint(BOOTLINE, "%s!%d", mp->type->name[Nbootp], mp->dev); | |
| 184 | + return bootp(mp->dev, file); | |
| 185 | + } | |
| 186 | + | |
| 187 | + if(flag & Fflash){ | |
| 188 | + if(mp->flag & Fflash && flashbootable(0)) | |
| 189 | + flashboot(mp->dev); | |
| 190 | + } | |
| 191 | + | |
| 192 | + if(flag & Fboot){ | |
| 193 | + | |
| 194 | + if(mp->flag & Fini){ | |
| 195 | + (*mp->type->setpart)(mp->dev, "disk"); | |
| 196 | + plan9ini(mp, nil); | |
| 197 | + } | |
| 198 | + if(file == 0 || *file == 0) | |
| 199 | + file = mp->partition->name; | |
| 200 | + (*mp->type->setpart)(mp->dev, file); | |
| 201 | + sprint(BOOTLINE, "%s!%d!%s", mp->type->name[Nboot], mp->dev, file); | |
| 202 | + r = plan9boot(mp->dev, mp->seek, mp->read); | |
| 203 | + uartsetboot(0); | |
| 204 | + return r; | |
| 205 | + } | |
| 206 | + | |
| 207 | + if(flag & Fdos){ | |
| 208 | + if(mp->type->setpart) | |
| 209 | + (*mp->type->setpart)(mp->dev, "disk"); | |
| 210 | + if(mp->flag & Fini) | |
| 211 | + plan9ini(mp, nil); | |
| 212 | + if(file == 0 || *file == 0){ | |
| 213 | + strcpy(ixdos, *ini); | |
| 214 | + if(p = strrchr(ixdos, '/')) | |
| 215 | + p++; | |
| 216 | + else | |
| 217 | + p = ixdos; | |
| 218 | + strcpy(p, "impc"); | |
| 219 | + if(dosstat(mp, ixdos, &df) <= 0) | |
| 220 | + return -1; | |
| 221 | + } | |
| 222 | + else | |
| 223 | + strcpy(ixdos, file); | |
| 224 | + sprint(BOOTLINE, "%s!%d!%s", mp->type->name[Ndos], mp->dev, ixdos); | |
| 225 | + return dosboot(mp, ixdos); | |
| 226 | + } | |
| 227 | + | |
| 228 | + return -1; | |
| 229 | +} | |
| 230 | + | |
| 231 | +static Medium* | |
| 232 | +allocm(Type *tp) | |
| 233 | +{ | |
| 234 | + Medium **l; | |
| 235 | + | |
| 236 | + if(curmedium >= &media[Nmedia]) | |
| 237 | + return 0; | |
| 238 | + | |
| 239 | + for(l = &tp->media; *l; l = &(*l)->next) | |
| 240 | + ; | |
| 241 | + *l = curmedium++; | |
| 242 | + return *l; | |
| 243 | +} | |
| 244 | + | |
| 245 | +Medium* | |
| 246 | +probe(int type, int flag, int dev) | |
| 247 | +{ | |
| 248 | + Type *tp; | |
| 249 | + int dombr, i, start; | |
| 250 | + Medium *mp; | |
| 251 | + Dosfile df; | |
| 252 | + Partition *pp; | |
| 253 | + | |
| 254 | + for(tp = types; tp->cname; tp++){ | |
| 255 | + if(type != Tany && type != tp->type || tp->init == 0) | |
| 256 | + continue; | |
| 257 | + | |
| 258 | + if(flag != Fnone){ | |
| 259 | + for(mp = tp->media; mp; mp = mp->next){ | |
| 260 | + if((flag & mp->flag) && (dev == Dany || dev == mp->dev)) | |
| 261 | + return mp; | |
| 262 | + } | |
| 263 | + } | |
| 264 | + if((tp->flag & Fprobe) == 0){ | |
| 265 | + tp->flag |= Fprobe; | |
| 266 | + tp->mask = (*tp->init)(); | |
| 267 | + } | |
| 268 | + | |
| 269 | + for(i = 0; tp->mask; i++){ | |
| 270 | + if((tp->mask & (1<<i)) == 0) | |
| 271 | + continue; | |
| 272 | + tp->mask &= ~(1<<i); | |
| 273 | + | |
| 274 | + if((mp = allocm(tp)) == 0) | |
| 275 | + continue; | |
| 276 | + | |
| 277 | + mp->dev = i; | |
| 278 | + mp->flag = tp->flag; | |
| 279 | + mp->seek = tp->seek; | |
| 280 | + mp->read = tp->read; | |
| 281 | + mp->type = tp; | |
| 282 | + | |
| 283 | + if(mp->flag & Fboot){ | |
| 284 | + if((mp->partition = (*tp->setpart)(i, "boot")) == 0) | |
| 285 | + mp->flag &= ~Fboot; | |
| 286 | + if((mp->flag & (Fflash|Fuart)) == 0) | |
| 287 | + (*tp->setpart)(i, "disk"); | |
| 288 | + } | |
| 289 | + | |
| 290 | + if(mp->flag & Fdos){ | |
| 291 | + start = 0; | |
| 292 | + dombr = 1; | |
| 293 | + if(mp->type->setpart){ | |
| 294 | + if(pp = (*mp->type->setpart)(i, "dos")){ | |
| 295 | + if(start = pp->start) | |
| 296 | + dombr = 0; | |
| 297 | + } | |
| 298 | + (*tp->setpart)(i, "disk"); | |
| 299 | + } | |
| 300 | + if(dosinit(mp, start, dombr) < 0) | |
| 301 | + mp->flag &= ~(Fini|Fdos); | |
| 302 | + else | |
| 303 | + print("dos init failed\n"); | |
| 304 | + } | |
| 305 | + | |
| 306 | + if(mp->flag & Fini){ | |
| 307 | + mp->flag &= ~Fini; | |
| 308 | + for(ini = inis; *ini; ini++){ | |
| 309 | + if(dosstat(mp, *ini, &df) <= 0) | |
| 310 | + continue; | |
| 311 | + mp->flag |= Fini; | |
| 312 | + break; | |
| 313 | + } | |
| 314 | + } | |
| 315 | + | |
| 316 | + if((flag & mp->flag) && (dev == Dany || dev == i)) | |
| 317 | + return mp; | |
| 318 | + } | |
| 319 | + } | |
| 320 | + | |
| 321 | + return 0; | |
| 322 | +} | |
| 323 | + | |
| 324 | +void | |
| 325 | +main(void) | |
| 326 | +{ | |
| 327 | + Medium *mp; | |
| 328 | + int dev, flag, i, mode, tried, type, options; | |
| 329 | + char def[2*NAMELEN], file[2*NAMELEN], line[80], *p; | |
| 330 | + Type *tp; | |
| 331 | + | |
| 332 | + machinit(); | |
| 333 | + archinit(); | |
| 334 | + meminit(); | |
| 335 | + cpminit(); | |
| 336 | + trapinit(); | |
| 337 | + consinit(); /* screen and keyboard initially */ | |
| 338 | + screeninit(); | |
| 339 | + cpuidprint(); | |
| 340 | + alarminit(); | |
| 341 | + clockinit(); | |
| 342 | + predawn = 0; | |
| 343 | + spllo(); | |
| 344 | + options = archoptionsw(); | |
| 345 | + | |
| 346 | + mp = 0; | |
| 347 | + for(tp = types; tp->cname; tp++){ | |
| 348 | + if(tp->type == Tether) | |
| 349 | + continue; | |
| 350 | + if((mp = probe(tp->type, Fini, Dany)) && (mp->flag & Fini)){ | |
| 351 | + plan9ini(mp, nil); | |
| 352 | + break; | |
| 353 | + } | |
| 354 | + } | |
| 355 | + | |
| 356 | + if(mp == 0 || (mp->flag & Fini) == 0) | |
| 357 | + plan9ini(nil, flashconfig(0)); | |
| 358 | + | |
| 359 | + //consinit(); /* establish new console location */ | |
| 360 | + | |
| 361 | + if((options & Snotflash) == 0 && flashbootable(0)){ | |
| 362 | + print("Flash boot\n"); | |
| 363 | + flashboot(0); | |
| 364 | + } | |
| 365 | + | |
| 366 | + tried = 0; | |
| 367 | + mode = Mauto; | |
| 368 | + p = getconf("bootfile"); | |
| 369 | + flag = 0; | |
| 370 | + | |
| 371 | + if(p != 0) { | |
| 372 | + mode = Manual; | |
| 373 | + for(i = 0; i < NMode; i++){ | |
| 374 | + if(strcmp(p, modes[i].name) == 0){ | |
| 375 | + mode = modes[i].mode; | |
| 376 | + goto done; | |
| 377 | + } | |
| 378 | + } | |
| 379 | + if(parse(p, &type, &flag, &dev, file) == 0) { | |
| 380 | + print("Bad bootfile syntax: %s\n", p); | |
| 381 | + goto done; | |
| 382 | + } | |
| 383 | + mp = probe(type, flag, dev); | |
| 384 | + if(mp == 0) { | |
| 385 | + print("Cannot access device: %s\n", p); | |
| 386 | + goto done; | |
| 387 | + } | |
| 388 | + tried = boot(mp, flag, file); | |
| 389 | + } | |
| 390 | +done: | |
| 391 | + if(tried == 0 && mode != Manual){ | |
| 392 | + flag = Fany; | |
| 393 | + if(mode == Mlocal) | |
| 394 | + flag &= ~Fbootp; | |
| 395 | + if(options & Snotflash) | |
| 396 | + flag &= ~Fflash; | |
| 397 | + if((mp = probe(Tany, flag, Dany)) != 0) | |
| 398 | + boot(mp, flag & mp->flag, 0); | |
| 399 | + } | |
| 400 | + | |
| 401 | + def[0] = 0; | |
| 402 | + probe(Tany, Fnone, Dany); | |
| 403 | + | |
| 404 | + flag = 0; | |
| 405 | + for(tp = types; tp->cname; tp++){ | |
| 406 | + for(mp = tp->media; mp; mp = mp->next){ | |
| 407 | + if(flag == 0){ | |
| 408 | + flag = 1; | |
| 409 | + print("Boot devices:"); | |
| 410 | + } | |
| 411 | + | |
| 412 | + if(mp->flag & Fbootp) | |
| 413 | + print(" %s!%d", mp->type->name[Nbootp], mp->dev); | |
| 414 | + if(mp->flag & Fdos) | |
| 415 | + print(" %s!%d", mp->type->name[Ndos], mp->dev); | |
| 416 | + if(mp->flag & (Fflash|Fuart) || mp->flag & Fboot) | |
| 417 | + print(" %s!%d", mp->type->name[Nboot], mp->dev); | |
| 418 | + } | |
| 419 | + } | |
| 420 | + if(flag) | |
| 421 | + print("\n"); | |
| 422 | + | |
| 423 | + for(;;){ | |
| 424 | + if(getstr("boot from", line, sizeof(line), def) >= 0){ | |
| 425 | + if(parse(line, &type, &flag, &dev, file)){ | |
| 426 | + if(mp = probe(type, flag, dev)) | |
| 427 | + boot(mp, flag, file); | |
| 428 | + } | |
| 429 | + } | |
| 430 | + def[0] = 0; | |
| 431 | + } | |
| 432 | +} | |
| 433 | + | |
| 434 | +void | |
| 435 | +machinit(void) | |
| 436 | +{ | |
| 437 | + memset(m, 0, sizeof(*m)); | |
| 438 | + m->delayloop = 20000; | |
| 439 | + m->cpupvr = getpvr(); | |
| 440 | + m->iomem = KADDR(INTMEM); | |
| 441 | +} | |
| 442 | + | |
| 443 | +int | |
| 444 | +getcfields(char* lp, char** fields, int n, char* sep) | |
| 445 | +{ | |
| 446 | + int i; | |
| 447 | + | |
| 448 | + for(i = 0; lp && *lp && i < n; i++){ | |
| 449 | + while(*lp && strchr(sep, *lp) != 0) | |
| 450 | + *lp++ = 0; | |
| 451 | + if(*lp == 0) | |
| 452 | + break; | |
| 453 | + fields[i] = lp; | |
| 454 | + while(*lp && strchr(sep, *lp) == 0){ | |
| 455 | + if(*lp == '\\' && *(lp+1) == '\n') | |
| 456 | + *lp++ = ' '; | |
| 457 | + lp++; | |
| 458 | + } | |
| 459 | + } | |
| 460 | + | |
| 461 | + return i; | |
| 462 | +} | |
| 463 | + | |
| 464 | +static Map memv[512]; | |
| 465 | +static RMap rammap = {"physical memory"}; | |
| 466 | + | |
| 467 | +void | |
| 468 | +meminit(void) | |
| 469 | +{ | |
| 470 | + ulong e; | |
| 471 | + | |
| 472 | + mapinit(&rammap, memv, sizeof(memv)); | |
| 473 | + e = PADDR(&end); | |
| 474 | + mapfree(&rammap, e, 4*1024*1024-e); /* fixed 4Mbytes is plenty for bootstrap */ | |
| 475 | +} | |
| 476 | + | |
| 477 | +void* | |
| 478 | +ialloc(ulong n, int align) | |
| 479 | +{ | |
| 480 | + ulong a; | |
| 481 | + int s; | |
| 482 | + | |
| 483 | + if(align <= 0) | |
| 484 | + align = 4; | |
| 485 | + s = splhi(); | |
| 486 | + a = mapalloc(&rammap, 0, n, align); | |
| 487 | + splx(s); | |
| 488 | + if(a == 0) | |
| 489 | + panic("ialloc"); | |
| 490 | + return memset(KADDR(a), 0, n); | |
| 491 | +} | |
| 492 | + | |
| 493 | +void* | |
| 494 | +malloc(ulong n) | |
| 495 | +{ | |
| 496 | + ulong *p; | |
| 497 | + | |
| 498 | + n = ((n+sizeof(int)-1)&~(sizeof(int)-1))+2*sizeof(int); | |
| 499 | + p = ialloc(n, sizeof(int)); | |
| 500 | + *p++ = 0xcafebeef; | |
| 501 | + *p++ = n; | |
| 502 | + return p; | |
| 503 | +} | |
| 504 | + | |
| 505 | +void | |
| 506 | +free(void *ap) | |
| 507 | +{ | |
| 508 | + int s; | |
| 509 | + ulong *p; | |
| 510 | + | |
| 511 | + p = ap; | |
| 512 | + if(p){ | |
| 513 | + if(*(p -= 2) != 0xcafebeef) | |
| 514 | + panic("free"); | |
| 515 | + s = splhi(); | |
| 516 | + mapfree(&rammap, (ulong)p, p[1]); | |
| 517 | + splx(s); | |
| 518 | + } | |
| 519 | +} | |
| 520 | + | |
| 521 | +void | |
| 522 | +sched(void) | |
| 523 | +{ | |
| 524 | +} | |
Empty file added.
| @@ -0,0 +1,95 @@ | ||
| 1 | +/* | |
| 2 | + * Memory and machine-specific definitions. Used in C and assembler. | |
| 3 | + */ | |
| 4 | + | |
| 5 | +/* | |
| 6 | + * Sizes | |
| 7 | + */ | |
| 8 | +#define BI2BY 8 /* bits per byte */ | |
| 9 | +#define BI2WD 32 /* bits per word */ | |
| 10 | +#define BY2WD 4 /* bytes per word */ | |
| 11 | +#define BY2PG 4096 /* bytes per page */ | |
| 12 | +#define WD2PG (BY2PG/BY2WD) /* words per page */ | |
| 13 | +#define PGSHIFT 12 /* log(BY2PG) */ | |
| 14 | +#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1)) | |
| 15 | + | |
| 16 | +#define MAXMACH 1 /* max # cpus system can run */ | |
| 17 | +#define CACHELINELOG 4 | |
| 18 | +#define CACHELINESZ (1<<CACHELINELOG) | |
| 19 | + | |
| 20 | +/* | |
| 21 | + * Time | |
| 22 | + */ | |
| 23 | +#define HZ (50) /* clock frequency */ | |
| 24 | +#define MS2HZ (1000/HZ) /* millisec per clock tick */ | |
| 25 | +#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */ | |
| 26 | +#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */ | |
| 27 | +#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */ | |
| 28 | +#define MHz 1000000 | |
| 29 | + | |
| 30 | +/* | |
| 31 | + * Fundamental values | |
| 32 | + */ | |
| 33 | + | |
| 34 | +#define KZERO 0 /* bootstrap runs in real mode */ | |
| 35 | +#define MACHSIZE 4096 | |
| 36 | + | |
| 37 | +/* | |
| 38 | + * physical MMU | |
| 39 | + */ | |
| 40 | +#define KSEG0 0x20000000 | |
| 41 | +#define KSEGM 0xE0000000 /* mask to check which seg */ | |
| 42 | + | |
| 43 | +/* | |
| 44 | + * MSR bits | |
| 45 | + */ | |
| 46 | + | |
| 47 | +#define POW 0x40000 /* enable power mgmt */ | |
| 48 | +#define TGPR 0x20000 /* GPR0-3 remapped; 603/603e specific */ | |
| 49 | +#define ILE 0x10000 /* interrupts little endian */ | |
| 50 | +#define EE 0x08000 /* enable external/decrementer interrupts */ | |
| 51 | +#define PR 0x04000 /* =1, user mode */ | |
| 52 | +#define FPE 0x02000 /* enable floating point */ | |
| 53 | +#define ME 0x01000 /* enable machine check exceptions */ | |
| 54 | +#define FE0 0x00800 | |
| 55 | +#define SE 0x00400 /* single-step trace */ | |
| 56 | +#define BE 0x00200 /* branch trace */ | |
| 57 | +#define FE1 0x00100 | |
| 58 | +#define IP 0x00040 /* =0, vector to nnnnn; =1, vector to FFFnnnnn */ | |
| 59 | +#define IR 0x00020 /* enable instruction address translation */ | |
| 60 | +#define DR 0x00010 /* enable data address translation */ | |
| 61 | +#define RI 0x00002 /* exception is recoverable */ | |
| 62 | +#define LE 0x00001 /* little endian mode */ | |
| 63 | + | |
| 64 | +#define KMSR (ME|FE0|FE1|FPE) | |
| 65 | +#define UMSR (KMSR|PR|EE|IR|DR) | |
| 66 | + | |
| 67 | +/* | |
| 68 | + * MPC82x addresses; mpc8bug is happy with these | |
| 69 | + */ | |
| 70 | +#define BCSRMEM 0x02100000 | |
| 71 | +#define INTMEM 0x02200000 | |
| 72 | +#define FLASHMEM 0x02800000 | |
| 73 | +#define SDRAMMEM 0x03000000 | |
| 74 | + | |
| 75 | +#define DPRAM (INTMEM+0x2000) | |
| 76 | +#define DPLEN1 0x400 | |
| 77 | +#define DPLEN2 0x200 | |
| 78 | +#define DPLEN3 0x100 | |
| 79 | +#define DPBASE (DPRAM+DPLEN1) | |
| 80 | + | |
| 81 | +#define SCC1P (INTMEM+0x3C00) | |
| 82 | +#define I2CP (INTMEM+0x3C80) | |
| 83 | +#define MISCP (INTMEM+0x3CB0) | |
| 84 | +#define IDMA1P (INTMEM+0x3CC0) | |
| 85 | +#define SCC2P (INTMEM+0x3D00) | |
| 86 | +#define SCC3P (INTMEM+0x3E00) | |
| 87 | +#define SCC4P (INTMEM+0x3F00) | |
| 88 | +#define SPIP (INTMEM+0x3D80) | |
| 89 | +#define TIMERP (INTMEM+0x3DB0) | |
| 90 | +#define SMC1P (INTMEM+0x3E80) | |
| 91 | +#define DSP1P (INTMEM+0x3EC0) | |
| 92 | +#define SMC2P (INTMEM+0x3F80) | |
| 93 | +#define DSP2P (INTMEM+0x3FC0) | |
| 94 | + | |
| 95 | +#define KEEP_ALIVE_KEY 0x55ccaa33 /* clock and rtc register key */ | |
| @@ -0,0 +1,116 @@ | ||
| 1 | +objtype=power | |
| 2 | +OBJTYPE=power # always | |
| 3 | +<../../../mkconfig | |
| 4 | +SYSTARG=$OSTARG # always | |
| 5 | +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE | |
| 6 | +INSTALLDIR=$ROOT/Inferno/$OBJTYPE/bin #path of directory where kernel is installed | |
| 7 | +ARCH=fads # selects board dependent code | |
| 8 | +TARG=qb$ARCH | |
| 9 | +OFILES=\ | |
| 10 | + l.$O\ | |
| 11 | + arch$ARCH.$O\ | |
| 12 | + devuart.$O\ | |
| 13 | + uartboot.$O\ | |
| 14 | + alarm.$O\ | |
| 15 | + bootp.$O\ | |
| 16 | + clock.$O\ | |
| 17 | + conf.$O\ | |
| 18 | + console.$O\ | |
| 19 | + cpm.$O\ | |
| 20 | + defont0.$O\ | |
| 21 | + donprint.$O\ | |
| 22 | + dosboot.$O\ | |
| 23 | + devether.$O\ | |
| 24 | + etherscc.$O\ | |
| 25 | + fblt.$O\ | |
| 26 | + gbitbltclip.$O\ | |
| 27 | + flash.$O\ | |
| 28 | + main.$O\ | |
| 29 | + plan9boot.$O\ | |
| 30 | + qio.$O\ | |
| 31 | + rmap.$O\ | |
| 32 | + screen.$O\ | |
| 33 | + init$ARCH.$O\ | |
| 34 | + trap.$O\ | |
| 35 | + zqs.$O\ | |
| 36 | + | |
| 37 | +HFILES=\ | |
| 38 | + boot.h\ | |
| 39 | + dat.h\ | |
| 40 | + fns.h\ | |
| 41 | + io.h\ | |
| 42 | + lib.h\ | |
| 43 | + mem.h\ | |
| 44 | + squeeze.h\ | |
| 45 | + gnot.h\ | |
| 46 | + arch$ARCH.h\ | |
| 47 | + | |
| 48 | +LIBS=\ | |
| 49 | + kern\ | |
| 50 | + | |
| 51 | +LIBDIRS=$LIBS | |
| 52 | +LIBNAMES=${LIBS:%=lib%.a} | |
| 53 | +LIBFILES=${LIBS:%=$ROOT/$TARGMODEL/$OBJTYPE/lib/lib%.a} | |
| 54 | + | |
| 55 | +#all:NV: $TARG k.mx f.mx | |
| 56 | +all:NV: $TARG | |
| 57 | +install:V: $INSTALLDIR/$TARG | |
| 58 | +installall:V: $INSTALLDIR/$TARG | |
| 59 | + | |
| 60 | +$INSTALLDIR/%: % | |
| 61 | + rm -f $INSTALLDIR/$stem && cp $stem $INSTALLDIR/$stem | |
| 62 | + | |
| 63 | +$TARG: $OFILES $LIBNAMES | |
| 64 | + $LD -o $target -l -T0x140000 -R4 $OFILES $LIBFILES | |
| 65 | + ls -l $target | |
| 66 | + | |
| 67 | +qbrom$ARCH: $OFILES $LIBNAMES | |
| 68 | + $LD -o $target -l -T0x02800100 -R0 -D0x140000 $OFILES $LIBFILES | |
| 69 | + | |
| 70 | +k.mx: $TARG | |
| 71 | + ms2 -S 0x100 -a 0x100 -p 4 $TARG >k.mx | |
| 72 | + | |
| 73 | +f.mx: qbrom$ARCH | |
| 74 | + ms2 -S 0x100 -a 0x2800100 -p 4 $prereq >f.mx | |
| 75 | + | |
| 76 | +%.$O: %.s | |
| 77 | + $AS $stem.s | |
| 78 | + | |
| 79 | +%.$O: %.c | |
| 80 | + $CC $CFLAGS $stem.c | |
| 81 | + | |
| 82 | +%.$O: $HFILES | |
| 83 | + | |
| 84 | +lib%.a:V: $SHELLTYPE-lib%.a | |
| 85 | + | |
| 86 | +rc-lib%.a nt-lib%.a:VQ: | |
| 87 | + echo '@{builtin cd ' $ROOT/lib$stem ';mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install}' | |
| 88 | + @{builtin cd $ROOT/lib$stem ;mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE install} | |
| 89 | + | |
| 90 | +sh-lib%.a:VQ: | |
| 91 | + echo "(cd $ROOT/lib$stem ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install)" | |
| 92 | + (cd $ROOT/lib$stem ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install) | |
| 93 | + | |
| 94 | +clock.$O floppy.$O trap.$O: ureg.h | |
| 95 | +conf.$O dosboot.$O main.$O: dosfs.h | |
| 96 | +ether.$O etherscc.$O: etherif.h | |
| 97 | +bootp.$O: ip.h | |
| 98 | + | |
| 99 | +clean:V: | |
| 100 | + rm -f *.[$OS] [$OS].out y.tab.? y.debug y.output $TARG qboot k.mx f.mx romboot | |
| 101 | + | |
| 102 | +nuke-sh:QV: | |
| 103 | + for i in $LIBDIRS | |
| 104 | + do | |
| 105 | + echo "(cd $ROOT/lib$i ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE nuke)" | |
| 106 | + (cd $ROOT/lib$i; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE nuke) | |
| 107 | + done | |
| 108 | + | |
| 109 | +nuke-rc nuke-nt:QV: | |
| 110 | + for (i in $LIBDIRS) | |
| 111 | + { | |
| 112 | + echo '@{cd $ROOT/lib$i ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE nuke}' | |
| 113 | + @{cd $ROOT/lib$i; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE nuke} | |
| 114 | + } | |
| 115 | + | |
| 116 | +nuke:V: clean nuke-$SHELLTYPE | |
| @@ -0,0 +1,179 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <bio.h> | |
| 4 | +#include <mach.h> | |
| 5 | + | |
| 6 | +void record(uchar*, int); | |
| 7 | +void usage(void); | |
| 8 | +void dosegment(long, int); | |
| 9 | +void trailer(ulong); | |
| 10 | + | |
| 11 | +enum | |
| 12 | +{ | |
| 13 | + Recordsize = 32, | |
| 14 | +}; | |
| 15 | + | |
| 16 | +int dsegonly; | |
| 17 | +int supressend; | |
| 18 | +int binary; | |
| 19 | +int addr4; | |
| 20 | +ulong addr; | |
| 21 | +ulong psize = 4096; | |
| 22 | +ulong startaddr = 0x030000; | |
| 23 | +Biobuf stdout; | |
| 24 | +Biobuf bio; | |
| 25 | + | |
| 26 | +void | |
| 27 | +main(int argc, char **argv) | |
| 28 | +{ | |
| 29 | + Dir dir; | |
| 30 | + Fhdr f; | |
| 31 | + int fd; | |
| 32 | + | |
| 33 | + ARGBEGIN{ | |
| 34 | + case 'd': | |
| 35 | + dsegonly++; | |
| 36 | + break; | |
| 37 | + case 's': | |
| 38 | + supressend++; | |
| 39 | + break; | |
| 40 | + case 'a': | |
| 41 | + addr = strtoul(ARGF(), 0, 0); | |
| 42 | + break; | |
| 43 | + case 'p': | |
| 44 | + psize = strtoul(ARGF(), 0, 0); | |
| 45 | + break; | |
| 46 | + case 'b': | |
| 47 | + binary++; | |
| 48 | + break; | |
| 49 | + case 'S': | |
| 50 | + startaddr = strtoul(ARGF(), 0, 0); | |
| 51 | + break; | |
| 52 | + case '4': | |
| 53 | + addr4++; | |
| 54 | + break; | |
| 55 | + default: | |
| 56 | + usage(); | |
| 57 | + }ARGEND | |
| 58 | + | |
| 59 | + if(argc != 1) | |
| 60 | + usage(); | |
| 61 | + | |
| 62 | + Binit(&stdout, 1, OWRITE); | |
| 63 | + | |
| 64 | + fd = open(argv[0], OREAD); | |
| 65 | + if(fd < 0) { | |
| 66 | + fprint(2, "ms2: open %s: %r\n", argv[0]); | |
| 67 | + exits("open"); | |
| 68 | + } | |
| 69 | + | |
| 70 | + if(binary) { | |
| 71 | + if(dirfstat(fd, &dir) < 0) { | |
| 72 | + fprint(2, "ms2: stat failed %r"); | |
| 73 | + exits("dirfstat"); | |
| 74 | + } | |
| 75 | + Binit(&bio, fd, OREAD); | |
| 76 | + dosegment(0, dir.length); | |
| 77 | + if(supressend == 0) | |
| 78 | + trailer(startaddr); | |
| 79 | + Bterm(&stdout); | |
| 80 | + Bterm(&bio); | |
| 81 | + exits(0); | |
| 82 | + } | |
| 83 | + | |
| 84 | + if(crackhdr(fd, &f) == 0){ | |
| 85 | + fprint(2, "ms2: bad magic: %r\n"); | |
| 86 | + exits("magic"); | |
| 87 | + } | |
| 88 | + seek(fd, 0, 0); | |
| 89 | + | |
| 90 | + Binit(&bio, fd, OREAD); | |
| 91 | + | |
| 92 | + if(dsegonly) | |
| 93 | + dosegment(f.datoff, f.datsz); | |
| 94 | + else { | |
| 95 | + dosegment(f.txtoff, f.txtsz); | |
| 96 | + addr = (addr+(psize-1))&~(psize-1); | |
| 97 | + dosegment(f.datoff, f.datsz); | |
| 98 | + } | |
| 99 | + | |
| 100 | + if(supressend == 0) | |
| 101 | + trailer(startaddr); | |
| 102 | + | |
| 103 | + Bterm(&stdout); | |
| 104 | + Bterm(&bio); | |
| 105 | + exits(0); | |
| 106 | +} | |
| 107 | + | |
| 108 | +void | |
| 109 | +dosegment(long foff, int len) | |
| 110 | +{ | |
| 111 | + int l, n; | |
| 112 | + uchar buf[2*Recordsize]; | |
| 113 | + | |
| 114 | + Bseek(&bio, foff, 0); | |
| 115 | + for(;;) { | |
| 116 | + l = len; | |
| 117 | + if(l > Recordsize) | |
| 118 | + l = Recordsize; | |
| 119 | + n = Bread(&bio, buf, l); | |
| 120 | + if(n == 0) | |
| 121 | + break; | |
| 122 | + if(n < 0) { | |
| 123 | + fprint(2, "ms2: read error: %r\n"); | |
| 124 | + exits("read"); | |
| 125 | + } | |
| 126 | + record(buf, l); | |
| 127 | + len -= l; | |
| 128 | + } | |
| 129 | +} | |
| 130 | + | |
| 131 | +void | |
| 132 | +record(uchar *s, int l) | |
| 133 | +{ | |
| 134 | + int i; | |
| 135 | + ulong cksum; | |
| 136 | + | |
| 137 | + if(addr4 || addr & (0xFF<<24)){ | |
| 138 | + Bprint(&stdout, "S3%.2X%.8luX", l+5, addr); | |
| 139 | + cksum = l+5; | |
| 140 | + cksum += (addr>>24)&0xff; | |
| 141 | + }else{ | |
| 142 | + Bprint(&stdout, "S2%.2X%.6X", l+4, addr); | |
| 143 | + cksum = l+4; | |
| 144 | + } | |
| 145 | + cksum += addr&0xff; | |
| 146 | + cksum += (addr>>8)&0xff; | |
| 147 | + cksum += (addr>>16)&0xff; | |
| 148 | + | |
| 149 | + for(i = 0; i < l; i++) { | |
| 150 | + cksum += *s; | |
| 151 | + Bprint(&stdout, "%.2X", *s++); | |
| 152 | + } | |
| 153 | + Bprint(&stdout, "%.2X\n", (~cksum)&0xff); | |
| 154 | + addr += l; | |
| 155 | +} | |
| 156 | + | |
| 157 | +void | |
| 158 | +trailer(ulong a) | |
| 159 | +{ | |
| 160 | + ulong cksum; | |
| 161 | + | |
| 162 | + cksum = 0; | |
| 163 | + if(addr4 || a & (0xFF<<24)){ | |
| 164 | + Bprint(&stdout, "S7%.8luX", a); | |
| 165 | + cksum += (a>>24)&0xff; | |
| 166 | + }else | |
| 167 | + Bprint(&stdout, "S9%.6X", a); | |
| 168 | + cksum += a&0xff; | |
| 169 | + cksum += (a>>8)&0xff; | |
| 170 | + cksum += (a>>16)&0xff; | |
| 171 | + Bprint(&stdout, "%.2X\n", (~cksum)&0xff); | |
| 172 | +} | |
| 173 | + | |
| 174 | +void | |
| 175 | +usage(void) | |
| 176 | +{ | |
| 177 | + fprint(2, "usage: ms2 [-ds] [-a address] [-p pagesize] ?.out\n"); | |
| 178 | + exits("usage"); | |
| 179 | +} | |
| @@ -0,0 +1,96 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | + | |
| 7 | +char *premature = "premature EOF\n"; | |
| 8 | + | |
| 9 | +/* | |
| 10 | + * read in a segment | |
| 11 | + */ | |
| 12 | +static long | |
| 13 | +readseg(int dev, long (*read)(int, void*, long), long len, long addr) | |
| 14 | +{ | |
| 15 | + char *a; | |
| 16 | + long n, sofar; | |
| 17 | + | |
| 18 | + a = (char *)addr; | |
| 19 | + for(sofar = 0; sofar < len; sofar += n){ | |
| 20 | + n = 8*1024; | |
| 21 | + if(len - sofar < n) | |
| 22 | + n = len - sofar; | |
| 23 | + n = (*read)(dev, a + sofar, n); | |
| 24 | + if(n <= 0) | |
| 25 | + break; | |
| 26 | + print("."); | |
| 27 | + } | |
| 28 | + return sofar; | |
| 29 | +} | |
| 30 | + | |
| 31 | +/* | |
| 32 | + * boot | |
| 33 | + */ | |
| 34 | +int | |
| 35 | +plan9boot(int dev, long (*seek)(int, long), long (*read)(int, void*, long)) | |
| 36 | +{ | |
| 37 | + long n; | |
| 38 | + long addr; | |
| 39 | + void (*b)(void); | |
| 40 | + Exec *ep; | |
| 41 | + | |
| 42 | + if((*seek)(dev, 0) < 0) | |
| 43 | + return -1; | |
| 44 | + | |
| 45 | + /* | |
| 46 | + * read header | |
| 47 | + */ | |
| 48 | + ep = (Exec *) ialloc(sizeof(Exec), 0); | |
| 49 | + n = sizeof(Exec); | |
| 50 | + if(readseg(dev, read, n, (long) ep) != n){ | |
| 51 | + print(premature); | |
| 52 | + return -1; | |
| 53 | + } | |
| 54 | + if(GLLONG(ep->magic) != Q_MAGIC){ | |
| 55 | + print("bad magic 0x%lux not a plan 9 executable!\n", GLLONG(ep->magic)); | |
| 56 | + return -1; | |
| 57 | + } | |
| 58 | + | |
| 59 | + /* | |
| 60 | + * read text | |
| 61 | + */ | |
| 62 | + addr = PADDR(GLLONG(ep->entry)); | |
| 63 | + n = GLLONG(ep->text); | |
| 64 | + print("%d", n); | |
| 65 | + if(readseg(dev, read, n, addr) != n){ | |
| 66 | + print(premature); | |
| 67 | + return -1; | |
| 68 | + } | |
| 69 | + | |
| 70 | + /* | |
| 71 | + * read data (starts at first page after kernel) | |
| 72 | + */ | |
| 73 | + addr = PGROUND(addr+n); | |
| 74 | + n = GLLONG(ep->data); | |
| 75 | + print("+%d@%8.8lux", n, addr); | |
| 76 | + if(readseg(dev, read, n, addr) != n){ | |
| 77 | + print(premature); | |
| 78 | + return -1; | |
| 79 | + } | |
| 80 | + | |
| 81 | + /* | |
| 82 | + * bss and entry point | |
| 83 | + */ | |
| 84 | + print("+%d\nstart at 0x%lux\n", GLLONG(ep->bss), GLLONG(ep->entry)); | |
| 85 | + uartwait(); | |
| 86 | + scc2stop(); | |
| 87 | + splhi(); | |
| 88 | + | |
| 89 | + /* | |
| 90 | + * Go to new code. It's up to the program to get its PC relocated to | |
| 91 | + * the right place. | |
| 92 | + */ | |
| 93 | + b = (void (*)(void))(PADDR(GLLONG(ep->entry))); | |
| 94 | + (*b)(); | |
| 95 | + return 0; | |
| 96 | +} | |
| @@ -0,0 +1,128 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +struct Queue { | |
| 9 | + Block* first; | |
| 10 | + Block* last; | |
| 11 | + void (*kick)(void*); | |
| 12 | + void* arg; | |
| 13 | + long len; | |
| 14 | +}; | |
| 15 | + | |
| 16 | +Block * | |
| 17 | +iallocb(int n) | |
| 18 | +{ | |
| 19 | + Block *b; | |
| 20 | + | |
| 21 | + b = (Block*)malloc(sizeof(Block)+n); | |
| 22 | + b->data = (uchar*)b + sizeof(Block); | |
| 23 | + b->rp = b->wp = b->data; | |
| 24 | + b->lim = b->data + n; | |
| 25 | + b->next = 0; | |
| 26 | + b->magic = 0xcafebee0; | |
| 27 | + return b; | |
| 28 | +} | |
| 29 | + | |
| 30 | +void | |
| 31 | +freeb(Block *b) | |
| 32 | +{ | |
| 33 | + if(b){ | |
| 34 | + if(b->magic != 0xcafebee0) | |
| 35 | + panic("freeb"); | |
| 36 | + b->magic = 0; | |
| 37 | + b->next = (Block*)0xdeadbabe; | |
| 38 | + free(b); | |
| 39 | + } | |
| 40 | +} | |
| 41 | + | |
| 42 | +Queue * | |
| 43 | +qopen(int limit, int msg, void (*kick)(void*), void *arg) | |
| 44 | +{ | |
| 45 | + Queue *q; | |
| 46 | + | |
| 47 | + USED(limit, msg); | |
| 48 | + q = (Queue*)malloc(sizeof(Queue)); | |
| 49 | + q->first = q->last = 0; | |
| 50 | + q->kick = kick; | |
| 51 | + q->arg = arg; | |
| 52 | + q->len = 0; | |
| 53 | + return q; | |
| 54 | +} | |
| 55 | + | |
| 56 | +Block * | |
| 57 | +qget(Queue *q) | |
| 58 | +{ | |
| 59 | + int s; | |
| 60 | + Block *b; | |
| 61 | + | |
| 62 | + s = splhi(); | |
| 63 | + if((b = q->first) != 0){ | |
| 64 | + q->first = b->next; | |
| 65 | + b->next = 0; | |
| 66 | + q->len -= BLEN(b); | |
| 67 | + if(q->len < 0) | |
| 68 | + panic("qget"); | |
| 69 | + } | |
| 70 | + splx(s); | |
| 71 | + return b; | |
| 72 | +} | |
| 73 | + | |
| 74 | +void | |
| 75 | +qbwrite(Queue *q, Block *b) | |
| 76 | +{ | |
| 77 | + int s; | |
| 78 | + | |
| 79 | + s = splhi(); | |
| 80 | + b->next = 0; | |
| 81 | + if(q->first == 0) | |
| 82 | + q->first = b; | |
| 83 | + else | |
| 84 | + q->last->next = b; | |
| 85 | + q->last = b; | |
| 86 | + q->len += BLEN(b); | |
| 87 | + splx(s); | |
| 88 | + if(q->kick) | |
| 89 | + q->kick(q->arg); | |
| 90 | +} | |
| 91 | + | |
| 92 | +long | |
| 93 | +qlen(Queue *q) | |
| 94 | +{ | |
| 95 | + return q->len; | |
| 96 | +} | |
| 97 | + | |
| 98 | +int | |
| 99 | +qbgetc(Queue *q) | |
| 100 | +{ | |
| 101 | + Block *b; | |
| 102 | + int s, c; | |
| 103 | + | |
| 104 | + c = -1; | |
| 105 | + s = splhi(); | |
| 106 | + while(c < 0 && (b = q->first) != nil){ | |
| 107 | + if(b->rp < b->wp){ | |
| 108 | + c = *b->rp++; | |
| 109 | + q->len--; | |
| 110 | + } | |
| 111 | + if(b->rp >= b->wp){ | |
| 112 | + q->first = b->next; | |
| 113 | + b->next = nil; | |
| 114 | + } | |
| 115 | + } | |
| 116 | + splx(s); | |
| 117 | + return c; | |
| 118 | +} | |
| 119 | + | |
| 120 | +void | |
| 121 | +qbputc(Queue *q, int c) | |
| 122 | +{ | |
| 123 | + Block *b; | |
| 124 | + | |
| 125 | + b = iallocb(1); | |
| 126 | + *b->wp++ = c; | |
| 127 | + qbwrite(q, b); | |
| 128 | +} | |
| @@ -0,0 +1,104 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | + | |
| 7 | +void | |
| 8 | +mapinit(RMap *rmap, Map *map, int size) | |
| 9 | +{ | |
| 10 | + lock(rmap); | |
| 11 | + rmap->map = map; | |
| 12 | + rmap->mapend = map+(size/sizeof(Map)); | |
| 13 | + unlock(rmap); | |
| 14 | +} | |
| 15 | + | |
| 16 | +void | |
| 17 | +mapfree(RMap* rmap, ulong addr, int size) | |
| 18 | +{ | |
| 19 | + Map *mp; | |
| 20 | + ulong t; | |
| 21 | + | |
| 22 | + if(size <= 0) | |
| 23 | + return; | |
| 24 | + | |
| 25 | + lock(rmap); | |
| 26 | + for(mp = rmap->map; mp->addr <= addr && mp->size; mp++) | |
| 27 | + ; | |
| 28 | + | |
| 29 | + if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){ | |
| 30 | + (mp-1)->size += size; | |
| 31 | + if(addr+size == mp->addr){ | |
| 32 | + (mp-1)->size += mp->size; | |
| 33 | + while(mp->size){ | |
| 34 | + mp++; | |
| 35 | + (mp-1)->addr = mp->addr; | |
| 36 | + (mp-1)->size = mp->size; | |
| 37 | + } | |
| 38 | + } | |
| 39 | + } | |
| 40 | + else{ | |
| 41 | + if(addr+size == mp->addr && mp->size){ | |
| 42 | + mp->addr -= size; | |
| 43 | + mp->size += size; | |
| 44 | + } | |
| 45 | + else do{ | |
| 46 | + if(mp >= rmap->mapend){ | |
| 47 | + print("mapfree: %s: losing 0x%uX, %d\n", | |
| 48 | + rmap->name, addr, size); | |
| 49 | + break; | |
| 50 | + } | |
| 51 | + t = mp->addr; | |
| 52 | + mp->addr = addr; | |
| 53 | + addr = t; | |
| 54 | + t = mp->size; | |
| 55 | + mp->size = size; | |
| 56 | + mp++; | |
| 57 | + }while(size = t); | |
| 58 | + } | |
| 59 | + unlock(rmap); | |
| 60 | +} | |
| 61 | + | |
| 62 | +ulong | |
| 63 | +mapalloc(RMap* rmap, ulong addr, int size, int align) | |
| 64 | +{ | |
| 65 | + Map *mp; | |
| 66 | + ulong maddr, oaddr; | |
| 67 | + | |
| 68 | + lock(rmap); | |
| 69 | + for(mp = rmap->map; mp->size; mp++){ | |
| 70 | + maddr = mp->addr; | |
| 71 | + | |
| 72 | + if(addr){ | |
| 73 | + if(maddr > addr) | |
| 74 | + continue; | |
| 75 | + if(addr+size > maddr+mp->size) | |
| 76 | + break; | |
| 77 | + maddr = addr; | |
| 78 | + } | |
| 79 | + | |
| 80 | + if(align > 0) | |
| 81 | + maddr = ((maddr+align-1)/align)*align; | |
| 82 | + if(mp->addr+mp->size-maddr < size) | |
| 83 | + continue; | |
| 84 | + | |
| 85 | + oaddr = mp->addr; | |
| 86 | + mp->addr = maddr+size; | |
| 87 | + mp->size -= maddr-oaddr+size; | |
| 88 | + if(mp->size == 0){ | |
| 89 | + do{ | |
| 90 | + mp++; | |
| 91 | + (mp-1)->addr = mp->addr; | |
| 92 | + }while((mp-1)->size = mp->size); | |
| 93 | + } | |
| 94 | + | |
| 95 | + unlock(rmap); | |
| 96 | + if(oaddr != maddr) | |
| 97 | + mapfree(rmap, oaddr, maddr-oaddr); | |
| 98 | + | |
| 99 | + return maddr; | |
| 100 | + } | |
| 101 | + unlock(rmap); | |
| 102 | + | |
| 103 | + return 0; | |
| 104 | +} | |
| @@ -0,0 +1,242 @@ | ||
| 1 | +#include "all.h" | |
| 2 | +#include <libg.h> | |
| 3 | +#include <gnot.h> | |
| 4 | + | |
| 5 | +enum { | |
| 6 | + Colldepth = 3, | |
| 7 | + Colmaxx = 640, | |
| 8 | + Colmaxxvis = 640, | |
| 9 | + Colmaxy = 480, | |
| 10 | +}; | |
| 11 | + | |
| 12 | +#define MINX 8 | |
| 13 | + | |
| 14 | +extern GSubfont defont0; | |
| 15 | + | |
| 16 | +struct{ | |
| 17 | + Point pos; | |
| 18 | + int bwid; | |
| 19 | +}out; | |
| 20 | + | |
| 21 | +typedef struct Mode Mode; | |
| 22 | +struct Mode { | |
| 23 | + int x; | |
| 24 | + int y; | |
| 25 | + int d; | |
| 26 | + char* aperture; | |
| 27 | + int apsize; | |
| 28 | +}; | |
| 29 | + | |
| 30 | +GBitmap gscreen; | |
| 31 | +Point gchar(GBitmap*, Point, GFont*, int, Fcode); | |
| 32 | +int setcolor(ulong, ulong, ulong, ulong); | |
| 33 | +static void lcdinit(Mode*); | |
| 34 | + | |
| 35 | +void | |
| 36 | +screeninit(void) | |
| 37 | +{ | |
| 38 | + Mode m; | |
| 39 | + | |
| 40 | + m.x = Colmaxx; | |
| 41 | + m.y = Colmaxy; | |
| 42 | + m.d = Colldepth; | |
| 43 | + m.aperture = 0; | |
| 44 | + lcdinit(&m); | |
| 45 | + if(m.aperture == 0) | |
| 46 | + return; | |
| 47 | + gscreen.ldepth = 3; | |
| 48 | + gscreen.base = (ulong*)m.aperture; | |
| 49 | + gscreen.width = Colmaxx/BY2WD; | |
| 50 | + gscreen.r = Rect(0, 0, Colmaxxvis, Colmaxy); | |
| 51 | + gscreen.clipr = gscreen.r; | |
| 52 | + /* | |
| 53 | + * For now, just use a fixed colormap: | |
| 54 | + * 0 == white and 255 == black | |
| 55 | + */ | |
| 56 | + setcolor(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); | |
| 57 | + setcolor(255, 0x00000000, 0x00000000, 0x00000000); | |
| 58 | + | |
| 59 | + gbitblt(&gscreen, Pt(0, 0), &gscreen, gscreen.r, Zero); | |
| 60 | + out.pos.x = MINX; | |
| 61 | + out.pos.y = 0; | |
| 62 | + out.bwid = defont0.info[' '].width; | |
| 63 | +} | |
| 64 | + | |
| 65 | +void | |
| 66 | +screenputc(int c) | |
| 67 | +{ | |
| 68 | + Fontchar *i; | |
| 69 | + Point p; | |
| 70 | + | |
| 71 | + if(gscreen.base == nil) | |
| 72 | + return; | |
| 73 | + switch(c){ | |
| 74 | + case '\n': | |
| 75 | + out.pos.x = MINX; | |
| 76 | + out.pos.y += defont0.height; | |
| 77 | + if(out.pos.y > gscreen.r.max.y-defont0.height) | |
| 78 | + out.pos.y = gscreen.r.min.y; | |
| 79 | + gbitblt(&gscreen, Pt(0, out.pos.y), &gscreen, | |
| 80 | + Rect(0, out.pos.y, gscreen.r.max.x, out.pos.y+2*defont0.height), | |
| 81 | + Zero); | |
| 82 | + break; | |
| 83 | + case '\t': | |
| 84 | + out.pos.x += (8-((out.pos.x-MINX)/out.bwid&7))*out.bwid; | |
| 85 | + if(out.pos.x >= gscreen.r.max.x) | |
| 86 | + screenputc('\n'); | |
| 87 | + break; | |
| 88 | + case '\b': | |
| 89 | + if(out.pos.x >= out.bwid+MINX){ | |
| 90 | + out.pos.x -= out.bwid; | |
| 91 | + screenputc(' '); | |
| 92 | + out.pos.x -= out.bwid; | |
| 93 | + } | |
| 94 | + break; | |
| 95 | + default: | |
| 96 | + if(out.pos.x >= gscreen.r.max.x-out.bwid) | |
| 97 | + screenputc('\n'); | |
| 98 | + c &= 0x7f; | |
| 99 | + if(c <= 0 || c >= defont0.n) | |
| 100 | + break; | |
| 101 | + i = defont0.info + c; | |
| 102 | + p = out.pos; | |
| 103 | + gbitblt(&gscreen, Pt(p.x+i->left, p.y), defont0.bits, | |
| 104 | + Rect(i[0].x, 0, i[1].x, defont0.height), | |
| 105 | + S); | |
| 106 | + out.pos.x = p.x + i->width; | |
| 107 | + break; | |
| 108 | + } | |
| 109 | +} | |
| 110 | + | |
| 111 | +void | |
| 112 | +screenputs(char *s, int n) | |
| 113 | +{ | |
| 114 | + while(n-- > 0) | |
| 115 | + screenputc(*s++); | |
| 116 | +} | |
| 117 | + | |
| 118 | +/* | |
| 119 | + * See section 5.2.1 (page 5-6) of the MPC823 manual | |
| 120 | + */ | |
| 121 | +static uchar lcdclock[17] = { /* (a<<2)|b => divisor of (1<<a)*((b<<1)+1) */ | |
| 122 | + 0, 0, (1<<2), 1, | |
| 123 | + (2<<2), 2, (1<<2)|1, 3, | |
| 124 | + (3<<2), (1<<2)|2, (1<<2)|2, (2<<2)|1, | |
| 125 | + (2<<2)|1, (1<<2)|3, (1<<2)|3, (4<<2), | |
| 126 | + (4<<2) | |
| 127 | +}; | |
| 128 | + | |
| 129 | +/* | |
| 130 | + * support for the Sharp LQ64D341 TFT colour display | |
| 131 | + */ | |
| 132 | + | |
| 133 | +enum { | |
| 134 | + COLS = 640, | |
| 135 | + ROWS = 480, | |
| 136 | + LDEPTH = 3, /* screen depth */ | |
| 137 | + LCDFREQ = 25000000, | |
| 138 | + | |
| 139 | + /* lccr */ | |
| 140 | + ClockLow = 1<<11, | |
| 141 | + OELow = 1<<10, | |
| 142 | + HsyncLow = 1<<9, | |
| 143 | + VsyncLow = 1<<8, | |
| 144 | + DataLow = 1<<7, | |
| 145 | + Passive8 = 1<<4, | |
| 146 | + DualScan = 1<<3, | |
| 147 | + IsColour = 1<<2, | |
| 148 | + IsTFT = 1<<1, | |
| 149 | + Enable = 1<<0, | |
| 150 | + | |
| 151 | + /* lchcr */ | |
| 152 | + BigEndian = 1<<24, | |
| 153 | + AT7 = 7<<21, /* access type */ | |
| 154 | + | |
| 155 | + /* sdcr */ | |
| 156 | + LAM = 1<<6, /* ``LCD aggressive mode'' */ | |
| 157 | +}; | |
| 158 | + | |
| 159 | +/* | |
| 160 | + * TO DO: most of the data could come from a table | |
| 161 | + */ | |
| 162 | +static void | |
| 163 | +lcdinit(Mode *mode) | |
| 164 | +{ | |
| 165 | + IMM *io; | |
| 166 | + int i, d; | |
| 167 | + long hz; | |
| 168 | + | |
| 169 | + io = m->iomem; | |
| 170 | + mode->y = ROWS; | |
| 171 | + mode->x = COLS; | |
| 172 | + mode->d = LDEPTH; | |
| 173 | + mode->aperture = ialloc(mode->x*mode->y, 16); | |
| 174 | + mode->apsize = mode->x*mode->y; | |
| 175 | + | |
| 176 | + io->sdcr &= ~LAM; /* MPC823 errata: turn off LAM before disabling controller */ | |
| 177 | + io->lcfaa = PADDR(mode->aperture); | |
| 178 | + io->lccr = (((mode->x*mode->y*(1<<LDEPTH)+127)/128) << 17) | (LDEPTH << 5) | IsColour | IsTFT | OELow | VsyncLow | ClockLow; | |
| 179 | + | |
| 180 | + switch(LDEPTH){ | |
| 181 | + default: | |
| 182 | + case 0: | |
| 183 | + /* monochrome/greyscale identity map */ | |
| 184 | + for(i=0; i<16; i++) | |
| 185 | + io->lcdmap[i] = i; | |
| 186 | + break; | |
| 187 | + case 2: | |
| 188 | + /* 4-bit grey scale map */ | |
| 189 | + for(i=0; i<16; i++) | |
| 190 | + io->lcdmap[0] = (i<<8)|(i<<4)|i; | |
| 191 | + break; | |
| 192 | + case 3: | |
| 193 | + /* 8-bit linear map */ | |
| 194 | + for(i=0; i<256; i++) | |
| 195 | + io->lcdmap[i] = (i<<8)|(i<<4)|i; | |
| 196 | + break; | |
| 197 | + } | |
| 198 | + | |
| 199 | + io->lcvcr = (mode->y << 11) | (1<<28) | 33; /* 2 line vsync pulse, 34 line wait between frames */ | |
| 200 | + io->lchcr = (mode->x<<10) | BigEndian | 228; /* clock cycles between lines */ | |
| 201 | + | |
| 202 | + hz = m->cpuhz; | |
| 203 | + d = hz/LCDFREQ; | |
| 204 | + if(hz/d > LCDFREQ) | |
| 205 | + d++; | |
| 206 | + if(d >= 16) | |
| 207 | + d = 16; | |
| 208 | + | |
| 209 | + /* | |
| 210 | + * enable LCD outputs | |
| 211 | + */ | |
| 212 | + io->pddat = 0; | |
| 213 | + io->pdpar = 0x1fff; | |
| 214 | +io->pdpar &= ~SIBIT(6); /* 823 bug fix? */ | |
| 215 | + io->pddir = 0x1fff; | |
| 216 | + io->pbpar |= IBIT(31) | IBIT(19) | IBIT(17); | |
| 217 | + io->pbdir |= IBIT(31) | IBIT(19) | IBIT(17); | |
| 218 | + io->pbodr &= ~(IBIT(31) | IBIT(19) | IBIT(17)); | |
| 219 | + | |
| 220 | + eieio(); | |
| 221 | + io->sccrk = KEEP_ALIVE_KEY; | |
| 222 | + eieio(); | |
| 223 | + io->sccr = (io->sccr & ~0x1F) | lcdclock[d]; | |
| 224 | + eieio(); | |
| 225 | + io->sccrk = ~KEEP_ALIVE_KEY; | |
| 226 | + eieio(); | |
| 227 | + gscreen.width = gscreen.width; /* access external memory before enabling (mpc823 errata) */ | |
| 228 | + io->lcsr = 7; /* clear status */ | |
| 229 | + eieio(); | |
| 230 | + io->lccr |= Enable; | |
| 231 | + archbacklight(1); | |
| 232 | +} | |
| 233 | + | |
| 234 | +int | |
| 235 | +setcolor(ulong p, ulong r, ulong g, ulong b) | |
| 236 | +{ | |
| 237 | + r >>= 28; | |
| 238 | + g >>= 28; | |
| 239 | + b >>= 28; | |
| 240 | + m->iomem->lcdmap[~p&0xFF] = (r<<8) | (g<<4) | b; /* TO DO: it's a function of the ldepth */ | |
| 241 | + return 1; | |
| 242 | +} | |
| @@ -0,0 +1,71 @@ | ||
| 1 | +/* | |
| 2 | + * send S records to rpcg | |
| 3 | + */ | |
| 4 | + | |
| 5 | +#include <u.h> | |
| 6 | +#include <libc.h> | |
| 7 | +#include <bio.h> | |
| 8 | + | |
| 9 | +static int dbg; | |
| 10 | +static char buf[2048]; | |
| 11 | +static int run=1; | |
| 12 | +static void stuffbym(char*, int, int); | |
| 13 | +static void getdot(void); | |
| 14 | + | |
| 15 | +void | |
| 16 | +main(int argc, char **argv) | |
| 17 | +{ | |
| 18 | + int n; | |
| 19 | + char *l; | |
| 20 | + Biobuf *f; | |
| 21 | + static int p; | |
| 22 | + | |
| 23 | + ARGBEGIN{ | |
| 24 | + case 'd': dbg++; break; | |
| 25 | + case 'n': run=0; break; | |
| 26 | + }ARGEND | |
| 27 | + | |
| 28 | + f = Bopen(*argv? *argv: "k.mx", OREAD); | |
| 29 | + if(f == 0) { | |
| 30 | + fprint(2, "sload: cannot open k.mx: %r\n"); | |
| 31 | + exits("sload"); | |
| 32 | + } | |
| 33 | + getdot(); | |
| 34 | + while((l = Brdline(f, '\n')) != 0) { | |
| 35 | + l[Blinelen(f)-1] = '\r'; | |
| 36 | + stuffbym(l, Blinelen(f), 16); | |
| 37 | + getdot(); | |
| 38 | + if(++p % 25 == 0) | |
| 39 | + write(2, ".", 1); | |
| 40 | + } | |
| 41 | + exits(0); | |
| 42 | +} | |
| 43 | + | |
| 44 | +static void | |
| 45 | +stuffbym(char *l, int n, int m) | |
| 46 | +{ | |
| 47 | + int nr, ns; | |
| 48 | + | |
| 49 | + while(n > 0) { | |
| 50 | + ns = n; | |
| 51 | + if(ns > m) | |
| 52 | + ns = m; | |
| 53 | + write(1, l, ns); | |
| 54 | + l += ns; | |
| 55 | + n -= ns; | |
| 56 | + } | |
| 57 | +} | |
| 58 | + | |
| 59 | +static void | |
| 60 | +getdot(void) | |
| 61 | +{ | |
| 62 | + char c; | |
| 63 | + | |
| 64 | + for(;;){ | |
| 65 | + if(read(0, &c, 1) != 1) | |
| 66 | + exits("bang"); | |
| 67 | + write(2, &c, 1); | |
| 68 | + if(c == '.') | |
| 69 | + break; | |
| 70 | + } | |
| 71 | +} | |
| @@ -0,0 +1,34 @@ | ||
| 1 | + | |
| 2 | +/* | |
| 3 | + * squeezed file format: | |
| 4 | + * Sqhdr | |
| 5 | + * original Exec header | |
| 6 | + * two Squeeze tables | |
| 7 | + * squeezed segment | |
| 8 | + * unsqueezed segment, if any | |
| 9 | + */ | |
| 10 | +#define SQMAGIC (ulong)0xFEEF0F1E | |
| 11 | + | |
| 12 | +typedef struct Sqhdr Sqhdr; | |
| 13 | +struct Sqhdr { | |
| 14 | + uchar magic[4]; /* SQMAGIC */ | |
| 15 | + uchar text[4]; /* squeezed length of text (excluding tables) */ | |
| 16 | + uchar data[4]; /* squeezed length of data (excluding tables) */ | |
| 17 | + uchar asis[4]; /* length of unsqueezed segment */ | |
| 18 | + uchar toptxt[4]; /* value for 0 encoding in text */ | |
| 19 | + uchar topdat[4]; /* value for 0 encoding in data */ | |
| 20 | + uchar sum[4]; /* simple checksum of unsqueezed data */ | |
| 21 | + uchar flags[4]; | |
| 22 | +}; | |
| 23 | +#define SQHDRLEN (8*4) | |
| 24 | + | |
| 25 | +/* | |
| 26 | + * certain power instruction types are rearranged by sqz | |
| 27 | + * so as to move the variable part of the instruction word to the | |
| 28 | + * low order bits. note that the mapping is its own inverse. | |
| 29 | + */ | |
| 30 | +#define QREMAP(X)\ | |
| 31 | + switch((X)>>26){\ | |
| 32 | + case 19: case 31: case 59: case 63:\ | |
| 33 | + (X) = (((X) & 0xFC00F801) | (((X)>>15)&0x7FE) | (((X)&0x7FE)<<15));\ | |
| 34 | + } | |
| @@ -0,0 +1,233 @@ | ||
| 1 | +#include "boot.h" | |
| 2 | + | |
| 3 | +enum | |
| 4 | +{ | |
| 5 | + Maxhandler= 32+16, /* max number of interrupt handlers */ | |
| 6 | +}; | |
| 7 | + | |
| 8 | +typedef struct Handler Handler; | |
| 9 | +struct Handler | |
| 10 | +{ | |
| 11 | + void (*r)(Ureg*, void*); | |
| 12 | + void *arg; | |
| 13 | + Handler *next; | |
| 14 | + int edge; | |
| 15 | +}; | |
| 16 | + | |
| 17 | +struct | |
| 18 | +{ | |
| 19 | + Handler *ivec[128]; | |
| 20 | + Handler h[Maxhandler]; | |
| 21 | + int free; | |
| 22 | +} halloc; | |
| 23 | + | |
| 24 | +char *excname[] = { | |
| 25 | + "reserved 0", | |
| 26 | + "system reset", | |
| 27 | + "machine check", | |
| 28 | + "data access", | |
| 29 | + "instruction access", | |
| 30 | + "external interrupt", | |
| 31 | + "alignment", | |
| 32 | + "program exception", | |
| 33 | + "floating-point unavailable", | |
| 34 | + "decrementer", | |
| 35 | + "reserved A", | |
| 36 | + "reserved B", | |
| 37 | + "system call", | |
| 38 | + "trace trap", | |
| 39 | + "floating point assist", | |
| 40 | + "reserved F", | |
| 41 | + "software emulation", | |
| 42 | + "ITLB miss", | |
| 43 | + "DTLB miss", | |
| 44 | + "ITLB error", | |
| 45 | + "DTLB error", | |
| 46 | +}; | |
| 47 | + | |
| 48 | +char *regname[]={ | |
| 49 | + "CAUSE", "SRR1", | |
| 50 | + "PC", "GOK", | |
| 51 | + "LR", "CR", | |
| 52 | + "XER", "CTR", | |
| 53 | + "R0", "R1", | |
| 54 | + "R2", "R3", | |
| 55 | + "R4", "R5", | |
| 56 | + "R6", "R7", | |
| 57 | + "R8", "R9", | |
| 58 | + "R10", "R11", | |
| 59 | + "R12", "R13", | |
| 60 | + "R14", "R15", | |
| 61 | + "R16", "R17", | |
| 62 | + "R18", "R19", | |
| 63 | + "R20", "R21", | |
| 64 | + "R22", "R23", | |
| 65 | + "R24", "R25", | |
| 66 | + "R26", "R27", | |
| 67 | + "R28", "R29", | |
| 68 | + "R30", "R31", | |
| 69 | +}; | |
| 70 | + | |
| 71 | +static void intr(Ureg*); | |
| 72 | + | |
| 73 | +void | |
| 74 | +sethvec(int v, void (*r)(void)) | |
| 75 | +{ | |
| 76 | + ulong *vp, pa, o; | |
| 77 | + | |
| 78 | + if((ulong)r & 3) | |
| 79 | + panic("sethvec"); | |
| 80 | + vp = (ulong*)KADDR(v); | |
| 81 | + vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */ | |
| 82 | + vp[1] = 0x7c0802a6; /* MOVW LR, R0 */ | |
| 83 | + vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */ | |
| 84 | + pa = PADDR(r); | |
| 85 | + o = pa >> 25; | |
| 86 | + if(o != 0 && o != 0x7F){ | |
| 87 | + /* a branch too far: running from ROM */ | |
| 88 | + vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ | |
| 89 | + vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ | |
| 90 | + vp[5] = 0x7c0803a6; /* MOVW R0, LR */ | |
| 91 | + vp[6] = 0x4e800021; /* BL (LR) */ | |
| 92 | + }else | |
| 93 | + vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */ | |
| 94 | +} | |
| 95 | + | |
| 96 | +#define LEV(n) (((n)<<1)|1) | |
| 97 | +#define IRQ(n) (((n)<<1)|0) | |
| 98 | + | |
| 99 | +void | |
| 100 | +setvec(int v, void (*r)(Ureg*, void*), void *arg) | |
| 101 | +{ | |
| 102 | + Handler *h; | |
| 103 | + IMM *io; | |
| 104 | + | |
| 105 | + if(halloc.free >= Maxhandler) | |
| 106 | + panic("out of interrupt handlers"); | |
| 107 | + v -= VectorPIC; | |
| 108 | + h = &halloc.h[halloc.free++]; | |
| 109 | + h->next = halloc.ivec[v]; | |
| 110 | + h->r = r; | |
| 111 | + h->arg = arg; | |
| 112 | + halloc.ivec[v] = h; | |
| 113 | + | |
| 114 | + /* | |
| 115 | + * enable corresponding interrupt in SIU/CPM | |
| 116 | + */ | |
| 117 | + | |
| 118 | + io = m->iomem; | |
| 119 | + if(v >= VectorCPIC){ | |
| 120 | + v -= VectorCPIC; | |
| 121 | + io->cimr |= 1<<(v&0x1F); | |
| 122 | + } | |
| 123 | + else if(v >= VectorIRQ) | |
| 124 | + io->simask |= 1<<(31-IRQ(v&7)); | |
| 125 | + else | |
| 126 | + io->simask |= 1<<(31-LEV(v)); | |
| 127 | +} | |
| 128 | + | |
| 129 | +void | |
| 130 | +trapinit(void) | |
| 131 | +{ | |
| 132 | + int i; | |
| 133 | + IMM *io; | |
| 134 | + | |
| 135 | + io = m->iomem; | |
| 136 | + io->sypcr &= ~(3<<2); /* disable watchdog (821/823) */ | |
| 137 | + io->simask = 0; /* mask all */ | |
| 138 | + io->siel = ~0; /* edge sensitive, wake on all */ | |
| 139 | + io->cicr = 0; /* disable CPM interrupts */ | |
| 140 | + io->cipr = ~0; /* clear all interrupts */ | |
| 141 | + io->cimr = 0; /* mask all events */ | |
| 142 | + io->cicr = (0xE1<<16)|(CPIClevel<<13)|(0x1F<<8); | |
| 143 | + io->cicr |= 1 << 7; /* enable */ | |
| 144 | + io->tbscrk = KEEP_ALIVE_KEY; | |
| 145 | + io->tbscr = 1; /* TBE */ | |
| 146 | + io->simask |= 1<<(31-LEV(CPIClevel)); /* CPM's level */ | |
| 147 | + io->tbk = KEEP_ALIVE_KEY; | |
| 148 | + eieio(); | |
| 149 | + putdec(~0); | |
| 150 | + | |
| 151 | + /* | |
| 152 | + * set all exceptions to trap | |
| 153 | + */ | |
| 154 | + for(i = 0x0; i < 0x3000; i += 0x100) | |
| 155 | + sethvec(i, exception); | |
| 156 | +} | |
| 157 | + | |
| 158 | +void | |
| 159 | +dumpregs(Ureg *ur) | |
| 160 | +{ | |
| 161 | + int i; | |
| 162 | + ulong *l; | |
| 163 | + l = &ur->cause; | |
| 164 | + for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2) | |
| 165 | + print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]); | |
| 166 | +} | |
| 167 | + | |
| 168 | +void | |
| 169 | +trap(Ureg *ur) | |
| 170 | +{ | |
| 171 | + int c; | |
| 172 | + | |
| 173 | + c = ur->cause >> 8; | |
| 174 | + switch(c){ | |
| 175 | + default: | |
| 176 | + {extern int predawn; predawn = 1;} | |
| 177 | + if(c < 0 || c >= nelem(excname)) | |
| 178 | + print("exception/interrupt #%x\n", c); | |
| 179 | + else | |
| 180 | + print("exception %s\n", excname[c]); | |
| 181 | + dumpregs(ur); | |
| 182 | + /* spllo(); */ | |
| 183 | + print("^P to reset\n"); | |
| 184 | + for(;;) | |
| 185 | + ; | |
| 186 | + | |
| 187 | + case 0x09: /* decrementer */ | |
| 188 | + clockintr(ur, 0); | |
| 189 | + return; | |
| 190 | + | |
| 191 | + case 0x05: /* external interrupt */ | |
| 192 | + intr(ur); | |
| 193 | + break; | |
| 194 | + } | |
| 195 | +} | |
| 196 | + | |
| 197 | +static void | |
| 198 | +intr(Ureg *ur) | |
| 199 | +{ | |
| 200 | + int b, v; | |
| 201 | + Handler *h; | |
| 202 | + IMM *io; | |
| 203 | + | |
| 204 | + io = m->iomem; | |
| 205 | + b = io->sivec>>2; | |
| 206 | + v = b>>1; | |
| 207 | + if(b & 1) { | |
| 208 | + if(v == CPIClevel){ | |
| 209 | + io->civr = 1; | |
| 210 | + eieio(); | |
| 211 | + v = VectorCPIC+(io->civr>>11); | |
| 212 | + } | |
| 213 | + }else | |
| 214 | + v += VectorIRQ; | |
| 215 | + h = halloc.ivec[v]; | |
| 216 | + if(h == nil){ | |
| 217 | + for(;;) | |
| 218 | + ; | |
| 219 | + //print("unknown interrupt %d pc=0x%lux\n", v, ur->pc); | |
| 220 | + return; | |
| 221 | + } | |
| 222 | + if(h->edge) | |
| 223 | + io->sipend |= 1<<(31-b); | |
| 224 | + /* | |
| 225 | + * call the interrupt handlers | |
| 226 | + */ | |
| 227 | + do { | |
| 228 | + (*h->r)(ur, h->arg); | |
| 229 | + h = h->next; | |
| 230 | + } while(h != nil); | |
| 231 | + if(v >= VectorCPIC) | |
| 232 | + io->cisr |= 1<<(v-VectorCPIC); | |
| 233 | +} | |
| @@ -0,0 +1,189 @@ | ||
| 1 | +#include "boot.h" | |
| 2 | + | |
| 3 | +/* | |
| 4 | + * this doesn't yet use the crc | |
| 5 | + */ | |
| 6 | + | |
| 7 | +typedef struct Uboot Uboot; | |
| 8 | +struct Uboot { | |
| 9 | + Queue* iq; | |
| 10 | + Block* partial; | |
| 11 | + ulong csum; | |
| 12 | + long bno; | |
| 13 | + uchar buf[64]; | |
| 14 | + int nleft; | |
| 15 | + int ntimeout; | |
| 16 | +}; | |
| 17 | + | |
| 18 | +static Uboot uboot; | |
| 19 | +ulong crc32(void *buf, int n, ulong crc); | |
| 20 | + | |
| 21 | +static void | |
| 22 | +uartbrecv(uchar *p, int n) | |
| 23 | +{ | |
| 24 | + Uboot *ub; | |
| 25 | + Block *b; | |
| 26 | + | |
| 27 | + ub = &uboot; | |
| 28 | + if(n > 0 && ub->iq != nil){ | |
| 29 | + b = iallocb(n); | |
| 30 | + memmove(b->wp, p, n); | |
| 31 | + b->wp += n; | |
| 32 | + qbwrite(ub->iq, b); | |
| 33 | + } | |
| 34 | +} | |
| 35 | + | |
| 36 | +int | |
| 37 | +uartinit(void) | |
| 38 | +{ | |
| 39 | + return 1<<0; | |
| 40 | +} | |
| 41 | + | |
| 42 | +Partition* | |
| 43 | +setuartpart(int, char *s) | |
| 44 | +{ | |
| 45 | + static Partition pp[1]; | |
| 46 | + | |
| 47 | + if(strcmp(s, "boot") != 0 && strcmp(s, "disk") != 0) | |
| 48 | + return 0; | |
| 49 | + pp[0].start = 0; | |
| 50 | + pp[0].end = 2*1024*1024; | |
| 51 | + strcpy(pp[0].name, "boot"); | |
| 52 | + return pp; | |
| 53 | +} | |
| 54 | + | |
| 55 | +long | |
| 56 | +uartseek(int, long) | |
| 57 | +{ | |
| 58 | + /* start the boot */ | |
| 59 | + if(uboot.iq == nil) | |
| 60 | + uboot.iq = qopen(64*1024, 0, 0, 0); | |
| 61 | + if(uboot.partial){ | |
| 62 | + freeb(uboot.partial); | |
| 63 | + uboot.partial = 0; | |
| 64 | + } | |
| 65 | + print("uart: start transmission\n"); | |
| 66 | + uartsetboot(uartbrecv); | |
| 67 | + uboot.csum = ~0; | |
| 68 | + uboot.bno = 0; | |
| 69 | + uboot.nleft = 0; | |
| 70 | + uboot.ntimeout = 0; | |
| 71 | + return 0; | |
| 72 | +} | |
| 73 | + | |
| 74 | +static long | |
| 75 | +uartreadn(void *buf, int nb) | |
| 76 | +{ | |
| 77 | + ulong start; | |
| 78 | + Uboot *ub; | |
| 79 | + int l; | |
| 80 | + Block *b; | |
| 81 | + uchar *p; | |
| 82 | + | |
| 83 | + p = buf; | |
| 84 | + ub = &uboot; | |
| 85 | + start = m->ticks; | |
| 86 | + while(nb > 0){ | |
| 87 | + b = ub->partial; | |
| 88 | + ub->partial = nil; | |
| 89 | + if(b == nil){ | |
| 90 | + ub->ntimeout = 0; | |
| 91 | + while((b = qget(ub->iq)) == 0){ | |
| 92 | + if(TK2MS(m->ticks - start) >= 15*1000){ | |
| 93 | + if(++ub->ntimeout >= 3){ | |
| 94 | + print("uart: timeout\n"); | |
| 95 | + return 0; | |
| 96 | + } | |
| 97 | + uartputs("n", 1); | |
| 98 | + } | |
| 99 | + } | |
| 100 | + } | |
| 101 | + l = BLEN(b); | |
| 102 | + if(l > nb) | |
| 103 | + l = nb; | |
| 104 | + memmove(p, b->rp, l); | |
| 105 | + b->rp += l; | |
| 106 | + if(b->rp >= b->wp) | |
| 107 | + freeb(b); | |
| 108 | + else | |
| 109 | + ub->partial = b; | |
| 110 | + nb -= l; | |
| 111 | + p += l; | |
| 112 | + } | |
| 113 | + return p-(uchar*)buf; | |
| 114 | +} | |
| 115 | + | |
| 116 | +long | |
| 117 | +uartread(int, void *buf, long n) | |
| 118 | +{ | |
| 119 | + uchar *p; | |
| 120 | + int l; | |
| 121 | + static uchar lbuf[64]; | |
| 122 | + | |
| 123 | + p = buf; | |
| 124 | + if((l = uboot.nleft) > 0){ | |
| 125 | + if(l > n) | |
| 126 | + l = n; | |
| 127 | + uboot.nleft -= l; | |
| 128 | + memmove(p, uboot.buf, l); | |
| 129 | + p += l; | |
| 130 | + n -= l; | |
| 131 | + } | |
| 132 | + while(n > 0){ | |
| 133 | + l = uartreadn(lbuf, sizeof(lbuf)); | |
| 134 | + if(l < sizeof(lbuf)) | |
| 135 | + return 0; | |
| 136 | + if(l > n){ | |
| 137 | + uboot.nleft = l-n; | |
| 138 | + memmove(uboot.buf, lbuf+n, uboot.nleft); | |
| 139 | + l = n; | |
| 140 | + } | |
| 141 | + memmove(p, lbuf, l); | |
| 142 | + n -= l; | |
| 143 | + p += l; | |
| 144 | + uboot.bno++; | |
| 145 | + uartputs("y", 1); | |
| 146 | + } | |
| 147 | + return p-(uchar*)buf; | |
| 148 | +} | |
| 149 | + | |
| 150 | +/* | |
| 151 | + * from Rob Warnock | |
| 152 | + */ | |
| 153 | +static ulong crc32tab[256]; /* initialised on first call to crc32 */ | |
| 154 | + | |
| 155 | +enum { | |
| 156 | + CRC32POLY = 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */ | |
| 157 | +}; | |
| 158 | + | |
| 159 | +/* | |
| 160 | + * Build auxiliary table for parallel byte-at-a-time CRC-32. | |
| 161 | + */ | |
| 162 | +static void | |
| 163 | +initcrc32(void) | |
| 164 | +{ | |
| 165 | + int i, j; | |
| 166 | + ulong c; | |
| 167 | + | |
| 168 | + for(i = 0; i < 256; i++) { | |
| 169 | + for(c = i << 24, j = 8; j > 0; j--) | |
| 170 | + if(c & (1<<31)) | |
| 171 | + c = (c<<1) ^ CRC32POLY; | |
| 172 | + else | |
| 173 | + c <<= 1; | |
| 174 | + crc32tab[i] = c; | |
| 175 | + } | |
| 176 | +} | |
| 177 | + | |
| 178 | +ulong | |
| 179 | +crc32(void *buf, int n, ulong crc) | |
| 180 | +{ | |
| 181 | + uchar *p; | |
| 182 | + | |
| 183 | + if(crc32tab[1] == 0) | |
| 184 | + initcrc32(); | |
| 185 | + crc = ~crc; | |
| 186 | + for(p = buf; --n >= 0;) | |
| 187 | + crc = (crc << 8) ^ crc32tab[(crc >> 24) ^ *p++]; | |
| 188 | + return ~crc; | |
| 189 | +} | |
| @@ -0,0 +1,43 @@ | ||
| 1 | +struct Ureg | |
| 2 | +{ | |
| 3 | + ulong cause; | |
| 4 | + union { ulong srr1; ulong status;}; | |
| 5 | + ulong pc; /* SRR0 */ | |
| 6 | + ulong pad; | |
| 7 | + ulong lr; | |
| 8 | + ulong cr; | |
| 9 | + ulong xer; | |
| 10 | + ulong ctr; | |
| 11 | + ulong r0; | |
| 12 | + union{ ulong r1; ulong sp; ulong usp; }; | |
| 13 | + ulong r2; | |
| 14 | + ulong r3; | |
| 15 | + ulong r4; | |
| 16 | + ulong r5; | |
| 17 | + ulong r6; | |
| 18 | + ulong r7; | |
| 19 | + ulong r8; | |
| 20 | + ulong r9; | |
| 21 | + ulong r10; | |
| 22 | + ulong r11; | |
| 23 | + ulong r12; | |
| 24 | + ulong r13; | |
| 25 | + ulong r14; | |
| 26 | + ulong r15; | |
| 27 | + ulong r16; | |
| 28 | + ulong r17; | |
| 29 | + ulong r18; | |
| 30 | + ulong r19; | |
| 31 | + ulong r20; | |
| 32 | + ulong r21; | |
| 33 | + ulong r22; | |
| 34 | + ulong r23; | |
| 35 | + ulong r24; | |
| 36 | + ulong r25; | |
| 37 | + ulong r26; | |
| 38 | + ulong r27; | |
| 39 | + ulong r28; | |
| 40 | + ulong r29; | |
| 41 | + ulong r30; | |
| 42 | + ulong r31; | |
| 43 | +}; | |
| @@ -0,0 +1,234 @@ | ||
| 1 | +#include "boot.h" | |
| 2 | +#include "squeeze.h" | |
| 3 | + | |
| 4 | +/* | |
| 5 | + * for details of `unsqueeze' see: | |
| 6 | + * | |
| 7 | + * %A Mark Taunton | |
| 8 | + * %T Compressed Executables: An Exercise in Thinking Small | |
| 9 | + * %P 385-404 | |
| 10 | + * %I USENIX | |
| 11 | + * %B USENIX Conference Proceedings | |
| 12 | + * %D Summer 1991 | |
| 13 | + * %C Nashville, TN | |
| 14 | + * | |
| 15 | + * several of the unimplemented improvements described in the paper | |
| 16 | + * have been implemented here | |
| 17 | + * | |
| 18 | + * there is a further transformation on the powerpc (QFLAG!=0) to shuffle bits | |
| 19 | + * in certain instructions so as to push the fixed bits to the top of the word. | |
| 20 | + */ | |
| 21 | + | |
| 22 | +#define EXECHDRLEN (8*4) | |
| 23 | + | |
| 24 | +typedef struct Squeeze Squeeze; | |
| 25 | +struct Squeeze { | |
| 26 | + int n; | |
| 27 | + ulong tab[7*256]; | |
| 28 | +}; | |
| 29 | + | |
| 30 | +#define GET4(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3]) | |
| 31 | + | |
| 32 | +/* | |
| 33 | + * for speed of unsqueezing from Flash, certain checks are | |
| 34 | + * not done inside the loop (as they would be in the unsqueeze program zqs), | |
| 35 | + * but instead the checksum is expected to catch corrupted files. | |
| 36 | + * in fact the Squeeze array bounds can't be exceeded in practice | |
| 37 | + * because the tables are always full for a squeezed kernel. | |
| 38 | + */ | |
| 39 | +enum { | |
| 40 | + QFLAG = 1, /* invert powerpc-specific code transformation */ | |
| 41 | + CHECK = 0, /* check precise bounds in Squeeze array (otherwise checksum detects error) */ | |
| 42 | +}; | |
| 43 | + | |
| 44 | +static ulong chksum; | |
| 45 | +static int rdtab(Block*, Squeeze*, int); | |
| 46 | +static ulong* unsqueeze(ulong*, uchar*, uchar*, Squeeze*, Squeeze*, ulong); | |
| 47 | +static uchar* unsqzseg(uchar*, Block*, long, long, char*); | |
| 48 | +static Alarm* unsqzal; | |
| 49 | + | |
| 50 | +int | |
| 51 | +issqueezed(uchar *b) | |
| 52 | +{ | |
| 53 | + return GET4(b) == SQMAGIC? GET4(b+SQHDRLEN): 0; | |
| 54 | +} | |
| 55 | + | |
| 56 | +static void | |
| 57 | +unsqzdot(Alarm*) | |
| 58 | +{ | |
| 59 | + unsqzal = alarm(500, unsqzdot, nil); | |
| 60 | + print("."); | |
| 61 | +} | |
| 62 | + | |
| 63 | +long | |
| 64 | +unsqueezef(Block *b, ulong *entryp) | |
| 65 | +{ | |
| 66 | + uchar *loada, *wp; | |
| 67 | + ulong toptxt, topdat, oldsum; | |
| 68 | + long asis, nst, nsd; | |
| 69 | + Sqhdr *sqh; | |
| 70 | + Exec *ex; | |
| 71 | + | |
| 72 | + if(BLEN(b) < SQHDRLEN+EXECHDRLEN) | |
| 73 | + return -1; | |
| 74 | + sqh = (Sqhdr*)b->rp; | |
| 75 | + if(GET4(sqh->magic) != SQMAGIC) | |
| 76 | + return -1; | |
| 77 | + chksum = 0; | |
| 78 | + toptxt = GET4(sqh->toptxt); | |
| 79 | + topdat = GET4(sqh->topdat); | |
| 80 | + oldsum = GET4(sqh->sum); | |
| 81 | + asis = GET4(sqh->asis); | |
| 82 | + nst = GET4(sqh->text); | |
| 83 | + nsd = GET4(sqh->data); | |
| 84 | + b->rp += SQHDRLEN; | |
| 85 | + ex = (Exec*)b->rp; | |
| 86 | + if(GET4(ex->magic) != Q_MAGIC){ | |
| 87 | + print("zqs: not powerPC executable\n"); | |
| 88 | + return -1; | |
| 89 | + } | |
| 90 | + *entryp = GET4(ex->entry); | |
| 91 | + b->rp += EXECHDRLEN; | |
| 92 | + loada = KADDR(PADDR(*entryp)); | |
| 93 | + wp = unsqzseg(loada, b, nst, toptxt, "text"); | |
| 94 | + if(wp == nil){ | |
| 95 | + print("zqs: format error\n"); | |
| 96 | + return -1; | |
| 97 | + } | |
| 98 | + if(nsd){ | |
| 99 | + wp = (uchar*)PGROUND((ulong)wp); | |
| 100 | + wp = unsqzseg(wp, b, nsd, topdat, "data"); | |
| 101 | + if(wp == nil){ | |
| 102 | + print("zqs: format error\n"); | |
| 103 | + return -1; | |
| 104 | + } | |
| 105 | + } | |
| 106 | + if(asis){ | |
| 107 | + memmove(wp, b->rp, asis); | |
| 108 | + wp += asis; | |
| 109 | + b->rp += asis; | |
| 110 | + } | |
| 111 | + if(chksum != oldsum){ | |
| 112 | + print("\nsqueezed kernel: checksum error: %8.8lux need %8.8lux\n", chksum, oldsum); | |
| 113 | + return -1; | |
| 114 | + } | |
| 115 | + return wp-loada; | |
| 116 | +} | |
| 117 | + | |
| 118 | +static uchar * | |
| 119 | +unsqzseg(uchar *wp, Block *b, long ns, long top, char *what) | |
| 120 | +{ | |
| 121 | + static Squeeze sq3, sq4; | |
| 122 | + | |
| 123 | + print("unpack %s %8.8lux %lud:", what, wp, ns); | |
| 124 | + if(ns == 0) | |
| 125 | + return wp; | |
| 126 | + if(rdtab(b, &sq3, 0) < 0) | |
| 127 | + return nil; | |
| 128 | + if(rdtab(b, &sq4, 8) < 0) | |
| 129 | + return nil; | |
| 130 | + if(BLEN(b) < ns){ | |
| 131 | + print(" **size error\n"); | |
| 132 | + return nil; | |
| 133 | + } | |
| 134 | + unsqzal = alarm(500, unsqzdot, nil); | |
| 135 | + wp = (uchar*)unsqueeze((ulong*)wp, b->rp, b->rp+ns, &sq3, &sq4, top); | |
| 136 | + cancel(unsqzal); | |
| 137 | + unsqzal = nil; | |
| 138 | + print("\n"); | |
| 139 | + if(wp == nil){ | |
| 140 | + print("zqs: corrupt squeezed data stream\n"); | |
| 141 | + return nil; | |
| 142 | + } | |
| 143 | + b->rp += ns; | |
| 144 | + return wp; | |
| 145 | +} | |
| 146 | + | |
| 147 | +static ulong* | |
| 148 | +unsqueeze(ulong *wp, uchar *rp, uchar *ep, Squeeze *sq3, Squeeze *sq4, ulong top) | |
| 149 | +{ | |
| 150 | + ulong nx, csum; | |
| 151 | + int code, n; | |
| 152 | + | |
| 153 | + if(QFLAG){ | |
| 154 | + QREMAP(top); /* adjust top just once, outside the loop */ | |
| 155 | + } | |
| 156 | + csum = chksum; | |
| 157 | + while(rp < ep){ | |
| 158 | + /* no function calls within this loop for speed */ | |
| 159 | + code = *rp; | |
| 160 | + rp++; | |
| 161 | + n = 0; | |
| 162 | + nx = code>>4; | |
| 163 | + do{ | |
| 164 | + if(nx == 0){ | |
| 165 | + nx = top; | |
| 166 | + }else{ | |
| 167 | + if(nx==1){ | |
| 168 | + nx = (((((rp[3]<<8)|rp[2])<<8)|rp[1])<<8)|rp[0]; | |
| 169 | + rp += 4; | |
| 170 | + }else if(nx <= 8){ /* 2 to 8 */ | |
| 171 | + nx = ((nx-2)<<8) | rp[0]; | |
| 172 | + if(CHECK && nx >= sq4->n) | |
| 173 | + return nil; /* corrupted file */ | |
| 174 | + nx = sq4->tab[nx] | rp[1]; | |
| 175 | + rp += 2; | |
| 176 | + }else{ /* 9 to 15 */ | |
| 177 | + nx = ((nx-9)<<8) | rp[0]; | |
| 178 | + if(CHECK && nx >= sq3->n) | |
| 179 | + return nil; /* corrupted file */ | |
| 180 | + nx = sq3->tab[nx]; | |
| 181 | + rp++; | |
| 182 | + } | |
| 183 | + if(rp > ep) | |
| 184 | + return nil; /* corrupted file */ | |
| 185 | + if(QFLAG){ | |
| 186 | + QREMAP(nx); | |
| 187 | + } | |
| 188 | + } | |
| 189 | + *wp = nx; | |
| 190 | + wp++; | |
| 191 | + csum += nx; | |
| 192 | + nx = code & 0xF; | |
| 193 | + }while(++n == 1); | |
| 194 | + } | |
| 195 | + chksum = csum; | |
| 196 | + return wp; | |
| 197 | +} | |
| 198 | + | |
| 199 | +static int | |
| 200 | +rdtab(Block *b, Squeeze *sq, int shift) | |
| 201 | +{ | |
| 202 | + uchar *p, *ep; | |
| 203 | + ulong v, w; | |
| 204 | + int i; | |
| 205 | + | |
| 206 | + if(BLEN(b) < 2) | |
| 207 | + return -1; | |
| 208 | + i = (b->rp[0]<<8) | b->rp[1]; | |
| 209 | + if(1) | |
| 210 | + print(" T%d", i); | |
| 211 | + b->rp += 2; | |
| 212 | + if((i -= 2) > 0){ | |
| 213 | + if(BLEN(b) < i) | |
| 214 | + return -1; | |
| 215 | + } | |
| 216 | + sq->n = 0; | |
| 217 | + p = b->rp; | |
| 218 | + ep = b->rp+i; | |
| 219 | + b->rp += i; | |
| 220 | + v = 0; | |
| 221 | + while(p < ep){ | |
| 222 | + w = 0; | |
| 223 | + do{ | |
| 224 | + if(p >= ep) | |
| 225 | + return -1; | |
| 226 | + w = (w<<7) | (*p & 0x7F); | |
| 227 | + }while(*p++ & 0x80); | |
| 228 | + v += w; | |
| 229 | + if(0) | |
| 230 | + print("%d %8.8lux %8.8lux\n", sq->n, v, w); | |
| 231 | + sq->tab[sq->n++] = v<<shift; | |
| 232 | + } | |
| 233 | + return 0; | |
| 234 | +} | |
| @@ -0,0 +1,308 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +/* | |
| 9 | + * INS8250 uart | |
| 10 | + */ | |
| 11 | +enum | |
| 12 | +{ | |
| 13 | + /* | |
| 14 | + * register numbers | |
| 15 | + */ | |
| 16 | + Data= 0, /* xmit/rcv buffer */ | |
| 17 | + Iena= 1, /* interrupt enable */ | |
| 18 | + Ircv= (1<<0), /* for char rcv'd */ | |
| 19 | + Ixmt= (1<<1), /* for xmit buffer empty */ | |
| 20 | + Irstat=(1<<2), /* for change in rcv'er status */ | |
| 21 | + Imstat=(1<<3), /* for change in modem status */ | |
| 22 | + Istat= 2, /* interrupt flag (read) */ | |
| 23 | + Tctl= 2, /* test control (write) */ | |
| 24 | + Format= 3, /* byte format */ | |
| 25 | + Bits8= (3<<0), /* 8 bits/byte */ | |
| 26 | + Stop2= (1<<2), /* 2 stop bits */ | |
| 27 | + Pena= (1<<3), /* generate parity */ | |
| 28 | + Peven= (1<<4), /* even parity */ | |
| 29 | + Pforce=(1<<5), /* force parity */ | |
| 30 | + Break= (1<<6), /* generate a break */ | |
| 31 | + Dra= (1<<7), /* address the divisor */ | |
| 32 | + Mctl= 4, /* modem control */ | |
| 33 | + Dtr= (1<<0), /* data terminal ready */ | |
| 34 | + Rts= (1<<1), /* request to send */ | |
| 35 | + Ri= (1<<2), /* ring */ | |
| 36 | + Inton= (1<<3), /* turn on interrupts */ | |
| 37 | + Loop= (1<<4), /* loop back */ | |
| 38 | + Lstat= 5, /* line status */ | |
| 39 | + Inready=(1<<0), /* receive buffer full */ | |
| 40 | + Oerror=(1<<1), /* receiver overrun */ | |
| 41 | + Perror=(1<<2), /* receiver parity error */ | |
| 42 | + Ferror=(1<<3), /* rcv framing error */ | |
| 43 | + Outready=(1<<5), /* output buffer empty */ | |
| 44 | + Mstat= 6, /* modem status */ | |
| 45 | + Ctsc= (1<<0), /* clear to send changed */ | |
| 46 | + Dsrc= (1<<1), /* data set ready changed */ | |
| 47 | + Rire= (1<<2), /* rising edge of ring indicator */ | |
| 48 | + Dcdc= (1<<3), /* data carrier detect changed */ | |
| 49 | + Cts= (1<<4), /* complement of clear to send line */ | |
| 50 | + Dsr= (1<<5), /* complement of data set ready line */ | |
| 51 | + Ring= (1<<6), /* complement of ring indicator line */ | |
| 52 | + Dcd= (1<<7), /* complement of data carrier detect line */ | |
| 53 | + Scratch=7, /* scratchpad */ | |
| 54 | + Dlsb= 0, /* divisor lsb */ | |
| 55 | + Dmsb= 1, /* divisor msb */ | |
| 56 | + | |
| 57 | + Serial= 0, | |
| 58 | + Modem= 1, | |
| 59 | +}; | |
| 60 | + | |
| 61 | +typedef struct Uart Uart; | |
| 62 | +struct Uart | |
| 63 | +{ | |
| 64 | + int port; | |
| 65 | + uchar sticky[8]; /* sticky write register values */ | |
| 66 | + uchar txbusy; | |
| 67 | + | |
| 68 | + void (*rx)(int); /* routine to take a received character */ | |
| 69 | + int (*tx)(void); /* routine to get a character to transmit */ | |
| 70 | + | |
| 71 | + ulong frame; | |
| 72 | + ulong overrun; | |
| 73 | +}; | |
| 74 | + | |
| 75 | +static Uart com[2]; | |
| 76 | +static Uart* uart; | |
| 77 | + | |
| 78 | +#define UartFREQ 1843200 | |
| 79 | + | |
| 80 | +#define uartwrreg(u,r,v) outb((u)->port + r, (u)->sticky[r] | (v)) | |
| 81 | +#define uartrdreg(u,r) inb((u)->port + r) | |
| 82 | + | |
| 83 | +/* | |
| 84 | + * set the baud rate by calculating and setting the baudrate | |
| 85 | + * generator constant. This will work with fairly non-standard | |
| 86 | + * baud rates. | |
| 87 | + */ | |
| 88 | +static void | |
| 89 | +uartsetbaud(Uart *up, int rate) | |
| 90 | +{ | |
| 91 | + ulong brconst; | |
| 92 | + | |
| 93 | + brconst = (UartFREQ+8*rate-1)/(16*rate); | |
| 94 | + | |
| 95 | + uartwrreg(up, Format, Dra); | |
| 96 | + outb(up->port+Dmsb, (brconst>>8) & 0xff); | |
| 97 | + outb(up->port+Dlsb, brconst & 0xff); | |
| 98 | + uartwrreg(up, Format, 0); | |
| 99 | +} | |
| 100 | + | |
| 101 | +/* | |
| 102 | + * toggle DTR | |
| 103 | + */ | |
| 104 | +static void | |
| 105 | +uartdtr(Uart *up, int n) | |
| 106 | +{ | |
| 107 | + if(n) | |
| 108 | + up->sticky[Mctl] |= Dtr; | |
| 109 | + else | |
| 110 | + up->sticky[Mctl] &= ~Dtr; | |
| 111 | + uartwrreg(up, Mctl, 0); | |
| 112 | +} | |
| 113 | + | |
| 114 | +/* | |
| 115 | + * toggle RTS | |
| 116 | + */ | |
| 117 | +static void | |
| 118 | +uartrts(Uart *up, int n) | |
| 119 | +{ | |
| 120 | + if(n) | |
| 121 | + up->sticky[Mctl] |= Rts; | |
| 122 | + else | |
| 123 | + up->sticky[Mctl] &= ~Rts; | |
| 124 | + uartwrreg(up, Mctl, 0); | |
| 125 | +} | |
| 126 | + | |
| 127 | +static void | |
| 128 | +uartintr(Ureg*, void *arg) | |
| 129 | +{ | |
| 130 | + Uart *up; | |
| 131 | + int ch; | |
| 132 | + int s, l, loops; | |
| 133 | + | |
| 134 | + up = arg; | |
| 135 | + for(loops = 0; loops < 1024; loops++){ | |
| 136 | + s = uartrdreg(up, Istat); | |
| 137 | + switch(s & 0x3F){ | |
| 138 | + case 6: /* receiver line status */ | |
| 139 | + l = uartrdreg(up, Lstat); | |
| 140 | + if(l & Ferror) | |
| 141 | + up->frame++; | |
| 142 | + if(l & Oerror) | |
| 143 | + up->overrun++; | |
| 144 | + break; | |
| 145 | + | |
| 146 | + case 4: /* received data available */ | |
| 147 | + case 12: | |
| 148 | + ch = inb(up->port+Data); | |
| 149 | + if(up->rx) | |
| 150 | + (*up->rx)(ch); | |
| 151 | + break; | |
| 152 | + | |
| 153 | + case 2: /* transmitter empty */ | |
| 154 | + ch = -1; | |
| 155 | + if(up->tx) | |
| 156 | + ch = (*up->tx)(); | |
| 157 | + if(ch != -1) | |
| 158 | + outb(up->port+Data, ch); | |
| 159 | + else | |
| 160 | + up->txbusy = 0; | |
| 161 | + break; | |
| 162 | + | |
| 163 | + case 0: /* modem status */ | |
| 164 | + uartrdreg(up, Mstat); | |
| 165 | + break; | |
| 166 | + | |
| 167 | + default: | |
| 168 | + if(s&1) | |
| 169 | + return; | |
| 170 | + print("weird modem interrupt #%2.2ux\n", s); | |
| 171 | + break; | |
| 172 | + } | |
| 173 | + } | |
| 174 | + panic("uartintr: 0x%2.2ux\n", uartrdreg(up, Istat)); | |
| 175 | +} | |
| 176 | + | |
| 177 | +/* | |
| 178 | + * turn on a port's interrupts. set DTR and RTS | |
| 179 | + */ | |
| 180 | +static void | |
| 181 | +uartenable(Uart *up) | |
| 182 | +{ | |
| 183 | + /* | |
| 184 | + * turn on interrupts | |
| 185 | + */ | |
| 186 | + up->sticky[Iena] = 0; | |
| 187 | + if(up->tx) | |
| 188 | + up->sticky[Iena] |= Ixmt; | |
| 189 | + if(up->rx) | |
| 190 | + up->sticky[Iena] |= Ircv|Irstat; | |
| 191 | + uartwrreg(up, Iena, 0); | |
| 192 | + | |
| 193 | + /* | |
| 194 | + * turn on DTR and RTS | |
| 195 | + */ | |
| 196 | + uartdtr(up, 1); | |
| 197 | + uartrts(up, 1); | |
| 198 | +} | |
| 199 | + | |
| 200 | +static void | |
| 201 | +uartdisable(Uart* up) | |
| 202 | +{ | |
| 203 | + /* | |
| 204 | + * Disable interrupts. | |
| 205 | + */ | |
| 206 | + up->sticky[Iena] = 0; | |
| 207 | + uartwrreg(up, Iena, 0); | |
| 208 | + uartdtr(up, 0); | |
| 209 | + uartrts(up, 0); | |
| 210 | +} | |
| 211 | + | |
| 212 | +void | |
| 213 | +uartspecial(int port, void (*rx)(int), int (*tx)(void), int baud) | |
| 214 | +{ | |
| 215 | + Uart *up; | |
| 216 | + int vector; | |
| 217 | + | |
| 218 | + switch(port){ | |
| 219 | + case 0: | |
| 220 | + port = 0x3F8; | |
| 221 | + vector = VectorUART0; | |
| 222 | + up = &com[0]; | |
| 223 | + break; | |
| 224 | + case 1: | |
| 225 | + port = 0x2F8; | |
| 226 | + vector = VectorUART1; | |
| 227 | + up = &com[1]; | |
| 228 | + break; | |
| 229 | + default: | |
| 230 | + return; | |
| 231 | + } | |
| 232 | + | |
| 233 | + if(uart != nil && uart != up) | |
| 234 | + uartdisable(uart); | |
| 235 | + uart = up; | |
| 236 | + | |
| 237 | + if(up->port == 0){ | |
| 238 | + up->port = port; | |
| 239 | + setvec(vector, uartintr, up); | |
| 240 | + } | |
| 241 | + | |
| 242 | + /* | |
| 243 | + * set rate to 9600 baud. | |
| 244 | + * 8 bits/character. | |
| 245 | + * 1 stop bit. | |
| 246 | + * interrupts enabled. | |
| 247 | + */ | |
| 248 | + uartsetbaud(up, 9600); | |
| 249 | + up->sticky[Format] = Bits8; | |
| 250 | + uartwrreg(up, Format, 0); | |
| 251 | + up->sticky[Mctl] |= Inton; | |
| 252 | + uartwrreg(up, Mctl, 0x0); | |
| 253 | + | |
| 254 | + up->rx = rx; | |
| 255 | + up->tx = tx; | |
| 256 | + uartenable(up); | |
| 257 | + if(baud) | |
| 258 | + uartsetbaud(up, baud); | |
| 259 | +} | |
| 260 | + | |
| 261 | +void | |
| 262 | +uartputc(int c) | |
| 263 | +{ | |
| 264 | + int i; | |
| 265 | + Uart *up; | |
| 266 | + | |
| 267 | + if((up = uart) == nil) | |
| 268 | + return; | |
| 269 | + for(i = 0; i < 100; i++){ | |
| 270 | + if(uartrdreg(up, Lstat) & Outready) | |
| 271 | + break; | |
| 272 | + delay(1); | |
| 273 | + } | |
| 274 | + outb(up->port+Data, c); | |
| 275 | +} | |
| 276 | + | |
| 277 | +void | |
| 278 | +uartputs(IOQ *q, char *s, int n) | |
| 279 | +{ | |
| 280 | + Uart *up; | |
| 281 | + int c, x; | |
| 282 | + | |
| 283 | + if((up = uart) == nil) | |
| 284 | + return; | |
| 285 | + while(n--){ | |
| 286 | + if(*s == '\n') | |
| 287 | + q->putc(q, '\r'); | |
| 288 | + q->putc(q, *s++); | |
| 289 | + } | |
| 290 | + x = splhi(); | |
| 291 | + if(up->txbusy == 0 && (c = q->getc(q)) != -1){ | |
| 292 | + uartputc(c & 0xFF); | |
| 293 | + up->txbusy = 1; | |
| 294 | + } | |
| 295 | + splx(x); | |
| 296 | +} | |
| 297 | + | |
| 298 | +void | |
| 299 | +uartdrain(void) | |
| 300 | +{ | |
| 301 | + Uart *up; | |
| 302 | + int timeo; | |
| 303 | + | |
| 304 | + if((up = uart) == nil) | |
| 305 | + return; | |
| 306 | + for(timeo = 0; timeo < 10000 && up->txbusy; timeo++) | |
| 307 | + delay(1); | |
| 308 | +} | |
| @@ -0,0 +1,237 @@ | ||
| 1 | +Lucent Public License Version 1.02 | |
| 2 | + | |
| 3 | +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC | |
| 4 | +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE | |
| 5 | +PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. | |
| 6 | + | |
| 7 | +1. DEFINITIONS | |
| 8 | + | |
| 9 | +"Contribution" means: | |
| 10 | + | |
| 11 | + a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original | |
| 12 | + Program, and | |
| 13 | + b. in the case of each Contributor, | |
| 14 | + | |
| 15 | + i. changes to the Program, and | |
| 16 | + ii. additions to the Program; | |
| 17 | + | |
| 18 | + where such changes and/or additions to the Program were added to the | |
| 19 | + Program by such Contributor itself or anyone acting on such | |
| 20 | + Contributor's behalf, and the Contributor explicitly consents, in | |
| 21 | + accordance with Section 3C, to characterization of the changes and/or | |
| 22 | + additions as Contributions. | |
| 23 | + | |
| 24 | +"Contributor" means LUCENT and any other entity that has Contributed a | |
| 25 | +Contribution to the Program. | |
| 26 | + | |
| 27 | +"Distributor" means a Recipient that distributes the Program, | |
| 28 | +modifications to the Program, or any part thereof. | |
| 29 | + | |
| 30 | +"Licensed Patents" mean patent claims licensable by a Contributor | |
| 31 | +which are necessarily infringed by the use or sale of its Contribution | |
| 32 | +alone or when combined with the Program. | |
| 33 | + | |
| 34 | +"Original Program" means the original version of the software | |
| 35 | +accompanying this Agreement as released by LUCENT, including source | |
| 36 | +code, object code and documentation, if any. | |
| 37 | + | |
| 38 | +"Program" means the Original Program and Contributions or any part | |
| 39 | +thereof | |
| 40 | + | |
| 41 | +"Recipient" means anyone who receives the Program under this | |
| 42 | +Agreement, including all Contributors. | |
| 43 | + | |
| 44 | +2. GRANT OF RIGHTS | |
| 45 | + | |
| 46 | + a. Subject to the terms of this Agreement, each Contributor hereby | |
| 47 | + grants Recipient a non-exclusive, worldwide, royalty-free copyright | |
| 48 | + license to reproduce, prepare derivative works of, publicly display, | |
| 49 | + publicly perform, distribute and sublicense the Contribution of such | |
| 50 | + Contributor, if any, and such derivative works, in source code and | |
| 51 | + object code form. | |
| 52 | + | |
| 53 | + b. Subject to the terms of this Agreement, each Contributor hereby | |
| 54 | + grants Recipient a non-exclusive, worldwide, royalty-free patent | |
| 55 | + license under Licensed Patents to make, use, sell, offer to sell, | |
| 56 | + import and otherwise transfer the Contribution of such Contributor, if | |
| 57 | + any, in source code and object code form. The patent license granted | |
| 58 | + by a Contributor shall also apply to the combination of the | |
| 59 | + Contribution of that Contributor and the Program if, at the time the | |
| 60 | + Contribution is added by the Contributor, such addition of the | |
| 61 | + Contribution causes such combination to be covered by the Licensed | |
| 62 | + Patents. The patent license granted by a Contributor shall not apply | |
| 63 | + to (i) any other combinations which include the Contribution, nor to | |
| 64 | + (ii) Contributions of other Contributors. No hardware per se is | |
| 65 | + licensed hereunder. | |
| 66 | + | |
| 67 | + c. Recipient understands that although each Contributor grants the | |
| 68 | + licenses to its Contributions set forth herein, no assurances are | |
| 69 | + provided by any Contributor that the Program does not infringe the | |
| 70 | + patent or other intellectual property rights of any other entity. Each | |
| 71 | + Contributor disclaims any liability to Recipient for claims brought by | |
| 72 | + any other entity based on infringement of intellectual property rights | |
| 73 | + or otherwise. As a condition to exercising the rights and licenses | |
| 74 | + granted hereunder, each Recipient hereby assumes sole responsibility | |
| 75 | + to secure any other intellectual property rights needed, if any. For | |
| 76 | + example, if a third party patent license is required to allow | |
| 77 | + Recipient to distribute the Program, it is Recipient's responsibility | |
| 78 | + to acquire that license before distributing the Program. | |
| 79 | + | |
| 80 | + d. Each Contributor represents that to its knowledge it has sufficient | |
| 81 | + copyright rights in its Contribution, if any, to grant the copyright | |
| 82 | + license set forth in this Agreement. | |
| 83 | + | |
| 84 | +3. REQUIREMENTS | |
| 85 | + | |
| 86 | +A. Distributor may choose to distribute the Program in any form under | |
| 87 | +this Agreement or under its own license agreement, provided that: | |
| 88 | + | |
| 89 | + a. it complies with the terms and conditions of this Agreement; | |
| 90 | + | |
| 91 | + b. if the Program is distributed in source code or other tangible | |
| 92 | + form, a copy of this Agreement or Distributor's own license agreement | |
| 93 | + is included with each copy of the Program; and | |
| 94 | + | |
| 95 | + c. if distributed under Distributor's own license agreement, such | |
| 96 | + license agreement: | |
| 97 | + | |
| 98 | + i. effectively disclaims on behalf of all Contributors all warranties | |
| 99 | + and conditions, express and implied, including warranties or | |
| 100 | + conditions of title and non-infringement, and implied warranties or | |
| 101 | + conditions of merchantability and fitness for a particular purpose; | |
| 102 | + ii. effectively excludes on behalf of all Contributors all liability | |
| 103 | + for damages, including direct, indirect, special, incidental and | |
| 104 | + consequential damages, such as lost profits; and | |
| 105 | + iii. states that any provisions which differ from this Agreement are | |
| 106 | + offered by that Contributor alone and not by any other party. | |
| 107 | + | |
| 108 | +B. Each Distributor must include the following in a conspicuous | |
| 109 | + location in the Program: | |
| 110 | + | |
| 111 | + Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights | |
| 112 | + Reserved. | |
| 113 | + | |
| 114 | +C. In addition, each Contributor must identify itself as the | |
| 115 | +originator of its Contribution in a manner that reasonably allows | |
| 116 | +subsequent Recipients to identify the originator of the Contribution. | |
| 117 | +Also, each Contributor must agree that the additions and/or changes | |
| 118 | +are intended to be a Contribution. Once a Contribution is contributed, | |
| 119 | +it may not thereafter be revoked. | |
| 120 | + | |
| 121 | +4. COMMERCIAL DISTRIBUTION | |
| 122 | + | |
| 123 | +Commercial distributors of software may accept certain | |
| 124 | +responsibilities with respect to end users, business partners and the | |
| 125 | +like. While this license is intended to facilitate the commercial use | |
| 126 | +of the Program, the Distributor who includes the Program in a | |
| 127 | +commercial product offering should do so in a manner which does not | |
| 128 | +create potential liability for Contributors. Therefore, if a | |
| 129 | +Distributor includes the Program in a commercial product offering, | |
| 130 | +such Distributor ("Commercial Distributor") hereby agrees to defend | |
| 131 | +and indemnify every Contributor ("Indemnified Contributor") against | |
| 132 | +any losses, damages and costs (collectively"Losses") arising from | |
| 133 | +claims, lawsuits and other legal actions brought by a third party | |
| 134 | +against the Indemnified Contributor to the extent caused by the acts | |
| 135 | +or omissions of such Commercial Distributor in connection with its | |
| 136 | +distribution of the Program in a commercial product offering. The | |
| 137 | +obligations in this section do not apply to any claims or Losses | |
| 138 | +relating to any actual or alleged intellectual property infringement. | |
| 139 | +In order to qualify, an Indemnified Contributor must: a) promptly | |
| 140 | +notify the Commercial Distributor in writing of such claim, and b) | |
| 141 | +allow the Commercial Distributor to control, and cooperate with the | |
| 142 | +Commercial Distributor in, the defense and any related settlement | |
| 143 | +negotiations. The Indemnified Contributor may participate in any such | |
| 144 | +claim at its own expense. | |
| 145 | + | |
| 146 | +For example, a Distributor might include the Program in a commercial | |
| 147 | +product offering, Product X. That Distributor is then a Commercial | |
| 148 | +Distributor. If that Commercial Distributor then makes performance | |
| 149 | +claims, or offers warranties related to Product X, those performance | |
| 150 | +claims and warranties are such Commercial Distributor's responsibility | |
| 151 | +alone. Under this section, the Commercial Distributor would have to | |
| 152 | +defend claims against the Contributors related to those performance | |
| 153 | +claims and warranties, and if a court requires any Contributor to pay | |
| 154 | +any damages as a result, the Commercial Distributor must pay those | |
| 155 | +damages. | |
| 156 | + | |
| 157 | +5. NO WARRANTY | |
| 158 | + | |
| 159 | +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS | |
| 160 | +PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| 161 | +KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY | |
| 162 | +WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY | |
| 163 | +OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely | |
| 164 | +responsible for determining the appropriateness of using and | |
| 165 | +distributing the Program and assumes all risks associated with its | |
| 166 | +exercise of rights under this Agreement, including but not limited to | |
| 167 | +the risks and costs of program errors, compliance with applicable | |
| 168 | +laws, damage to or loss of data, programs or equipment, and | |
| 169 | +unavailability or interruption of operations. | |
| 170 | + | |
| 171 | +6. DISCLAIMER OF LIABILITY | |
| 172 | + | |
| 173 | +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR | |
| 174 | +ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, | |
| 175 | +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING | |
| 176 | +WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF | |
| 177 | +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| 178 | +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR | |
| 179 | +DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED | |
| 180 | +HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
| 181 | + | |
| 182 | +7. EXPORT CONTROL | |
| 183 | + | |
| 184 | +Recipient agrees that Recipient alone is responsible for compliance | |
| 185 | +with the United States export administration regulations (and the | |
| 186 | +export control laws and regulation of any other countries). | |
| 187 | + | |
| 188 | +8. GENERAL | |
| 189 | + | |
| 190 | +If any provision of this Agreement is invalid or unenforceable under | |
| 191 | +applicable law, it shall not affect the validity or enforceability of | |
| 192 | +the remainder of the terms of this Agreement, and without further | |
| 193 | +action by the parties hereto, such provision shall be reformed to the | |
| 194 | +minimum extent necessary to make such provision valid and enforceable. | |
| 195 | + | |
| 196 | +If Recipient institutes patent litigation against a Contributor with | |
| 197 | +respect to a patent applicable to software (including a cross-claim or | |
| 198 | +counterclaim in a lawsuit), then any patent licenses granted by that | |
| 199 | +Contributor to such Recipient under this Agreement shall terminate as | |
| 200 | +of the date such litigation is filed. In addition, if Recipient | |
| 201 | +institutes patent litigation against any entity (including a | |
| 202 | +cross-claim or counterclaim in a lawsuit) alleging that the Program | |
| 203 | +itself (excluding combinations of the Program with other software or | |
| 204 | +hardware) infringes such Recipient's patent(s), then such Recipient's | |
| 205 | +rights granted under Section 2(b) shall terminate as of the date such | |
| 206 | +litigation is filed. | |
| 207 | + | |
| 208 | +All Recipient's rights under this Agreement shall terminate if it | |
| 209 | +fails to comply with any of the material terms or conditions of this | |
| 210 | +Agreement and does not cure such failure in a reasonable period of | |
| 211 | +time after becoming aware of such noncompliance. If all Recipient's | |
| 212 | +rights under this Agreement terminate, Recipient agrees to cease use | |
| 213 | +and distribution of the Program as soon as reasonably practicable. | |
| 214 | +However, Recipient's obligations under this Agreement and any licenses | |
| 215 | +granted by Recipient relating to the Program shall continue and | |
| 216 | +survive. | |
| 217 | + | |
| 218 | +LUCENT may publish new versions (including revisions) of this | |
| 219 | +Agreement from time to time. Each new version of the Agreement will be | |
| 220 | +given a distinguishing version number. The Program (including | |
| 221 | +Contributions) may always be distributed subject to the version of the | |
| 222 | +Agreement under which it was received. In addition, after a new | |
| 223 | +version of the Agreement is published, Contributor may elect to | |
| 224 | +distribute the Program (including its Contributions) under the new | |
| 225 | +version. No one other than LUCENT has the right to modify this | |
| 226 | +Agreement. Except as expressly stated in Sections 2(a) and 2(b) above, | |
| 227 | +Recipient receives no rights or licenses to the intellectual property | |
| 228 | +of any Contributor under this Agreement, whether expressly, by | |
| 229 | +implication, estoppel or otherwise. All rights in the Program not | |
| 230 | +expressly granted under this Agreement are reserved. | |
| 231 | + | |
| 232 | +This Agreement is governed by the laws of the State of New York and | |
| 233 | +the intellectual property laws of the United States of America. No | |
| 234 | +party to this Agreement will bring a legal action under this Agreement | |
| 235 | +more than one year after the cause of action arose. Each party waives | |
| 236 | +its rights to a jury trial in any resulting litigation. | |
| 237 | + | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +Copyright © 1995-2006 Lucent Technologies Inc. and others. All rights reserved. | |
| 2 | +Revisions for use with Inferno © 2003-2006 Vita Nuova Holdings Limited. | |
| 3 | + | |
| 4 | +This software is provided under the terms of the Lucent Public License, Version 1.02. | |
| @@ -0,0 +1,123 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | +#define MAXALARM 10 | |
| 8 | + | |
| 9 | +Alarm alarmtab[MAXALARM]; | |
| 10 | + | |
| 11 | +/* | |
| 12 | + * Insert new into list after where | |
| 13 | + */ | |
| 14 | +void | |
| 15 | +insert(List **head, List *where, List *new) | |
| 16 | +{ | |
| 17 | + if(where == 0){ | |
| 18 | + new->next = *head; | |
| 19 | + *head = new; | |
| 20 | + }else{ | |
| 21 | + new->next = where->next; | |
| 22 | + where->next = new; | |
| 23 | + } | |
| 24 | + | |
| 25 | +} | |
| 26 | + | |
| 27 | +/* | |
| 28 | + * Delete old from list. where->next is known to be old. | |
| 29 | + */ | |
| 30 | +void | |
| 31 | +delete(List **head, List *where, List *old) | |
| 32 | +{ | |
| 33 | + if(where == 0){ | |
| 34 | + *head = old->next; | |
| 35 | + return; | |
| 36 | + } | |
| 37 | + where->next = old->next; | |
| 38 | +} | |
| 39 | + | |
| 40 | +Alarm* | |
| 41 | +newalarm(void) | |
| 42 | +{ | |
| 43 | + int i; | |
| 44 | + Alarm *a; | |
| 45 | + | |
| 46 | + for(i=0,a=alarmtab; i < nelem(alarmtab); i++,a++) | |
| 47 | + if(a->busy==0 && a->f==0){ | |
| 48 | + a->f = 0; | |
| 49 | + a->arg = 0; | |
| 50 | + a->busy = 1; | |
| 51 | + return a; | |
| 52 | + } | |
| 53 | + panic("newalarm"); | |
| 54 | + return 0; /* not reached */ | |
| 55 | +} | |
| 56 | + | |
| 57 | +Alarm* | |
| 58 | +alarm(int ms, void (*f)(Alarm*), void *arg) | |
| 59 | +{ | |
| 60 | + Alarm *a, *w, *pw; | |
| 61 | + ulong s; | |
| 62 | + | |
| 63 | + if(ms < 0) | |
| 64 | + ms = 0; | |
| 65 | + s = splhi(); | |
| 66 | + a = newalarm(); | |
| 67 | + a->dt = MS2TK(ms); | |
| 68 | + a->f = f; | |
| 69 | + a->arg = arg; | |
| 70 | + pw = 0; | |
| 71 | + for(w=m->alarm; w; pw=w, w=w->next){ | |
| 72 | + if(w->dt <= a->dt){ | |
| 73 | + a->dt -= w->dt; | |
| 74 | + continue; | |
| 75 | + } | |
| 76 | + w->dt -= a->dt; | |
| 77 | + break; | |
| 78 | + } | |
| 79 | + insert(&m->alarm, pw, a); | |
| 80 | + splx(s); | |
| 81 | + return a; | |
| 82 | +} | |
| 83 | + | |
| 84 | +void | |
| 85 | +cancel(Alarm *a) | |
| 86 | +{ | |
| 87 | + a->f = 0; | |
| 88 | +} | |
| 89 | + | |
| 90 | +void | |
| 91 | +alarminit(void) | |
| 92 | +{ | |
| 93 | +} | |
| 94 | + | |
| 95 | +#define NA 10 /* alarms per clock tick */ | |
| 96 | +void | |
| 97 | +checkalarms(void) | |
| 98 | +{ | |
| 99 | + int i, n, s; | |
| 100 | + Alarm *a; | |
| 101 | + void (*f)(Alarm*); | |
| 102 | + Alarm *alist[NA]; | |
| 103 | + | |
| 104 | + s = splhi(); | |
| 105 | + a = m->alarm; | |
| 106 | + if(a){ | |
| 107 | + for(n=0; a && a->dt<=0 && n<NA; n++){ | |
| 108 | + alist[n] = a; | |
| 109 | + delete(&m->alarm, 0, a); | |
| 110 | + a = m->alarm; | |
| 111 | + } | |
| 112 | + if(a) | |
| 113 | + a->dt--; | |
| 114 | + | |
| 115 | + for(i = 0; i < n; i++){ | |
| 116 | + f = alist[i]->f; /* avoid race with cancel */ | |
| 117 | + if(f) | |
| 118 | + (*f)(alist[i]); | |
| 119 | + alist[i]->busy = 0; | |
| 120 | + } | |
| 121 | + } | |
| 122 | + splx(s); | |
| 123 | +} | |
| @@ -0,0 +1,16 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +Apminfo apm; | |
| 9 | + | |
| 10 | +void | |
| 11 | +apminit(void) | |
| 12 | +{ | |
| 13 | + if(getconf("apm0") && apm.haveinfo) | |
| 14 | + changeconf("apm0=ax=%x ebx=%x cx=%x dx=%x di=%x esi=%x\n", | |
| 15 | + apm.ax, apm.ebx, apm.cx, apm.dx, apm.di, apm.esi); | |
| 16 | +} | |
| @@ -0,0 +1,460 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +#include "fs.h" | |
| 9 | + | |
| 10 | +Type types[] = { | |
| 11 | + { Tfloppy, | |
| 12 | + Fini|Ffs, | |
| 13 | + floppyinit, floppyinitdev, | |
| 14 | + floppygetfspart, 0, floppyboot, | |
| 15 | + }, | |
| 16 | + { Tsd, | |
| 17 | + Fini|Ffs, | |
| 18 | + sdinit, sdinitdev, | |
| 19 | + sdgetfspart, sdaddconf, sdboot, | |
| 20 | + }, | |
| 21 | + { Tnil, | |
| 22 | + 0, | |
| 23 | + 0, 0, | |
| 24 | + 0, 0, 0, | |
| 25 | + }, | |
| 26 | +}; | |
| 27 | + | |
| 28 | +#include "sd.h" | |
| 29 | + | |
| 30 | +extern SDifc sdataifc; | |
| 31 | +extern SDifc sdmylexifc; | |
| 32 | +extern SDifc sd53c8xxifc; | |
| 33 | +SDifc* sdifc[] = { | |
| 34 | + &sdataifc, | |
| 35 | +// &sdmylexifc, | |
| 36 | +// &sd53c8xxifc, | |
| 37 | + nil, | |
| 38 | +}; | |
| 39 | + | |
| 40 | +typedef struct Mode Mode; | |
| 41 | + | |
| 42 | +enum { | |
| 43 | + Maxdev = 7, | |
| 44 | + Dany = -1, | |
| 45 | + Nmedia = 16, | |
| 46 | + Nini = 10, | |
| 47 | +}; | |
| 48 | + | |
| 49 | +enum { /* mode */ | |
| 50 | + Mauto = 0x00, | |
| 51 | + Mlocal = 0x01, | |
| 52 | + Manual = 0x02, | |
| 53 | + NMode = 0x03, | |
| 54 | +}; | |
| 55 | + | |
| 56 | +typedef struct Medium Medium; | |
| 57 | +struct Medium { | |
| 58 | + Type* type; | |
| 59 | + int flag; | |
| 60 | + int dev; | |
| 61 | + char name[NAMELEN]; | |
| 62 | + Fs* inifs; | |
| 63 | + | |
| 64 | + Medium* next; | |
| 65 | +}; | |
| 66 | + | |
| 67 | +typedef struct Mode { | |
| 68 | + char* name; | |
| 69 | + int mode; | |
| 70 | +} Mode; | |
| 71 | + | |
| 72 | +static Medium media[Nmedia]; | |
| 73 | +static Medium *curmedium = media; | |
| 74 | + | |
| 75 | +static Mode modes[NMode+1] = { | |
| 76 | + [Mauto] { "auto", Mauto, }, | |
| 77 | + [Mlocal] { "local", Mlocal, }, | |
| 78 | + [Manual] { "manual", Manual, }, | |
| 79 | +}; | |
| 80 | + | |
| 81 | +char *defaultpartition = "new"; | |
| 82 | + | |
| 83 | +static Medium* | |
| 84 | +parse(char *line, char **file) | |
| 85 | +{ | |
| 86 | + char *p; | |
| 87 | + Type *tp; | |
| 88 | + Medium *mp; | |
| 89 | + | |
| 90 | + if(p = strchr(line, '!')) { | |
| 91 | + *p++ = 0; | |
| 92 | + *file = p; | |
| 93 | + } else | |
| 94 | + *file = ""; | |
| 95 | + | |
| 96 | + for(tp = types; tp->type != Tnil; tp++) | |
| 97 | + for(mp = tp->media; mp; mp = mp->next) | |
| 98 | + if(strcmp(mp->name, line) == 0) | |
| 99 | + return mp; | |
| 100 | + return nil; | |
| 101 | +} | |
| 102 | + | |
| 103 | +static int | |
| 104 | +boot(Medium *mp, char *file) | |
| 105 | +{ | |
| 106 | + static Boot b; | |
| 107 | + | |
| 108 | + memset(&b, 0, sizeof b); | |
| 109 | + b.state = INIT9LOAD; | |
| 110 | + | |
| 111 | +// sprint(BOOTLINE, "%s!%s", mp->name, file); | |
| 112 | + return (*mp->type->boot)(mp->dev, file, &b); | |
| 113 | +} | |
| 114 | + | |
| 115 | +static Medium* | |
| 116 | +allocm(Type *tp) | |
| 117 | +{ | |
| 118 | + Medium **l; | |
| 119 | + | |
| 120 | + if(curmedium >= &media[Nmedia]) | |
| 121 | + return 0; | |
| 122 | + | |
| 123 | + for(l = &tp->media; *l; l = &(*l)->next) | |
| 124 | + ; | |
| 125 | + *l = curmedium++; | |
| 126 | + return *l; | |
| 127 | +} | |
| 128 | + | |
| 129 | +char *parts[] = { "dos", "9fat", "fs", 0 }; | |
| 130 | + | |
| 131 | +Medium* | |
| 132 | +probe(int type, int flag, int dev) | |
| 133 | +{ | |
| 134 | + Type *tp; | |
| 135 | + int i; | |
| 136 | + Medium *mp; | |
| 137 | + | |
| 138 | + for(tp = types; tp->type != Tnil; tp++){ | |
| 139 | + if(type != Tany && type != tp->type) | |
| 140 | + continue; | |
| 141 | + | |
| 142 | + if(flag != Fnone){ | |
| 143 | + for(mp = tp->media; mp; mp = mp->next){ | |
| 144 | + if((flag & mp->flag) && (dev == Dany || dev == mp->dev)) | |
| 145 | + return mp; | |
| 146 | + } | |
| 147 | + } | |
| 148 | + | |
| 149 | + if((tp->flag & Fprobe) == 0){ | |
| 150 | + tp->flag |= Fprobe; | |
| 151 | + tp->mask = (*tp->init)(); | |
| 152 | + } | |
| 153 | + | |
| 154 | + for(i = 0; tp->mask; i++){ | |
| 155 | + if((tp->mask & (1<<i)) == 0) | |
| 156 | + continue; | |
| 157 | + tp->mask &= ~(1<<i); | |
| 158 | + | |
| 159 | + if((mp = allocm(tp)) == 0) | |
| 160 | + continue; | |
| 161 | + | |
| 162 | + mp->dev = i; | |
| 163 | + mp->flag = tp->flag; | |
| 164 | + mp->type = tp; | |
| 165 | + (*tp->initdev)(i, mp->name); | |
| 166 | + | |
| 167 | + if((flag & mp->flag) && (dev == Dany || dev == i)) | |
| 168 | + return mp; | |
| 169 | + } | |
| 170 | + } | |
| 171 | + | |
| 172 | + return 0; | |
| 173 | +} | |
| 174 | + | |
| 175 | +extern int loopconst; | |
| 176 | +void | |
| 177 | +main(void) | |
| 178 | +{ | |
| 179 | + Medium *mp; | |
| 180 | + int flag; | |
| 181 | + char def[2*NAMELEN], line[80], *p, *file; | |
| 182 | + Type *tp; | |
| 183 | + | |
| 184 | + i8042a20(); | |
| 185 | + memset(m, 0, sizeof(Mach)); | |
| 186 | + trapinit(); | |
| 187 | + clockinit(); | |
| 188 | + alarminit(); | |
| 189 | + spllo(); | |
| 190 | + | |
| 191 | + kbdinit(); | |
| 192 | + | |
| 193 | + if((ulong)&end > (KZERO|(640*1024))) | |
| 194 | + panic("i'm too big"); | |
| 195 | + | |
| 196 | + /* | |
| 197 | + * If there were any arguments, MS-DOS leaves a character | |
| 198 | + * count followed by the arguments in the runtime header. | |
| 199 | + * Step over the leading space. | |
| 200 | + */ | |
| 201 | + p = (char*)0x80080080; | |
| 202 | + if(p[0]){ | |
| 203 | + p[p[0]+1] = 0; | |
| 204 | + p += 2; | |
| 205 | + } | |
| 206 | + else | |
| 207 | + p = 0; | |
| 208 | + | |
| 209 | + /* | |
| 210 | + * Advance command line to first option, if any | |
| 211 | + */ | |
| 212 | + if(p) { | |
| 213 | + while(*p==' ' || *p=='\t') | |
| 214 | + p++; | |
| 215 | + if(*p == 0) | |
| 216 | + p = nil; | |
| 217 | + } | |
| 218 | + | |
| 219 | + /* | |
| 220 | + * Probe everything, to collect device names. | |
| 221 | + */ | |
| 222 | + probe(Tany, Fnone, Dany); | |
| 223 | + | |
| 224 | + if(p != 0) { | |
| 225 | + if((mp = parse(p, &file)) == nil) { | |
| 226 | + print("bad loadfile syntax: %s\n", p); | |
| 227 | + goto done; | |
| 228 | + } | |
| 229 | + boot(mp, file); | |
| 230 | + } | |
| 231 | + | |
| 232 | +done: | |
| 233 | + flag = 0; | |
| 234 | + for(tp = types; tp->type != Tnil; tp++){ | |
| 235 | + for(mp = tp->media; mp; mp = mp->next){ | |
| 236 | + if(flag == 0){ | |
| 237 | + flag = 1; | |
| 238 | + print("Load devices:"); | |
| 239 | + } | |
| 240 | + print(" %s", mp->name); | |
| 241 | + } | |
| 242 | + } | |
| 243 | + if(flag) | |
| 244 | + print("\n"); | |
| 245 | + | |
| 246 | + for(;;){ | |
| 247 | + if(getstr("load from", line, sizeof(line), nil, 0) >= 0) | |
| 248 | + if(mp = parse(line, &file)) | |
| 249 | + boot(mp, file); | |
| 250 | + def[0] = 0; | |
| 251 | + } | |
| 252 | +} | |
| 253 | + | |
| 254 | +int | |
| 255 | +getfields(char *lp, char **fields, int n, char sep) | |
| 256 | +{ | |
| 257 | + int i; | |
| 258 | + | |
| 259 | + for(i = 0; lp && *lp && i < n; i++){ | |
| 260 | + while(*lp == sep) | |
| 261 | + *lp++ = 0; | |
| 262 | + if(*lp == 0) | |
| 263 | + break; | |
| 264 | + fields[i] = lp; | |
| 265 | + while(*lp && *lp != sep){ | |
| 266 | + if(*lp == '\\' && *(lp+1) == '\n') | |
| 267 | + *lp++ = ' '; | |
| 268 | + lp++; | |
| 269 | + } | |
| 270 | + } | |
| 271 | + return i; | |
| 272 | +} | |
| 273 | + | |
| 274 | +int | |
| 275 | +cistrcmp(char *a, char *b) | |
| 276 | +{ | |
| 277 | + int ac, bc; | |
| 278 | + | |
| 279 | + for(;;){ | |
| 280 | + ac = *a++; | |
| 281 | + bc = *b++; | |
| 282 | + | |
| 283 | + if(ac >= 'A' && ac <= 'Z') | |
| 284 | + ac = 'a' + (ac - 'A'); | |
| 285 | + if(bc >= 'A' && bc <= 'Z') | |
| 286 | + bc = 'a' + (bc - 'A'); | |
| 287 | + ac -= bc; | |
| 288 | + if(ac) | |
| 289 | + return ac; | |
| 290 | + if(bc == 0) | |
| 291 | + break; | |
| 292 | + } | |
| 293 | + return 0; | |
| 294 | +} | |
| 295 | + | |
| 296 | +int | |
| 297 | +cistrncmp(char *a, char *b, int n) | |
| 298 | +{ | |
| 299 | + unsigned ac, bc; | |
| 300 | + | |
| 301 | + while(n > 0){ | |
| 302 | + ac = *a++; | |
| 303 | + bc = *b++; | |
| 304 | + n--; | |
| 305 | + | |
| 306 | + if(ac >= 'A' && ac <= 'Z') | |
| 307 | + ac = 'a' + (ac - 'A'); | |
| 308 | + if(bc >= 'A' && bc <= 'Z') | |
| 309 | + bc = 'a' + (bc - 'A'); | |
| 310 | + | |
| 311 | + ac -= bc; | |
| 312 | + if(ac) | |
| 313 | + return ac; | |
| 314 | + if(bc == 0) | |
| 315 | + break; | |
| 316 | + } | |
| 317 | + | |
| 318 | + return 0; | |
| 319 | +} | |
| 320 | + | |
| 321 | +void* | |
| 322 | +ialloc(ulong n, int align) | |
| 323 | +{ | |
| 324 | + | |
| 325 | + static ulong palloc; | |
| 326 | + ulong p; | |
| 327 | + int a; | |
| 328 | + | |
| 329 | + if(palloc == 0) | |
| 330 | + palloc = 3*1024*1024; | |
| 331 | + | |
| 332 | + p = palloc; | |
| 333 | + if(align <= 0) | |
| 334 | + align = 4; | |
| 335 | + if(a = n % align) | |
| 336 | + n += align - a; | |
| 337 | + if(a = p % align) | |
| 338 | + p += align - a; | |
| 339 | + | |
| 340 | + palloc = p+n; | |
| 341 | + | |
| 342 | + return memset((void*)(p|KZERO), 0, n); | |
| 343 | +} | |
| 344 | + | |
| 345 | +void* | |
| 346 | +xspanalloc(ulong size, int align, ulong span) | |
| 347 | +{ | |
| 348 | + ulong a, v; | |
| 349 | + | |
| 350 | + a = (ulong)ialloc(size+align+span, 0); | |
| 351 | + | |
| 352 | + if(span > 2) | |
| 353 | + v = (a + span) & ~(span-1); | |
| 354 | + else | |
| 355 | + v = a; | |
| 356 | + | |
| 357 | + if(align > 1) | |
| 358 | + v = (v + align) & ~(align-1); | |
| 359 | + | |
| 360 | + return (void*)v; | |
| 361 | +} | |
| 362 | + | |
| 363 | +static Block *allocbp; | |
| 364 | + | |
| 365 | +Block* | |
| 366 | +allocb(int size) | |
| 367 | +{ | |
| 368 | + Block *bp, **lbp; | |
| 369 | + ulong addr; | |
| 370 | + | |
| 371 | + lbp = &allocbp; | |
| 372 | + for(bp = *lbp; bp; bp = bp->next){ | |
| 373 | + if((bp->lim - bp->base) >= size){ | |
| 374 | + *lbp = bp->next; | |
| 375 | + break; | |
| 376 | + } | |
| 377 | + lbp = &bp->next; | |
| 378 | + } | |
| 379 | + if(bp == 0){ | |
| 380 | + bp = ialloc(sizeof(Block)+size+64, 0); | |
| 381 | + addr = (ulong)bp; | |
| 382 | + addr = ROUNDUP(addr + sizeof(Block), 8); | |
| 383 | + bp->base = (uchar*)addr; | |
| 384 | + bp->lim = ((uchar*)bp) + sizeof(Block)+size+64; | |
| 385 | + } | |
| 386 | + | |
| 387 | + if(bp->flag) | |
| 388 | + panic("allocb reuse\n"); | |
| 389 | + | |
| 390 | + bp->rp = bp->base; | |
| 391 | + bp->wp = bp->rp; | |
| 392 | + bp->next = 0; | |
| 393 | + bp->flag = 1; | |
| 394 | + | |
| 395 | + return bp; | |
| 396 | +} | |
| 397 | + | |
| 398 | +void | |
| 399 | +freeb(Block* bp) | |
| 400 | +{ | |
| 401 | + bp->next = allocbp; | |
| 402 | + allocbp = bp; | |
| 403 | + | |
| 404 | + bp->flag = 0; | |
| 405 | +} | |
| 406 | + | |
| 407 | +enum { | |
| 408 | + Paddr= 0x70, /* address port */ | |
| 409 | + Pdata= 0x71, /* data port */ | |
| 410 | +}; | |
| 411 | + | |
| 412 | +uchar | |
| 413 | +nvramread(int offset) | |
| 414 | +{ | |
| 415 | + outb(Paddr, offset); | |
| 416 | + return inb(Pdata); | |
| 417 | +} | |
| 418 | + | |
| 419 | +void (*etherdetach)(void); | |
| 420 | +void (*floppydetach)(void); | |
| 421 | +void (*sddetach)(void); | |
| 422 | + | |
| 423 | +void | |
| 424 | +warp9(ulong entry) | |
| 425 | +{ | |
| 426 | + if(etherdetach) | |
| 427 | + etherdetach(); | |
| 428 | + consdrain(); | |
| 429 | + (*(void(*)(void))(PADDR(entry)))(); | |
| 430 | +} | |
| 431 | + | |
| 432 | +char* | |
| 433 | +getconf(char*) | |
| 434 | +{ | |
| 435 | + return nil; | |
| 436 | +} | |
| 437 | + | |
| 438 | +void | |
| 439 | +addconf(char*, ...) | |
| 440 | +{ | |
| 441 | +} | |
| 442 | + | |
| 443 | +void | |
| 444 | +uartspecial(int, void(*)(int), int(*)(void), int) | |
| 445 | +{ | |
| 446 | +} | |
| 447 | + | |
| 448 | +void | |
| 449 | +uartputs(IOQ*, char*, int) | |
| 450 | +{ | |
| 451 | +} | |
| 452 | + | |
| 453 | +void | |
| 454 | +uartputc(int) | |
| 455 | +{} | |
| 456 | + | |
| 457 | +void | |
| 458 | +uartdrain(void) | |
| 459 | +{ | |
| 460 | +} | |
| @@ -0,0 +1,451 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +#include "../../../utils/libmach/elf.h" | |
| 9 | + | |
| 10 | +static uchar elfident[7] = { | |
| 11 | + '\177', 'E', 'L', 'F', '\1', '\1', '\1' | |
| 12 | +}; | |
| 13 | +static Ehdr ehdr, rehdr; | |
| 14 | +static Phdr *phdr; | |
| 15 | +static int curphdr; | |
| 16 | +static ulong curoff; | |
| 17 | +static ulong elftotal; | |
| 18 | +static long (*swal)(long); | |
| 19 | +static ushort (*swab)(ushort); | |
| 20 | + | |
| 21 | +/* | |
| 22 | + * big-endian short | |
| 23 | + */ | |
| 24 | +ushort | |
| 25 | +beswab(ushort s) | |
| 26 | +{ | |
| 27 | + uchar *p; | |
| 28 | + | |
| 29 | + p = (uchar*)&s; | |
| 30 | + return (p[0]<<8) | p[1]; | |
| 31 | +} | |
| 32 | + | |
| 33 | +/* | |
| 34 | + * big-endian long | |
| 35 | + */ | |
| 36 | +long | |
| 37 | +beswal(long l) | |
| 38 | +{ | |
| 39 | + uchar *p; | |
| 40 | + | |
| 41 | + p = (uchar*)&l; | |
| 42 | + return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; | |
| 43 | +} | |
| 44 | + | |
| 45 | +/* | |
| 46 | + * little-endian short | |
| 47 | + */ | |
| 48 | +ushort | |
| 49 | +leswab(ushort s) | |
| 50 | +{ | |
| 51 | + uchar *p; | |
| 52 | + | |
| 53 | + p = (uchar*)&s; | |
| 54 | + return (p[1]<<8) | p[0]; | |
| 55 | +} | |
| 56 | + | |
| 57 | +/* | |
| 58 | + * little-endian long | |
| 59 | + */ | |
| 60 | +long | |
| 61 | +leswal(long l) | |
| 62 | +{ | |
| 63 | + uchar *p; | |
| 64 | + | |
| 65 | + p = (uchar*)&l; | |
| 66 | + return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0]; | |
| 67 | +} | |
| 68 | + | |
| 69 | +/* | |
| 70 | + * Convert header to canonical form | |
| 71 | + */ | |
| 72 | +static void | |
| 73 | +hswal(long *lp, int n, long (*swap) (long)) | |
| 74 | +{ | |
| 75 | + while (n--) { | |
| 76 | + *lp = (*swap) (*lp); | |
| 77 | + lp++; | |
| 78 | + } | |
| 79 | +} | |
| 80 | + | |
| 81 | +static int | |
| 82 | +readehdr(Boot *b) | |
| 83 | +{ | |
| 84 | + int i; | |
| 85 | + | |
| 86 | + /* bitswap the header according to the DATA format */ | |
| 87 | + if(ehdr.ident[CLASS] != ELFCLASS32) { | |
| 88 | + print("bad ELF class - not 32 bit\n"); | |
| 89 | + return 0; | |
| 90 | + } | |
| 91 | + if(ehdr.ident[DATA] == ELFDATA2LSB) { | |
| 92 | + swab = leswab; | |
| 93 | + swal = leswal; | |
| 94 | + } else if(ehdr.ident[DATA] == ELFDATA2MSB) { | |
| 95 | + swab = beswab; | |
| 96 | + swal = beswal; | |
| 97 | + } else { | |
| 98 | + print("bad ELF encoding - not big or little endian\n"); | |
| 99 | + return 0; | |
| 100 | + } | |
| 101 | + memmove(&rehdr, &ehdr, sizeof(Ehdr)); | |
| 102 | + | |
| 103 | + ehdr.type = swab(ehdr.type); | |
| 104 | + ehdr.machine = swab(ehdr.machine); | |
| 105 | + ehdr.version = swal(ehdr.version); | |
| 106 | + ehdr.elfentry = swal(ehdr.elfentry); | |
| 107 | + ehdr.phoff = swal(ehdr.phoff); | |
| 108 | + ehdr.shoff = swal(ehdr.shoff); | |
| 109 | + ehdr.flags = swal(ehdr.flags); | |
| 110 | + ehdr.ehsize = swab(ehdr.ehsize); | |
| 111 | + ehdr.phentsize = swab(ehdr.phentsize); | |
| 112 | + ehdr.phnum = swab(ehdr.phnum); | |
| 113 | + ehdr.shentsize = swab(ehdr.shentsize); | |
| 114 | + ehdr.shnum = swab(ehdr.shnum); | |
| 115 | + ehdr.shstrndx = swab(ehdr.shstrndx); | |
| 116 | + if(ehdr.type != EXEC || ehdr.version != CURRENT) | |
| 117 | + return 0; | |
| 118 | + if(ehdr.phentsize != sizeof(Phdr)) | |
| 119 | + return 0; | |
| 120 | + | |
| 121 | + if(debug) | |
| 122 | + print("readehdr OK entry 0x%lux\n", ehdr.elfentry); | |
| 123 | + | |
| 124 | + curoff = sizeof(Ehdr); | |
| 125 | + i = ehdr.phoff+ehdr.phentsize*ehdr.phnum - curoff; | |
| 126 | + b->state = READPHDR; | |
| 127 | + b->bp = (char*)malloc(i); | |
| 128 | + b->wp = b->bp; | |
| 129 | + b->ep = b->wp + i; | |
| 130 | + phdr = (Phdr*)(b->bp + ehdr.phoff-sizeof(Ehdr)); | |
| 131 | + if(debug) | |
| 132 | + print("phdr..."); | |
| 133 | + | |
| 134 | + return 1; | |
| 135 | +} | |
| 136 | + | |
| 137 | +static int | |
| 138 | +nextphdr(Boot *b) | |
| 139 | +{ | |
| 140 | + Phdr *php; | |
| 141 | + ulong entry, offset; | |
| 142 | + char *paddr; | |
| 143 | + | |
| 144 | + if(debug) | |
| 145 | + print("readedata %d\n", curphdr); | |
| 146 | + | |
| 147 | + for(; curphdr < ehdr.phnum; curphdr++){ | |
| 148 | + php = phdr+curphdr; | |
| 149 | + if(php->type != LOAD) | |
| 150 | + continue; | |
| 151 | + offset = php->offset; | |
| 152 | + paddr = (char*)PADDR(php->paddr); | |
| 153 | + if(offset < curoff){ | |
| 154 | + /* | |
| 155 | + * Can't (be bothered to) rewind the | |
| 156 | + * input, it might be from tftp. If we | |
| 157 | + * did then we could boot FreeBSD kernels | |
| 158 | + * too maybe. | |
| 159 | + */ | |
| 160 | + return 0; | |
| 161 | + } | |
| 162 | + if(php->offset > curoff){ | |
| 163 | + b->state = READEPAD; | |
| 164 | + b->bp = (char*)malloc(offset - curoff); | |
| 165 | + b->wp = b->bp; | |
| 166 | + b->ep = b->wp + offset - curoff; | |
| 167 | + if(debug) | |
| 168 | + print("nextphdr %lud...\n", offset - curoff); | |
| 169 | + return 1; | |
| 170 | + } | |
| 171 | + b->state = READEDATA; | |
| 172 | + b->bp = paddr; | |
| 173 | + b->wp = b->bp; | |
| 174 | + b->ep = b->wp+php->filesz; | |
| 175 | + print("%ud+", php->filesz); | |
| 176 | + elftotal += php->filesz; | |
| 177 | + if(debug) | |
| 178 | + print("nextphdr %ud@0x%p\n", php->filesz, paddr); | |
| 179 | + | |
| 180 | + return 1; | |
| 181 | + } | |
| 182 | + | |
| 183 | + if(curphdr != 0){ | |
| 184 | + print("=%lud\n", elftotal); | |
| 185 | + b->state = TRYBOOT; | |
| 186 | + entry = ehdr.elfentry & ~0xF0000000; | |
| 187 | + PLLONG(b->exec.entry, entry); | |
| 188 | + return 1; | |
| 189 | + } | |
| 190 | + | |
| 191 | + return 0; | |
| 192 | +} | |
| 193 | + | |
| 194 | +static int | |
| 195 | +readepad(Boot *b) | |
| 196 | +{ | |
| 197 | + Phdr *php; | |
| 198 | + | |
| 199 | + php = phdr+curphdr; | |
| 200 | + if(debug) | |
| 201 | + print("readepad %d\n", curphdr); | |
| 202 | + curoff = php->offset; | |
| 203 | + | |
| 204 | + return nextphdr(b); | |
| 205 | +} | |
| 206 | + | |
| 207 | +static int | |
| 208 | +readedata(Boot *b) | |
| 209 | +{ | |
| 210 | + Phdr *php; | |
| 211 | + | |
| 212 | + php = phdr+curphdr; | |
| 213 | + if(debug) | |
| 214 | + print("readedata %d\n", curphdr); | |
| 215 | + if(php->filesz < php->memsz){ | |
| 216 | + print("%lud", php->memsz-php->filesz); | |
| 217 | + elftotal += php->memsz-php->filesz; | |
| 218 | + memset((char*)(PADDR(php->paddr)+php->filesz), 0, php->memsz-php->filesz); | |
| 219 | + } | |
| 220 | + curoff = php->offset+php->filesz; | |
| 221 | + curphdr++; | |
| 222 | + | |
| 223 | + return nextphdr(b); | |
| 224 | +} | |
| 225 | + | |
| 226 | +static int | |
| 227 | +readphdr(Boot *b) | |
| 228 | +{ | |
| 229 | + Phdr *php; | |
| 230 | + | |
| 231 | + php = phdr; | |
| 232 | + hswal((long*)php, ehdr.phentsize*ehdr.phnum/sizeof(long), swal); | |
| 233 | + if(debug) | |
| 234 | + print("phdr curoff %lud vaddr 0x%lux paddr 0x%lux\n", | |
| 235 | + curoff, php->vaddr, php->paddr); | |
| 236 | + | |
| 237 | + curoff = ehdr.phoff+ehdr.phentsize*ehdr.phnum; | |
| 238 | + curphdr = 0; | |
| 239 | + | |
| 240 | + return nextphdr(b); | |
| 241 | +} | |
| 242 | + | |
| 243 | +static int | |
| 244 | +addbytes(char **dbuf, char *edbuf, char **sbuf, char *esbuf) | |
| 245 | +{ | |
| 246 | + int n; | |
| 247 | + | |
| 248 | + n = edbuf - *dbuf; | |
| 249 | + if(n <= 0) | |
| 250 | + return 0; | |
| 251 | + if(n > esbuf - *sbuf) | |
| 252 | + n = esbuf - *sbuf; | |
| 253 | + if(n <= 0) | |
| 254 | + return -1; | |
| 255 | + | |
| 256 | + memmove(*dbuf, *sbuf, n); | |
| 257 | + *sbuf += n; | |
| 258 | + *dbuf += n; | |
| 259 | + return edbuf - *dbuf; | |
| 260 | +} | |
| 261 | + | |
| 262 | +int | |
| 263 | +bootpass(Boot *b, void *vbuf, int nbuf) | |
| 264 | +{ | |
| 265 | + char *buf, *ebuf; | |
| 266 | + Exec *ep; | |
| 267 | + ulong entry, data, text, bss; | |
| 268 | + | |
| 269 | + if(b->state == FAILED) | |
| 270 | + return FAIL; | |
| 271 | + | |
| 272 | + if(nbuf == 0) | |
| 273 | + goto Endofinput; | |
| 274 | + | |
| 275 | + buf = vbuf; | |
| 276 | + ebuf = buf+nbuf; | |
| 277 | + while(addbytes(&b->wp, b->ep, &buf, ebuf) == 0) { | |
| 278 | + switch(b->state) { | |
| 279 | + case INITKERNEL: | |
| 280 | + b->state = READEXEC; | |
| 281 | + b->bp = (char*)&b->exec; | |
| 282 | + b->wp = b->bp; | |
| 283 | + b->ep = b->bp+sizeof(Exec); | |
| 284 | + break; | |
| 285 | + case READEXEC: | |
| 286 | + ep = &b->exec; | |
| 287 | + if(GLLONG(ep->magic) == I_MAGIC) { | |
| 288 | + b->state = READ9TEXT; | |
| 289 | + b->bp = (char*)PADDR(GLLONG(ep->entry)); | |
| 290 | + b->wp = b->bp; | |
| 291 | + b->ep = b->wp+GLLONG(ep->text); | |
| 292 | + print("%lud", GLLONG(ep->text)); | |
| 293 | + break; | |
| 294 | + } | |
| 295 | + | |
| 296 | + /* check for gzipped kernel */ | |
| 297 | + if(b->bp[0] == 0x1F && (uchar)b->bp[1] == 0x8B && b->bp[2] == 0x08) { | |
| 298 | + b->state = READGZIP; | |
| 299 | + b->bp = (char*)malloc(1440*1024); | |
| 300 | + b->wp = b->bp; | |
| 301 | + b->ep = b->wp + 1440*1024; | |
| 302 | + memmove(b->bp, &b->exec, sizeof(Exec)); | |
| 303 | + b->wp += sizeof(Exec); | |
| 304 | + print("gz..."); | |
| 305 | + break; | |
| 306 | + } | |
| 307 | + | |
| 308 | + /* | |
| 309 | + * Check for ELF. | |
| 310 | + */ | |
| 311 | + if(memcmp(b->bp, elfident, 4) == 0){ | |
| 312 | + b->state = READEHDR; | |
| 313 | + b->bp = (char*)&ehdr; | |
| 314 | + b->wp = b->bp; | |
| 315 | + b->ep = b->wp + sizeof(Ehdr); | |
| 316 | + memmove(b->bp, &b->exec, sizeof(Exec)); | |
| 317 | + b->wp += sizeof(Exec); | |
| 318 | + print("elf..."); | |
| 319 | + break; | |
| 320 | + } | |
| 321 | + | |
| 322 | + print("bad kernel format\n"); | |
| 323 | + b->state = FAILED; | |
| 324 | + return FAIL; | |
| 325 | + | |
| 326 | + case READ9TEXT: | |
| 327 | + ep = &b->exec; | |
| 328 | + b->state = READ9DATA; | |
| 329 | + b->bp = (char*)PGROUND(PADDR(GLLONG(ep->entry))+GLLONG(ep->text)); | |
| 330 | + b->wp = b->bp; | |
| 331 | + b->ep = b->wp + GLLONG(ep->data); | |
| 332 | + print("+%ld", GLLONG(ep->data)); | |
| 333 | + break; | |
| 334 | + | |
| 335 | + case READ9DATA: | |
| 336 | + ep = &b->exec; | |
| 337 | + bss = GLLONG(ep->bss); | |
| 338 | + print("+%ld=%ld\n", | |
| 339 | + bss, GLLONG(ep->text)+GLLONG(ep->data)+bss); | |
| 340 | + b->state = TRYBOOT; | |
| 341 | + return ENOUGH; | |
| 342 | + | |
| 343 | + case READEHDR: | |
| 344 | + if(!readehdr(b)){ | |
| 345 | + print("readehdr failed\n"); | |
| 346 | + b->state = FAILED; | |
| 347 | + return FAIL; | |
| 348 | + } | |
| 349 | + break; | |
| 350 | + | |
| 351 | + case READPHDR: | |
| 352 | + if(!readphdr(b)){ | |
| 353 | + b->state = FAILED; | |
| 354 | + return FAIL; | |
| 355 | + } | |
| 356 | + break; | |
| 357 | + | |
| 358 | + case READEPAD: | |
| 359 | + if(!readepad(b)){ | |
| 360 | + b->state = FAILED; | |
| 361 | + return FAIL; | |
| 362 | + } | |
| 363 | + break; | |
| 364 | + | |
| 365 | + case READEDATA: | |
| 366 | + if(!readedata(b)){ | |
| 367 | + b->state = FAILED; | |
| 368 | + return FAIL; | |
| 369 | + } | |
| 370 | + if(b->state == TRYBOOT) | |
| 371 | + return ENOUGH; | |
| 372 | + break; | |
| 373 | + | |
| 374 | + case TRYBOOT: | |
| 375 | + case READGZIP: | |
| 376 | + return ENOUGH; | |
| 377 | + | |
| 378 | + case READ9LOAD: | |
| 379 | + case INIT9LOAD: | |
| 380 | + panic("9load"); | |
| 381 | + | |
| 382 | + default: | |
| 383 | + panic("bootstate"); | |
| 384 | + } | |
| 385 | + } | |
| 386 | + return MORE; | |
| 387 | + | |
| 388 | + | |
| 389 | +Endofinput: | |
| 390 | + /* end of input */ | |
| 391 | + switch(b->state) { | |
| 392 | + case INITKERNEL: | |
| 393 | + case READEXEC: | |
| 394 | + case READ9TEXT: | |
| 395 | + case READ9DATA: | |
| 396 | + case READEHDR: | |
| 397 | + case READPHDR: | |
| 398 | + case READEPAD: | |
| 399 | + case READEDATA: | |
| 400 | + print("premature EOF\n"); | |
| 401 | + b->state = FAILED; | |
| 402 | + return FAIL; | |
| 403 | + | |
| 404 | + case TRYBOOT: | |
| 405 | + entry = GLLONG(b->exec.entry); | |
| 406 | + print("entry: 0x%lux\n", entry); | |
| 407 | + warp9(PADDR(entry)); | |
| 408 | + b->state = FAILED; | |
| 409 | + return FAIL; | |
| 410 | + | |
| 411 | + case READGZIP: | |
| 412 | + ep = &b->exec; | |
| 413 | + if(b->bp[0] != 0x1F || (uchar)b->bp[1] != 0x8B || b->bp[2] != 0x08) | |
| 414 | + print("lost magic\n"); | |
| 415 | + | |
| 416 | + print("%ld => ", b->wp - b->bp); | |
| 417 | + if(gunzip((uchar*)ep, sizeof(*ep), (uchar*)b->bp, b->wp - b->bp) < sizeof(*ep)) { | |
| 418 | + print("badly compressed kernel\n"); | |
| 419 | + return FAIL; | |
| 420 | + } | |
| 421 | + | |
| 422 | + entry = GLLONG(ep->entry); | |
| 423 | + text = GLLONG(ep->text); | |
| 424 | + data = GLLONG(ep->data); | |
| 425 | + bss = GLLONG(ep->bss); | |
| 426 | + print("%lud+%lud+%lud=%lud\n", text, data, bss, text+data+bss); | |
| 427 | + | |
| 428 | + if(gunzip((uchar*)PADDR(entry)-sizeof(Exec), sizeof(Exec)+text+data, | |
| 429 | + (uchar*)b->bp, b->wp-b->bp) < sizeof(Exec)+text+data) { | |
| 430 | + print("error uncompressing kernel\n"); | |
| 431 | + return FAIL; | |
| 432 | + } | |
| 433 | + | |
| 434 | + /* relocate data to start at page boundary */ | |
| 435 | + memmove((void*)PGROUND(PADDR(entry+text)), (void*)(PADDR(entry+text)), data); | |
| 436 | + | |
| 437 | + print("entry: %lux\n", entry); | |
| 438 | + warp9(PADDR(entry)); | |
| 439 | + b->state = FAILED; | |
| 440 | + return FAIL; | |
| 441 | + | |
| 442 | + case INIT9LOAD: | |
| 443 | + case READ9LOAD: | |
| 444 | + panic("end 9load"); | |
| 445 | + | |
| 446 | + default: | |
| 447 | + panic("bootdone"); | |
| 448 | + } | |
| 449 | + b->state = FAILED; | |
| 450 | + return FAIL; | |
| 451 | +} | |
| @@ -0,0 +1,108 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +static int | |
| 9 | +addbytes(char **dbuf, char *edbuf, char **sbuf, char *esbuf) | |
| 10 | +{ | |
| 11 | + int n; | |
| 12 | + | |
| 13 | + n = edbuf - *dbuf; | |
| 14 | + if(n <= 0) | |
| 15 | + return 0; | |
| 16 | + if(n > esbuf - *sbuf) | |
| 17 | + n = esbuf - *sbuf; | |
| 18 | + if(n <= 0) | |
| 19 | + return -1; | |
| 20 | + | |
| 21 | + memmove(*dbuf, *sbuf, n); | |
| 22 | + *sbuf += n; | |
| 23 | + *dbuf += n; | |
| 24 | + return edbuf - *dbuf; | |
| 25 | +} | |
| 26 | + | |
| 27 | +extern void origin(void); | |
| 28 | + | |
| 29 | +int | |
| 30 | +bootpass(Boot *b, void *vbuf, int nbuf) | |
| 31 | +{ | |
| 32 | + char *buf, *ebuf, *p, *q; | |
| 33 | + ulong size; | |
| 34 | + | |
| 35 | + if(b->state == FAILED) | |
| 36 | + return FAIL; | |
| 37 | + | |
| 38 | + if(nbuf == 0) | |
| 39 | + goto Endofinput; | |
| 40 | + | |
| 41 | + buf = vbuf; | |
| 42 | + ebuf = buf+nbuf; | |
| 43 | + while(addbytes(&b->wp, b->ep, &buf, ebuf) == 0) { | |
| 44 | + switch(b->state) { | |
| 45 | + case INIT9LOAD: | |
| 46 | + b->state = READ9LOAD; | |
| 47 | + b->bp = (char*)0x10000; | |
| 48 | + b->wp = b->bp; | |
| 49 | + b->ep = b->bp + 256*1024; | |
| 50 | + break; | |
| 51 | + | |
| 52 | + case READ9LOAD: | |
| 53 | + return ENOUGH; | |
| 54 | + | |
| 55 | + default: | |
| 56 | + panic("bootstate"); | |
| 57 | + } | |
| 58 | + } | |
| 59 | + return MORE; | |
| 60 | + | |
| 61 | + | |
| 62 | +Endofinput: | |
| 63 | + /* end of input */ | |
| 64 | + print("\n"); | |
| 65 | + switch(b->state) { | |
| 66 | + case INIT9LOAD: | |
| 67 | + print("premature EOF\n"); | |
| 68 | + b->state = FAILED; | |
| 69 | + return FAIL; | |
| 70 | + | |
| 71 | + case READ9LOAD: | |
| 72 | + size = b->wp - b->bp; | |
| 73 | + if(memcmp(b->bp, origin, 16) != 0) { | |
| 74 | + print("beginning of file does not look right\n"); | |
| 75 | + b->state = FAILED; | |
| 76 | + return FAIL; | |
| 77 | + } | |
| 78 | + if(size < 32*1024 || size > 256*1024) { | |
| 79 | + print("got %lud byte loader; not likely\n", size); | |
| 80 | + b->state = FAILED; | |
| 81 | + return FAIL; | |
| 82 | + } | |
| 83 | + | |
| 84 | + p = b->bp; | |
| 85 | + q = b->wp; | |
| 86 | + if(q - p > 10000) /* don't search much past l.s */ | |
| 87 | + q = p+10000; | |
| 88 | + | |
| 89 | + /* | |
| 90 | + * The string `JUMP' appears right before | |
| 91 | + * tokzero, which is where we want to jump. | |
| 92 | + */ | |
| 93 | + for(; p<q; p++) { | |
| 94 | + if(strncmp(p, "JUMP", 4) == 0) { | |
| 95 | + p += 4; | |
| 96 | + warp9((ulong)p); | |
| 97 | + } | |
| 98 | + } | |
| 99 | + print("could not find jump destination\n"); | |
| 100 | + b->state = FAILED; | |
| 101 | + return FAIL; | |
| 102 | + | |
| 103 | + default: | |
| 104 | + panic("bootdone"); | |
| 105 | + } | |
| 106 | + b->state = FAILED; | |
| 107 | + return FAIL; | |
| 108 | +} | |
| @@ -0,0 +1,652 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +#include "ip.h" | |
| 9 | + | |
| 10 | +uchar broadcast[Eaddrlen] = { | |
| 11 | + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 12 | +}; | |
| 13 | + | |
| 14 | +static ushort tftpport = 5000; | |
| 15 | +static int Id = 1; | |
| 16 | +static Netaddr myaddr; | |
| 17 | +static Netaddr server; | |
| 18 | + | |
| 19 | +typedef struct { | |
| 20 | + uchar header[4]; | |
| 21 | + uchar data[Segsize]; | |
| 22 | +} Tftp; | |
| 23 | +static Tftp tftpb; | |
| 24 | + | |
| 25 | +static void | |
| 26 | +hnputs(uchar *ptr, ushort val) | |
| 27 | +{ | |
| 28 | + ptr[0] = val>>8; | |
| 29 | + ptr[1] = val; | |
| 30 | +} | |
| 31 | + | |
| 32 | +static void | |
| 33 | +hnputl(uchar *ptr, ulong val) | |
| 34 | +{ | |
| 35 | + ptr[0] = val>>24; | |
| 36 | + ptr[1] = val>>16; | |
| 37 | + ptr[2] = val>>8; | |
| 38 | + ptr[3] = val; | |
| 39 | +} | |
| 40 | + | |
| 41 | +static ulong | |
| 42 | +nhgetl(uchar *ptr) | |
| 43 | +{ | |
| 44 | + return ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]); | |
| 45 | +} | |
| 46 | + | |
| 47 | +static ushort | |
| 48 | +nhgets(uchar *ptr) | |
| 49 | +{ | |
| 50 | + return ((ptr[0]<<8) | ptr[1]); | |
| 51 | +} | |
| 52 | + | |
| 53 | +static short endian = 1; | |
| 54 | +static char* aendian = (char*)&endian; | |
| 55 | +#define LITTLE *aendian | |
| 56 | + | |
| 57 | +static ushort | |
| 58 | +ptcl_csum(void *a, int len) | |
| 59 | +{ | |
| 60 | + uchar *addr; | |
| 61 | + ulong t1, t2; | |
| 62 | + ulong losum, hisum, mdsum, x; | |
| 63 | + | |
| 64 | + addr = a; | |
| 65 | + losum = 0; | |
| 66 | + hisum = 0; | |
| 67 | + mdsum = 0; | |
| 68 | + | |
| 69 | + x = 0; | |
| 70 | + if((ulong)addr & 1) { | |
| 71 | + if(len) { | |
| 72 | + hisum += addr[0]; | |
| 73 | + len--; | |
| 74 | + addr++; | |
| 75 | + } | |
| 76 | + x = 1; | |
| 77 | + } | |
| 78 | + while(len >= 16) { | |
| 79 | + t1 = *(ushort*)(addr+0); | |
| 80 | + t2 = *(ushort*)(addr+2); mdsum += t1; | |
| 81 | + t1 = *(ushort*)(addr+4); mdsum += t2; | |
| 82 | + t2 = *(ushort*)(addr+6); mdsum += t1; | |
| 83 | + t1 = *(ushort*)(addr+8); mdsum += t2; | |
| 84 | + t2 = *(ushort*)(addr+10); mdsum += t1; | |
| 85 | + t1 = *(ushort*)(addr+12); mdsum += t2; | |
| 86 | + t2 = *(ushort*)(addr+14); mdsum += t1; | |
| 87 | + mdsum += t2; | |
| 88 | + len -= 16; | |
| 89 | + addr += 16; | |
| 90 | + } | |
| 91 | + while(len >= 2) { | |
| 92 | + mdsum += *(ushort*)addr; | |
| 93 | + len -= 2; | |
| 94 | + addr += 2; | |
| 95 | + } | |
| 96 | + if(x) { | |
| 97 | + if(len) | |
| 98 | + losum += addr[0]; | |
| 99 | + if(LITTLE) | |
| 100 | + losum += mdsum; | |
| 101 | + else | |
| 102 | + hisum += mdsum; | |
| 103 | + } else { | |
| 104 | + if(len) | |
| 105 | + hisum += addr[0]; | |
| 106 | + if(LITTLE) | |
| 107 | + hisum += mdsum; | |
| 108 | + else | |
| 109 | + losum += mdsum; | |
| 110 | + } | |
| 111 | + | |
| 112 | + losum += hisum >> 8; | |
| 113 | + losum += (hisum & 0xff) << 8; | |
| 114 | + while(hisum = losum>>16) | |
| 115 | + losum = hisum + (losum & 0xffff); | |
| 116 | + | |
| 117 | + return ~losum; | |
| 118 | +} | |
| 119 | + | |
| 120 | +static ushort | |
| 121 | +ip_csum(uchar *addr) | |
| 122 | +{ | |
| 123 | + int len; | |
| 124 | + ulong sum = 0; | |
| 125 | + | |
| 126 | + len = (addr[0]&0xf)<<2; | |
| 127 | + | |
| 128 | + while(len > 0) { | |
| 129 | + sum += addr[0]<<8 | addr[1] ; | |
| 130 | + len -= 2; | |
| 131 | + addr += 2; | |
| 132 | + } | |
| 133 | + | |
| 134 | + sum = (sum & 0xffff) + (sum >> 16); | |
| 135 | + sum = (sum & 0xffff) + (sum >> 16); | |
| 136 | + return (sum^0xffff); | |
| 137 | +} | |
| 138 | + | |
| 139 | +enum { | |
| 140 | + /* this is only true of IPv4, but we're not doing v6 yet */ | |
| 141 | + Min_udp_payload = ETHERMINTU - ETHERHDRSIZE - UDP_HDRSIZE, | |
| 142 | +}; | |
| 143 | + | |
| 144 | +static void | |
| 145 | +udpsend(int ctlrno, Netaddr *a, void *data, int dlen) | |
| 146 | +{ | |
| 147 | + char payload[ETHERMAXTU]; | |
| 148 | + Udphdr *uh; | |
| 149 | + Etherhdr *ip; | |
| 150 | + Etherpkt pkt; | |
| 151 | + int len, ptcllen; | |
| 152 | + | |
| 153 | + /* | |
| 154 | + * if packet is too short, make it longer rather than relying | |
| 155 | + * on ethernet interface or lower layers to pad it. | |
| 156 | + */ | |
| 157 | + if (dlen < Min_udp_payload) { | |
| 158 | + memmove(payload, data, dlen); | |
| 159 | + data = payload; | |
| 160 | + dlen = Min_udp_payload; | |
| 161 | + } | |
| 162 | + | |
| 163 | + uh = (Udphdr*)&pkt; | |
| 164 | + | |
| 165 | + memset(uh, 0, sizeof(Etherpkt)); | |
| 166 | + memmove(uh->udpcksum+sizeof(uh->udpcksum), data, dlen); | |
| 167 | + | |
| 168 | + /* | |
| 169 | + * UDP portion | |
| 170 | + */ | |
| 171 | + ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE); | |
| 172 | + uh->ttl = 0; | |
| 173 | + uh->udpproto = IP_UDPPROTO; | |
| 174 | + uh->frag[0] = 0; | |
| 175 | + uh->frag[1] = 0; | |
| 176 | + hnputs(uh->udpplen, ptcllen); | |
| 177 | + hnputl(uh->udpsrc, myaddr.ip); | |
| 178 | + hnputs(uh->udpsport, myaddr.port); | |
| 179 | + hnputl(uh->udpdst, a->ip); | |
| 180 | + hnputs(uh->udpdport, a->port); | |
| 181 | + hnputs(uh->udplen, ptcllen); | |
| 182 | + uh->udpcksum[0] = 0; | |
| 183 | + uh->udpcksum[1] = 0; | |
| 184 | + dlen = (dlen+1)&~1; | |
| 185 | + hnputs(uh->udpcksum, ptcl_csum(&uh->ttl, dlen+UDP_HDRSIZE)); | |
| 186 | + | |
| 187 | + /* | |
| 188 | + * IP portion | |
| 189 | + */ | |
| 190 | + ip = (Etherhdr*)&pkt; | |
| 191 | + len = UDP_EHSIZE+UDP_HDRSIZE+dlen; /* non-descriptive names */ | |
| 192 | + ip->vihl = IP_VER|IP_HLEN; | |
| 193 | + ip->tos = 0; | |
| 194 | + ip->ttl = 255; | |
| 195 | + hnputs(ip->length, len-ETHER_HDR); | |
| 196 | + hnputs(ip->id, Id++); | |
| 197 | + ip->frag[0] = 0; | |
| 198 | + ip->frag[1] = 0; | |
| 199 | + ip->cksum[0] = 0; | |
| 200 | + ip->cksum[1] = 0; | |
| 201 | + hnputs(ip->cksum, ip_csum(&ip->vihl)); | |
| 202 | + | |
| 203 | + /* | |
| 204 | + * Ethernet MAC portion | |
| 205 | + */ | |
| 206 | + hnputs(ip->type, ET_IP); | |
| 207 | + memmove(ip->d, a->ea, sizeof(ip->d)); | |
| 208 | + | |
| 209 | +if(debug) { | |
| 210 | + print("udpsend "); | |
| 211 | +} | |
| 212 | + ethertxpkt(ctlrno, &pkt, len, Timeout); | |
| 213 | +} | |
| 214 | + | |
| 215 | +static void | |
| 216 | +nak(int ctlrno, Netaddr *a, int code, char *msg, int report) | |
| 217 | +{ | |
| 218 | + int n; | |
| 219 | + char buf[128]; | |
| 220 | + | |
| 221 | + buf[0] = 0; | |
| 222 | + buf[1] = Tftp_ERROR; | |
| 223 | + buf[2] = 0; | |
| 224 | + buf[3] = code; | |
| 225 | + strcpy(buf+4, msg); | |
| 226 | + n = strlen(msg) + 4 + 1; | |
| 227 | + udpsend(ctlrno, a, buf, n); | |
| 228 | + if(report) | |
| 229 | + print("\ntftp: error(%d): %s\n", code, msg); | |
| 230 | +} | |
| 231 | + | |
| 232 | +static int | |
| 233 | +udprecv(int ctlrno, Netaddr *a, void *data, int dlen) | |
| 234 | +{ | |
| 235 | + int n, len; | |
| 236 | + ushort csm; | |
| 237 | + Udphdr *h; | |
| 238 | + ulong addr, timo; | |
| 239 | + Etherpkt pkt; | |
| 240 | + static int rxactive; | |
| 241 | + | |
| 242 | + if(rxactive == 0) | |
| 243 | + timo = 1000; | |
| 244 | + else | |
| 245 | + timo = Timeout; | |
| 246 | + timo += TK2MS(m->ticks); | |
| 247 | + while(timo > TK2MS(m->ticks)){ | |
| 248 | + n = etherrxpkt(ctlrno, &pkt, timo-TK2MS(m->ticks)); | |
| 249 | + if(n <= 0) | |
| 250 | + continue; | |
| 251 | + | |
| 252 | + h = (Udphdr*)&pkt; | |
| 253 | + if(debug) | |
| 254 | + print("udprecv %E to %E...\n", h->s, h->d); | |
| 255 | + | |
| 256 | + if(nhgets(h->type) != ET_IP) { | |
| 257 | + if(debug) | |
| 258 | + print("not ip..."); | |
| 259 | + continue; | |
| 260 | + } | |
| 261 | + | |
| 262 | + if(ip_csum(&h->vihl)) { | |
| 263 | + print("ip chksum error\n"); | |
| 264 | + continue; | |
| 265 | + } | |
| 266 | + if(h->vihl != (IP_VER|IP_HLEN)) { | |
| 267 | + print("ip bad vers/hlen\n"); | |
| 268 | + continue; | |
| 269 | + } | |
| 270 | + | |
| 271 | + if(h->udpproto != IP_UDPPROTO) { | |
| 272 | + if(debug) | |
| 273 | + print("not udp (%d)...", h->udpproto); | |
| 274 | + continue; | |
| 275 | + } | |
| 276 | + | |
| 277 | + if(debug) | |
| 278 | + print("okay udp..."); | |
| 279 | + | |
| 280 | + h->ttl = 0; | |
| 281 | + len = nhgets(h->udplen); | |
| 282 | + hnputs(h->udpplen, len); | |
| 283 | + | |
| 284 | + if(nhgets(h->udpcksum)) { | |
| 285 | + csm = ptcl_csum(&h->ttl, len+UDP_PHDRSIZE); | |
| 286 | + if(csm != 0) { | |
| 287 | + print("udp chksum error csum #%4ux len %d\n", | |
| 288 | + csm, n); | |
| 289 | + break; | |
| 290 | + } | |
| 291 | + } | |
| 292 | + | |
| 293 | + if(a->port != 0 && nhgets(h->udpsport) != a->port) { | |
| 294 | + if(debug) | |
| 295 | + print("udpport %ux %ux\n", | |
| 296 | + nhgets(h->udpsport), a->port); | |
| 297 | + continue; | |
| 298 | + } | |
| 299 | + | |
| 300 | + addr = nhgetl(h->udpsrc); | |
| 301 | + if(a->ip != Bcastip && addr != a->ip) { | |
| 302 | + if(debug) | |
| 303 | + print("bad ip\n"); | |
| 304 | + continue; | |
| 305 | + } | |
| 306 | + | |
| 307 | + len -= UDP_HDRSIZE-UDP_PHDRSIZE; | |
| 308 | + if(len > dlen) { | |
| 309 | + print("udp: packet too big: %d > %d; from addr %E\n", | |
| 310 | + len, dlen, h->udpsrc); | |
| 311 | + continue; | |
| 312 | + } | |
| 313 | + | |
| 314 | + memmove(data, h->udpcksum+sizeof(h->udpcksum), len); | |
| 315 | + a->ip = addr; | |
| 316 | + a->port = nhgets(h->udpsport); | |
| 317 | + memmove(a->ea, pkt.s, sizeof(a->ea)); | |
| 318 | + | |
| 319 | + rxactive = 1; | |
| 320 | + return len; | |
| 321 | + } | |
| 322 | + | |
| 323 | + return 0; | |
| 324 | +} | |
| 325 | + | |
| 326 | +static int tftpblockno; | |
| 327 | + | |
| 328 | +/* | |
| 329 | + * format of a request packet, from the RFC: | |
| 330 | + * | |
| 331 | + 2 bytes string 1 byte string 1 byte | |
| 332 | + ------------------------------------------------ | |
| 333 | + | Opcode | Filename | 0 | Mode | 0 | | |
| 334 | + ------------------------------------------------ | |
| 335 | + */ | |
| 336 | +static int | |
| 337 | +tftpopen(int ctlrno, Netaddr *a, char *name, Tftp *tftp) | |
| 338 | +{ | |
| 339 | + int i, len, rlen, oport; | |
| 340 | + char buf[Segsize+2]; | |
| 341 | + | |
| 342 | + buf[0] = 0; | |
| 343 | + buf[1] = Tftp_READ; | |
| 344 | + len = 2 + sprint(buf+2, "%s", name) + 1; | |
| 345 | + len += sprint(buf+len, "octet") + 1; | |
| 346 | + | |
| 347 | + oport = a->port; | |
| 348 | + for(i = 0; i < 5; i++){ | |
| 349 | + a->port = oport; | |
| 350 | + udpsend(ctlrno, a, buf, len); | |
| 351 | + a->port = 0; | |
| 352 | + if((rlen = udprecv(ctlrno, a, tftp, sizeof(Tftp))) < sizeof(tftp->header)) | |
| 353 | + continue; | |
| 354 | + | |
| 355 | + switch((tftp->header[0]<<8)|tftp->header[1]){ | |
| 356 | + | |
| 357 | + case Tftp_ERROR: | |
| 358 | + print("tftpopen: error (%d): %s\n", | |
| 359 | + (tftp->header[2]<<8)|tftp->header[3], (char*)tftp->data); | |
| 360 | + return -1; | |
| 361 | + | |
| 362 | + case Tftp_DATA: | |
| 363 | + tftpblockno = 1; | |
| 364 | + len = (tftp->header[2]<<8)|tftp->header[3]; | |
| 365 | + if(len != tftpblockno){ | |
| 366 | + print("tftpopen: block error: %d\n", len); | |
| 367 | + nak(ctlrno, a, 1, "block error", 0); | |
| 368 | + return -1; | |
| 369 | + } | |
| 370 | + rlen -= sizeof(tftp->header); | |
| 371 | + if(rlen < Segsize){ | |
| 372 | + /* ACK now, in case we don't later */ | |
| 373 | + buf[0] = 0; | |
| 374 | + buf[1] = Tftp_ACK; | |
| 375 | + buf[2] = tftpblockno>>8; | |
| 376 | + buf[3] = tftpblockno; | |
| 377 | + udpsend(ctlrno, a, buf, sizeof(tftp->header)); | |
| 378 | + } | |
| 379 | + return rlen; | |
| 380 | + } | |
| 381 | + } | |
| 382 | + | |
| 383 | + print("tftpopen: failed to connect to server\n"); | |
| 384 | + return -1; | |
| 385 | +} | |
| 386 | + | |
| 387 | +static int | |
| 388 | +tftpread(int ctlrno, Netaddr *a, Tftp *tftp, int dlen) | |
| 389 | +{ | |
| 390 | + uchar buf[4]; | |
| 391 | + int try, blockno, len; | |
| 392 | + | |
| 393 | + dlen += sizeof(tftp->header); | |
| 394 | + | |
| 395 | + for(try = 0; try < 10; try++) { | |
| 396 | + buf[0] = 0; | |
| 397 | + buf[1] = Tftp_ACK; | |
| 398 | + buf[2] = tftpblockno>>8; | |
| 399 | + buf[3] = tftpblockno; | |
| 400 | + | |
| 401 | + udpsend(ctlrno, a, buf, sizeof(buf)); | |
| 402 | + len = udprecv(ctlrno, a, tftp, dlen); | |
| 403 | + if(len <= sizeof(tftp->header)){ | |
| 404 | + if(debug) | |
| 405 | + print("tftpread: too short %d <= %d\n", | |
| 406 | + len, sizeof(tftp->header)); | |
| 407 | + continue; | |
| 408 | + } | |
| 409 | + blockno = (tftp->header[2]<<8)|tftp->header[3]; | |
| 410 | + if(blockno <= tftpblockno){ | |
| 411 | + if(debug) | |
| 412 | + print("tftpread: blkno %d <= %d\n", | |
| 413 | + blockno, tftpblockno); | |
| 414 | + continue; | |
| 415 | + } | |
| 416 | + | |
| 417 | + if(blockno == tftpblockno+1) { | |
| 418 | + tftpblockno++; | |
| 419 | + if(len < dlen) { /* last packet; send final ack */ | |
| 420 | + tftpblockno++; | |
| 421 | + buf[0] = 0; | |
| 422 | + buf[1] = Tftp_ACK; | |
| 423 | + buf[2] = tftpblockno>>8; | |
| 424 | + buf[3] = tftpblockno; | |
| 425 | + udpsend(ctlrno, a, buf, sizeof(buf)); | |
| 426 | + } | |
| 427 | + return len-sizeof(tftp->header); | |
| 428 | + } | |
| 429 | + print("tftpread: block error: %d, expected %d\n", | |
| 430 | + blockno, tftpblockno+1); | |
| 431 | + } | |
| 432 | + | |
| 433 | + return -1; | |
| 434 | +} | |
| 435 | + | |
| 436 | +static int | |
| 437 | +bootpopen(int ctlrno, char *file, Bootp *rep, int dotftpopen) | |
| 438 | +{ | |
| 439 | + Bootp req; | |
| 440 | + int i, n; | |
| 441 | + uchar *ea; | |
| 442 | + char name[128], *filename, *sysname; | |
| 443 | + | |
| 444 | + if((ea = etheraddr(ctlrno)) == 0){ | |
| 445 | + print("invalid ctlrno %d\n", ctlrno); | |
| 446 | + return -1; | |
| 447 | + } | |
| 448 | + | |
| 449 | + filename = 0; | |
| 450 | + sysname = 0; | |
| 451 | + if(file && *file){ | |
| 452 | + strcpy(name, file); | |
| 453 | + if(filename = strchr(name, '!')){ | |
| 454 | + sysname = name; | |
| 455 | + *filename++ = 0; | |
| 456 | + } | |
| 457 | + else | |
| 458 | + filename = name; | |
| 459 | + } | |
| 460 | + | |
| 461 | + memset(&req, 0, sizeof(req)); | |
| 462 | + req.op = Bootrequest; | |
| 463 | + req.htype = 1; /* ethernet */ | |
| 464 | + req.hlen = Eaddrlen; /* ethernet */ | |
| 465 | + memmove(req.chaddr, ea, Eaddrlen); | |
| 466 | + if(filename != nil) | |
| 467 | + strncpy(req.file, filename, sizeof(req.file)); | |
| 468 | + if(sysname != nil) | |
| 469 | + strncpy(req.sname, sysname, sizeof(req.sname)); | |
| 470 | + | |
| 471 | + myaddr.ip = 0; | |
| 472 | + myaddr.port = BPportsrc; | |
| 473 | + memmove(myaddr.ea, ea, Eaddrlen); | |
| 474 | + | |
| 475 | + etherrxflush(ctlrno); | |
| 476 | + for(i = 0; i < 10; i++) { | |
| 477 | + server.ip = Bcastip; | |
| 478 | + server.port = BPportdst; | |
| 479 | + memmove(server.ea, broadcast, sizeof(server.ea)); | |
| 480 | + udpsend(ctlrno, &server, &req, sizeof(req)); | |
| 481 | + if(udprecv(ctlrno, &server, rep, sizeof(*rep)) <= 0) | |
| 482 | + continue; | |
| 483 | + if(memcmp(req.chaddr, rep->chaddr, Eaddrlen)) | |
| 484 | + continue; | |
| 485 | + if(rep->htype != 1 || rep->hlen != Eaddrlen) | |
| 486 | + continue; | |
| 487 | + if(sysname == 0 || strcmp(sysname, rep->sname) == 0) | |
| 488 | + break; | |
| 489 | + } | |
| 490 | + if(i >= 10) { | |
| 491 | + print("bootp timed out\n"); | |
| 492 | + return -1; | |
| 493 | + } | |
| 494 | + | |
| 495 | + if(!dotftpopen) | |
| 496 | + return 0; | |
| 497 | + | |
| 498 | + if(filename == 0 || *filename == 0){ | |
| 499 | + if(strcmp(rep->file, "/386/9pxeload") == 0) | |
| 500 | + return -1; | |
| 501 | + filename = rep->file; | |
| 502 | + } | |
| 503 | + | |
| 504 | + if(rep->sname[0] != '\0') | |
| 505 | + print("%s ", rep->sname); | |
| 506 | + print("(%d.%d.%d.%d!%d): %s\n", | |
| 507 | + rep->siaddr[0], | |
| 508 | + rep->siaddr[1], | |
| 509 | + rep->siaddr[2], | |
| 510 | + rep->siaddr[3], | |
| 511 | + server.port, | |
| 512 | + filename); | |
| 513 | + | |
| 514 | + myaddr.ip = nhgetl(rep->yiaddr); | |
| 515 | + myaddr.port = tftpport++; | |
| 516 | + server.ip = nhgetl(rep->siaddr); | |
| 517 | + server.port = TFTPport; | |
| 518 | + | |
| 519 | + if((n = tftpopen(ctlrno, &server, filename, &tftpb)) < 0) | |
| 520 | + return -1; | |
| 521 | + | |
| 522 | + return n; | |
| 523 | +} | |
| 524 | + | |
| 525 | +int | |
| 526 | +bootpboot(int ctlrno, char *file, Boot *b) | |
| 527 | +{ | |
| 528 | + int n; | |
| 529 | + Bootp rep; | |
| 530 | + | |
| 531 | + if((n = bootpopen(ctlrno, file, &rep, 1)) < 0) | |
| 532 | + return -1; | |
| 533 | + | |
| 534 | + while(bootpass(b, tftpb.data, n) == MORE){ | |
| 535 | + n = tftpread(ctlrno, &server, &tftpb, sizeof(tftpb.data)); | |
| 536 | + if(n < sizeof(tftpb.data)) | |
| 537 | + break; | |
| 538 | + } | |
| 539 | + | |
| 540 | + if(0 < n && n < sizeof(tftpb.data)) /* got to end of file */ | |
| 541 | + bootpass(b, tftpb.data, n); | |
| 542 | + else | |
| 543 | + nak(ctlrno, &server, 3, "ok", 0); /* tftpclose to abort transfer */ | |
| 544 | + bootpass(b, nil, 0); /* boot if possible */ | |
| 545 | + return -1; | |
| 546 | +} | |
| 547 | + | |
| 548 | +#include "fs.h" | |
| 549 | + | |
| 550 | +#define INIPATHLEN 64 | |
| 551 | + | |
| 552 | +static struct { | |
| 553 | + Fs fs; | |
| 554 | + char ini[INIPATHLEN]; | |
| 555 | +} pxether[MaxEther]; | |
| 556 | + | |
| 557 | +static vlong | |
| 558 | +pxediskseek(Fs*, vlong) | |
| 559 | +{ | |
| 560 | + return -1LL; | |
| 561 | +} | |
| 562 | + | |
| 563 | +static long | |
| 564 | +pxediskread(Fs*, void*, long) | |
| 565 | +{ | |
| 566 | + return -1; | |
| 567 | +} | |
| 568 | + | |
| 569 | +static long | |
| 570 | +pxeread(File* f, void* va, long len) | |
| 571 | +{ | |
| 572 | + int n; | |
| 573 | + Bootp rep; | |
| 574 | + char *p, *v; | |
| 575 | + | |
| 576 | + if((n = bootpopen(f->fs->dev, pxether[f->fs->dev].ini, &rep, 1)) < 0) | |
| 577 | + return -1; | |
| 578 | + | |
| 579 | + p = v = va; | |
| 580 | + while(n > 0) { | |
| 581 | + if((p-v)+n > len) | |
| 582 | + n = len - (p-v); | |
| 583 | + memmove(p, tftpb.data, n); | |
| 584 | + p += n; | |
| 585 | + if(n != Segsize) | |
| 586 | + break; | |
| 587 | + if((n = tftpread(f->fs->dev, &server, &tftpb, sizeof(tftpb.data))) < 0) | |
| 588 | + return -1; | |
| 589 | + } | |
| 590 | + return p-v; | |
| 591 | +} | |
| 592 | + | |
| 593 | +static int | |
| 594 | +pxewalk(File* f, char* name) | |
| 595 | +{ | |
| 596 | + Bootp rep; | |
| 597 | + char *ini; | |
| 598 | + | |
| 599 | + switch(f->walked){ | |
| 600 | + default: | |
| 601 | + return -1; | |
| 602 | + case 0: | |
| 603 | + if(strcmp(name, "cfg") == 0){ | |
| 604 | + f->walked = 1; | |
| 605 | + return 1; | |
| 606 | + } | |
| 607 | + break; | |
| 608 | + case 1: | |
| 609 | + if(strcmp(name, "pxe") == 0){ | |
| 610 | + f->walked = 2; | |
| 611 | + return 1; | |
| 612 | + } | |
| 613 | + break; | |
| 614 | + case 2: | |
| 615 | + if(strcmp(name, "%E") != 0) | |
| 616 | + break; | |
| 617 | + f->walked = 3; | |
| 618 | + | |
| 619 | + if(bootpopen(f->fs->dev, nil, &rep, 0) < 0) | |
| 620 | + return 0; | |
| 621 | + | |
| 622 | + ini = pxether[f->fs->dev].ini; | |
| 623 | + snprint(ini, INIPATHLEN, "/cfg/pxe/%E", rep.chaddr); | |
| 624 | + f->path = ini; | |
| 625 | + | |
| 626 | + return 1; | |
| 627 | + } | |
| 628 | + return 0; | |
| 629 | +} | |
| 630 | + | |
| 631 | +void* | |
| 632 | +pxegetfspart(int ctlrno, char* part, int) | |
| 633 | +{ | |
| 634 | + if(!pxe) | |
| 635 | + return nil; | |
| 636 | + if(strcmp(part, "*") != 0) | |
| 637 | + return nil; | |
| 638 | + if(ctlrno >= MaxEther) | |
| 639 | + return nil; | |
| 640 | + | |
| 641 | + pxether[ctlrno].fs.dev = ctlrno; | |
| 642 | + pxether[ctlrno].fs.diskread = pxediskread; | |
| 643 | + pxether[ctlrno].fs.diskseek = pxediskseek; | |
| 644 | + | |
| 645 | + pxether[ctlrno].fs.read = pxeread; | |
| 646 | + pxether[ctlrno].fs.walk = pxewalk; | |
| 647 | + | |
| 648 | + pxether[ctlrno].fs.root.fs = &pxether[ctlrno].fs; | |
| 649 | + pxether[ctlrno].fs.root.walked = 0; | |
| 650 | + | |
| 651 | + return &pxether[ctlrno].fs; | |
| 652 | +} | |
| @@ -0,0 +1,91 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | + | |
| 7 | +enum { | |
| 8 | + Width = 160, | |
| 9 | + Height = 25, | |
| 10 | + | |
| 11 | + Attr = 7, /* white on black */ | |
| 12 | +}; | |
| 13 | + | |
| 14 | +#define CGASCREENBASE ((uchar*)KADDR(0xB8000)) | |
| 15 | + | |
| 16 | +static int pos; | |
| 17 | +static int screeninitdone; | |
| 18 | + | |
| 19 | +static uchar | |
| 20 | +cgaregr(int index) | |
| 21 | +{ | |
| 22 | + outb(0x3D4, index); | |
| 23 | + return inb(0x3D4+1) & 0xFF; | |
| 24 | +} | |
| 25 | + | |
| 26 | +static void | |
| 27 | +cgaregw(int index, int data) | |
| 28 | +{ | |
| 29 | + outb(0x3D4, index); | |
| 30 | + outb(0x3D4+1, data); | |
| 31 | +} | |
| 32 | + | |
| 33 | +static void | |
| 34 | +movecursor(void) | |
| 35 | +{ | |
| 36 | + cgaregw(0x0E, (pos/2>>8) & 0xFF); | |
| 37 | + cgaregw(0x0F, pos/2 & 0xFF); | |
| 38 | + CGASCREENBASE[pos+1] = Attr; | |
| 39 | +} | |
| 40 | + | |
| 41 | +static void | |
| 42 | +cgascreenputc(int c) | |
| 43 | +{ | |
| 44 | + int i; | |
| 45 | + | |
| 46 | + if(c == '\n'){ | |
| 47 | + pos = pos/Width; | |
| 48 | + pos = (pos+1)*Width; | |
| 49 | + } | |
| 50 | + else if(c == '\t'){ | |
| 51 | + i = 8 - ((pos/2)&7); | |
| 52 | + while(i-->0) | |
| 53 | + cgascreenputc(' '); | |
| 54 | + } | |
| 55 | + else if(c == '\b'){ | |
| 56 | + if(pos >= 2) | |
| 57 | + pos -= 2; | |
| 58 | + cgascreenputc(' '); | |
| 59 | + pos -= 2; | |
| 60 | + } | |
| 61 | + else{ | |
| 62 | + CGASCREENBASE[pos++] = c; | |
| 63 | + CGASCREENBASE[pos++] = Attr; | |
| 64 | + } | |
| 65 | + if(pos >= Width*Height){ | |
| 66 | + memmove(CGASCREENBASE, &CGASCREENBASE[Width], Width*(Height-1)); | |
| 67 | + memset(&CGASCREENBASE[Width*(Height-1)], 0, Width); | |
| 68 | + pos = Width*(Height-1); | |
| 69 | + } | |
| 70 | + movecursor(); | |
| 71 | +} | |
| 72 | + | |
| 73 | +static void | |
| 74 | +screeninit(void) | |
| 75 | +{ | |
| 76 | + if(screeninitdone == 0){ | |
| 77 | + pos = cgaregr(0x0E)<<8; | |
| 78 | + pos |= cgaregr(0x0F); | |
| 79 | + pos *= 2; | |
| 80 | + screeninitdone = 1; | |
| 81 | + } | |
| 82 | +} | |
| 83 | + | |
| 84 | +void | |
| 85 | +cgascreenputs(char* s, int n) | |
| 86 | +{ | |
| 87 | + if(screeninitdone == 0) | |
| 88 | + screeninit(); | |
| 89 | + while(n-- > 0) | |
| 90 | + cgascreenputc(*s++); | |
| 91 | +} | |
| @@ -0,0 +1,305 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | +#include "ureg.h" | |
| 8 | + | |
| 9 | +/* | |
| 10 | + * 8253 timer | |
| 11 | + */ | |
| 12 | +enum | |
| 13 | +{ | |
| 14 | + T0cntr= 0x40, /* counter ports */ | |
| 15 | + T1cntr= 0x41, /* ... */ | |
| 16 | + T2cntr= 0x42, /* ... */ | |
| 17 | + Tmode= 0x43, /* mode port */ | |
| 18 | + | |
| 19 | + /* commands */ | |
| 20 | + Latch0= 0x00, /* latch counter 0's value */ | |
| 21 | + Load0= 0x30, /* load counter 0 with 2 bytes */ | |
| 22 | + | |
| 23 | + /* modes */ | |
| 24 | + Square= 0x36, /* perioic square wave */ | |
| 25 | + | |
| 26 | + Freq= 1193182, /* Real clock frequency */ | |
| 27 | +}; | |
| 28 | + | |
| 29 | +static uvlong cpuhz = 66000000; | |
| 30 | +static int cpumhz = 66; | |
| 31 | +static int loopconst = 100; | |
| 32 | +int cpuidax, cpuiddx; | |
| 33 | +int havetsc; | |
| 34 | + | |
| 35 | +extern void _cycles(uvlong*); /* in l.s */ | |
| 36 | +extern void wrmsr(int, vlong); | |
| 37 | + | |
| 38 | +static void | |
| 39 | +clockintr(Ureg*, void*) | |
| 40 | +{ | |
| 41 | + m->ticks++; | |
| 42 | + checkalarms(); | |
| 43 | +} | |
| 44 | + | |
| 45 | +#define STEPPING(x) ((x)&0xf) | |
| 46 | +#define X86MODEL(x) (((x)>>4)&0xf) | |
| 47 | +#define X86FAMILY(x) (((x)>>8)&0xf) | |
| 48 | + | |
| 49 | +enum | |
| 50 | +{ | |
| 51 | + /* flags */ | |
| 52 | + CpuidFPU = 0x001, /* on-chip floating point unit */ | |
| 53 | + CpuidMCE = 0x080, /* machine check exception */ | |
| 54 | + CpuidCX8 = 0x100, /* CMPXCHG8B instruction */ | |
| 55 | +}; | |
| 56 | + | |
| 57 | +typedef struct | |
| 58 | +{ | |
| 59 | + int family; | |
| 60 | + int model; | |
| 61 | + int aalcycles; | |
| 62 | + char *name; | |
| 63 | +} X86type; | |
| 64 | + | |
| 65 | +X86type x86intel[] = | |
| 66 | +{ | |
| 67 | + { 4, 0, 22, "486DX", }, /* known chips */ | |
| 68 | + { 4, 1, 22, "486DX50", }, | |
| 69 | + { 4, 2, 22, "486SX", }, | |
| 70 | + { 4, 3, 22, "486DX2", }, | |
| 71 | + { 4, 4, 22, "486SL", }, | |
| 72 | + { 4, 5, 22, "486SX2", }, | |
| 73 | + { 4, 7, 22, "DX2WB", }, /* P24D */ | |
| 74 | + { 4, 8, 22, "DX4", }, /* P24C */ | |
| 75 | + { 4, 9, 22, "DX4WB", }, /* P24CT */ | |
| 76 | + { 5, 0, 23, "P5", }, | |
| 77 | + { 5, 1, 23, "P5", }, | |
| 78 | + { 5, 2, 23, "P54C", }, | |
| 79 | + { 5, 3, 23, "P24T", }, | |
| 80 | + { 5, 4, 23, "P55C MMX", }, | |
| 81 | + { 5, 7, 23, "P54C VRT", }, | |
| 82 | + { 6, 1, 16, "PentiumPro", },/* trial and error */ | |
| 83 | + { 6, 3, 16, "PentiumII", }, | |
| 84 | + { 6, 5, 16, "PentiumII/Xeon", }, | |
| 85 | + { 6, 6, 16, "Celeron", }, | |
| 86 | + { 6, 7, 16, "PentiumIII/Xeon", }, | |
| 87 | + { 6, 8, 16, "PentiumIII/Xeon", }, | |
| 88 | + { 6, 0xB, 16, "PentiumIII/Xeon", }, | |
| 89 | + { 0xF, 1, 16, "P4", }, /* P4 */ | |
| 90 | + { 0xF, 2, 16, "PentiumIV/Xeon", }, | |
| 91 | + | |
| 92 | + { 3, -1, 32, "386", }, /* family defaults */ | |
| 93 | + { 4, -1, 22, "486", }, | |
| 94 | + { 5, -1, 23, "P5", }, | |
| 95 | + { 6, -1, 16, "P6", }, | |
| 96 | + { 0xF, -1, 16, "P4", }, /* P4 */ | |
| 97 | + | |
| 98 | + { -1, -1, 16, "unknown", }, /* total default */ | |
| 99 | +}; | |
| 100 | + | |
| 101 | + | |
| 102 | +/* | |
| 103 | + * The AMD processors all implement the CPUID instruction. | |
| 104 | + * The later ones also return the processor name via functions | |
| 105 | + * 0x80000002, 0x80000003 and 0x80000004 in registers AX, BX, CX | |
| 106 | + * and DX: | |
| 107 | + * K5 "AMD-K5(tm) Processor" | |
| 108 | + * K6 "AMD-K6tm w/ multimedia extensions" | |
| 109 | + * K6 3D "AMD-K6(tm) 3D processor" | |
| 110 | + * K6 3D+ ? | |
| 111 | + */ | |
| 112 | +static X86type x86amd[] = | |
| 113 | +{ | |
| 114 | + { 5, 0, 23, "AMD-K5", }, /* guesswork */ | |
| 115 | + { 5, 1, 23, "AMD-K5", }, /* guesswork */ | |
| 116 | + { 5, 2, 23, "AMD-K5", }, /* guesswork */ | |
| 117 | + { 5, 3, 23, "AMD-K5", }, /* guesswork */ | |
| 118 | + { 5, 6, 11, "AMD-K6", }, /* trial and error */ | |
| 119 | + { 5, 7, 11, "AMD-K6", }, /* trial and error */ | |
| 120 | + { 5, 8, 11, "AMD-K6-2", }, /* trial and error */ | |
| 121 | + { 5, 9, 11, "AMD-K6-III", },/* trial and error */ | |
| 122 | + | |
| 123 | + { 6, 1, 11, "AMD-Athlon", },/* trial and error */ | |
| 124 | + { 6, 2, 11, "AMD-Athlon", },/* trial and error */ | |
| 125 | + | |
| 126 | + { 4, -1, 22, "Am486", }, /* guesswork */ | |
| 127 | + { 5, -1, 23, "AMD-K5/K6", }, /* guesswork */ | |
| 128 | + { 6, -1, 11, "AMD-Athlon", },/* guesswork */ | |
| 129 | + { 0xF, -1, 11, "AMD64", }, /* guesswork */ | |
| 130 | + | |
| 131 | + { -1, -1, 11, "unknown", }, /* total default */ | |
| 132 | +}; | |
| 133 | + | |
| 134 | +static X86type *cputype; | |
| 135 | + | |
| 136 | + | |
| 137 | +void | |
| 138 | +delay(int millisecs) | |
| 139 | +{ | |
| 140 | + millisecs *= loopconst; | |
| 141 | + if(millisecs <= 0) | |
| 142 | + millisecs = 1; | |
| 143 | + aamloop(millisecs); | |
| 144 | +} | |
| 145 | + | |
| 146 | +void | |
| 147 | +microdelay(int microsecs) | |
| 148 | +{ | |
| 149 | + microsecs *= loopconst; | |
| 150 | + microsecs /= 1000; | |
| 151 | + if(microsecs <= 0) | |
| 152 | + microsecs = 1; | |
| 153 | + aamloop(microsecs); | |
| 154 | +} | |
| 155 | + | |
| 156 | +extern void cpuid(char*, int*, int*); | |
| 157 | + | |
| 158 | +X86type* | |
| 159 | +cpuidentify(void) | |
| 160 | +{ | |
| 161 | + int family, model; | |
| 162 | + X86type *t; | |
| 163 | + char cpuidid[16]; | |
| 164 | + int cpuidax, cpuiddx; | |
| 165 | + | |
| 166 | + cpuid(cpuidid, &cpuidax, &cpuiddx); | |
| 167 | + if(strncmp(cpuidid, "AuthenticAMD", 12) == 0) | |
| 168 | + t = x86amd; | |
| 169 | + else | |
| 170 | + t = x86intel; | |
| 171 | + family = X86FAMILY(cpuidax); | |
| 172 | + model = X86MODEL(cpuidax); | |
| 173 | + if (0) | |
| 174 | + print("cpuidentify: cpuidax 0x%ux cpuiddx 0x%ux\n", | |
| 175 | + cpuidax, cpuiddx); | |
| 176 | + while(t->name){ | |
| 177 | + if((t->family == family && t->model == model) | |
| 178 | + || (t->family == family && t->model == -1) | |
| 179 | + || (t->family == -1)) | |
| 180 | + break; | |
| 181 | + t++; | |
| 182 | + } | |
| 183 | + if(t->name == nil) | |
| 184 | + panic("cpuidentify"); | |
| 185 | + | |
| 186 | + if(cpuiddx & 0x10){ | |
| 187 | + havetsc = 1; | |
| 188 | + if(cpuiddx & 0x20) | |
| 189 | + wrmsr(0x10, 0); | |
| 190 | + } | |
| 191 | + | |
| 192 | + return t; | |
| 193 | +} | |
| 194 | + | |
| 195 | +void | |
| 196 | +clockinit(void) | |
| 197 | +{ | |
| 198 | + uvlong a, b, cpufreq; | |
| 199 | + int loops, incr, x, y; | |
| 200 | + X86type *t; | |
| 201 | + | |
| 202 | + /* | |
| 203 | + * set vector for clock interrupts | |
| 204 | + */ | |
| 205 | + setvec(VectorCLOCK, clockintr, 0); | |
| 206 | + | |
| 207 | + t = cpuidentify(); | |
| 208 | + | |
| 209 | + /* | |
| 210 | + * set clock for 1/HZ seconds | |
| 211 | + */ | |
| 212 | + outb(Tmode, Load0|Square); | |
| 213 | + outb(T0cntr, (Freq/HZ)); /* low byte */ | |
| 214 | + outb(T0cntr, (Freq/HZ)>>8); /* high byte */ | |
| 215 | + | |
| 216 | + /* | |
| 217 | + * Introduce a little delay to make sure the count is | |
| 218 | + * latched and the timer is counting down; with a fast | |
| 219 | + * enough processor this may not be the case. | |
| 220 | + * The i8254 (which this probably is) has a read-back | |
| 221 | + * command which can be used to make sure the counting | |
| 222 | + * register has been written into the counting element. | |
| 223 | + */ | |
| 224 | + x = (Freq/HZ); | |
| 225 | + for(loops = 0; loops < 100000 && x >= (Freq/HZ); loops++){ | |
| 226 | + outb(Tmode, Latch0); | |
| 227 | + x = inb(T0cntr); | |
| 228 | + x |= inb(T0cntr)<<8; | |
| 229 | + } | |
| 230 | + | |
| 231 | + /* find biggest loop that doesn't wrap */ | |
| 232 | + incr = 16000000/(t->aalcycles*HZ*2); | |
| 233 | + x = 2000; | |
| 234 | + for(loops = incr; loops < 64*1024; loops += incr) { | |
| 235 | + | |
| 236 | + /* | |
| 237 | + * measure time for the loop | |
| 238 | + * | |
| 239 | + * MOVL loops,CX | |
| 240 | + * aaml1: AAM | |
| 241 | + * LOOP aaml1 | |
| 242 | + * | |
| 243 | + * the time for the loop should be independent of external | |
| 244 | + * cache and memory system since it fits in the execution | |
| 245 | + * prefetch buffer. | |
| 246 | + * | |
| 247 | + */ | |
| 248 | + outb(Tmode, Latch0); | |
| 249 | + if(havetsc) | |
| 250 | + _cycles(&a); | |
| 251 | + x = inb(T0cntr); | |
| 252 | + x |= inb(T0cntr)<<8; | |
| 253 | + aamloop(loops); | |
| 254 | + outb(Tmode, Latch0); | |
| 255 | + if(havetsc) | |
| 256 | + _cycles(&b); | |
| 257 | + y = inb(T0cntr); | |
| 258 | + y |= inb(T0cntr)<<8; | |
| 259 | + x -= y; | |
| 260 | + | |
| 261 | + if(x < 0) | |
| 262 | + x += Freq/HZ; | |
| 263 | + | |
| 264 | + if(x > Freq/(3*HZ)) | |
| 265 | + break; | |
| 266 | + } | |
| 267 | + | |
| 268 | + /* | |
| 269 | + * figure out clock frequency and a loop multiplier for delay(). | |
| 270 | + * counter goes at twice the frequency, once per transition, | |
| 271 | + * i.e., twice per square wave | |
| 272 | + */ | |
| 273 | + cpufreq = (vlong)loops*((t->aalcycles*2*Freq)/x); | |
| 274 | + loopconst = (cpufreq/1000)/t->aalcycles; /* AAM+LOOP's for 1 ms */ | |
| 275 | + | |
| 276 | + if(havetsc){ | |
| 277 | + /* counter goes up by 2*Freq */ | |
| 278 | + b = (b-a)<<1; | |
| 279 | + b *= Freq; | |
| 280 | + b /= x; | |
| 281 | + | |
| 282 | + /* | |
| 283 | + * round to the nearest megahz | |
| 284 | + */ | |
| 285 | + cpumhz = (b+500000)/1000000L; | |
| 286 | + cpuhz = b; | |
| 287 | + } | |
| 288 | + else{ | |
| 289 | + /* | |
| 290 | + * add in possible .5% error and convert to MHz | |
| 291 | + */ | |
| 292 | + cpumhz = (cpufreq + cpufreq/200)/1000000; | |
| 293 | + cpuhz = cpufreq; | |
| 294 | + } | |
| 295 | + | |
| 296 | + if(debug){ | |
| 297 | + int timeo; | |
| 298 | + | |
| 299 | + print("%dMHz %s loop %d\n", cpumhz, t->name, loopconst); | |
| 300 | + print("tick..."); | |
| 301 | + for(timeo = 0; timeo < 10; timeo++) | |
| 302 | + delay(1000); | |
| 303 | + print("tock...\n"); | |
| 304 | + } | |
| 305 | +} | |
| @@ -0,0 +1,537 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +#include "fs.h" | |
| 9 | + | |
| 10 | +/* | |
| 11 | + * Where configuration info is left for the loaded programme. | |
| 12 | + * This will turn into a structure as more is done by the boot loader | |
| 13 | + * (e.g. why parse the .ini file twice?). | |
| 14 | + * There are 3584 bytes available at CONFADDR. | |
| 15 | + * | |
| 16 | + * The low-level boot routines in l.s leave data for us at CONFADDR, | |
| 17 | + * which we pick up before reading the plan9.ini file. | |
| 18 | + */ | |
| 19 | +#define BOOTLINELEN 64 | |
| 20 | +#define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN)) | |
| 21 | +#define BOOTARGSLEN (3584-0x200-BOOTLINELEN) | |
| 22 | +#define MAXCONF 100 | |
| 23 | + | |
| 24 | +static char *confname[MAXCONF]; | |
| 25 | +static char *confval[MAXCONF]; | |
| 26 | +static int nconf; | |
| 27 | + | |
| 28 | +extern char **ini; | |
| 29 | + | |
| 30 | +typedef struct { | |
| 31 | + char* name; | |
| 32 | + int start; | |
| 33 | + int end; | |
| 34 | +} Mblock; | |
| 35 | + | |
| 36 | +typedef struct { | |
| 37 | + char* tag; | |
| 38 | + Mblock* mb; | |
| 39 | +} Mitem; | |
| 40 | + | |
| 41 | +static Mblock mblock[MAXCONF]; | |
| 42 | +static int nmblock; | |
| 43 | +static Mitem mitem[MAXCONF]; | |
| 44 | +static int nmitem; | |
| 45 | +static char* mdefault; | |
| 46 | +static char mdefaultbuf[10]; | |
| 47 | +static int mtimeout; | |
| 48 | + | |
| 49 | +static char* | |
| 50 | +comma(char* line, char** residue) | |
| 51 | +{ | |
| 52 | + char *q, *r; | |
| 53 | + | |
| 54 | + if((q = strchr(line, ',')) != nil){ | |
| 55 | + *q++ = 0; | |
| 56 | + if(*q == ' ') | |
| 57 | + q++; | |
| 58 | + } | |
| 59 | + *residue = q; | |
| 60 | + | |
| 61 | + if((r = strchr(line, ' ')) != nil) | |
| 62 | + *r = 0; | |
| 63 | + | |
| 64 | + if(*line == ' ') | |
| 65 | + line++; | |
| 66 | + return line; | |
| 67 | +} | |
| 68 | + | |
| 69 | +static Mblock* | |
| 70 | +findblock(char* name, char** residue) | |
| 71 | +{ | |
| 72 | + int i; | |
| 73 | + char *p; | |
| 74 | + | |
| 75 | + p = comma(name, residue); | |
| 76 | + for(i = 0; i < nmblock; i++){ | |
| 77 | + if(strcmp(p, mblock[i].name) == 0) | |
| 78 | + return &mblock[i]; | |
| 79 | + } | |
| 80 | + return nil; | |
| 81 | +} | |
| 82 | + | |
| 83 | +static Mitem* | |
| 84 | +finditem(char* name, char** residue) | |
| 85 | +{ | |
| 86 | + int i; | |
| 87 | + char *p; | |
| 88 | + | |
| 89 | + p = comma(name, residue); | |
| 90 | + for(i = 0; i < nmitem; i++){ | |
| 91 | + if(strcmp(p, mitem[i].mb->name) == 0) | |
| 92 | + return &mitem[i]; | |
| 93 | + } | |
| 94 | + return nil; | |
| 95 | +} | |
| 96 | + | |
| 97 | +static void | |
| 98 | +parsemenu(char* str, char* scratch, int len) | |
| 99 | +{ | |
| 100 | + Mitem *mi; | |
| 101 | + Mblock *mb, *menu; | |
| 102 | + char buf[20], *p, *q, *line[MAXCONF]; | |
| 103 | + int i, inblock, n, show; | |
| 104 | + | |
| 105 | + inblock = 0; | |
| 106 | + menu = nil; | |
| 107 | + memmove(scratch, str, len); | |
| 108 | + n = getfields(scratch, line, MAXCONF, '\n'); | |
| 109 | + if(n >= MAXCONF) | |
| 110 | + print("warning: possibly too many lines in plan9.ini\n"); | |
| 111 | + for(i = 0; i < n; i++){ | |
| 112 | + p = line[i]; | |
| 113 | + if(inblock && *p == '['){ | |
| 114 | + mblock[nmblock].end = i; | |
| 115 | + if(strcmp(mblock[nmblock].name, "menu") == 0) | |
| 116 | + menu = &mblock[nmblock]; | |
| 117 | + nmblock++; | |
| 118 | + inblock = 0; | |
| 119 | + } | |
| 120 | + if(*p == '['){ | |
| 121 | + if(nmblock == 0 && i != 0){ | |
| 122 | + mblock[nmblock].name = "common"; | |
| 123 | + mblock[nmblock].start = 0; | |
| 124 | + mblock[nmblock].end = i; | |
| 125 | + nmblock++; | |
| 126 | + } | |
| 127 | + q = strchr(p+1, ']'); | |
| 128 | + if(q == nil || *(q+1) != 0){ | |
| 129 | + print("malformed menu block header - %s\n", p); | |
| 130 | + return; | |
| 131 | + } | |
| 132 | + *q = 0; | |
| 133 | + mblock[nmblock].name = p+1; | |
| 134 | + mblock[nmblock].start = i+1; | |
| 135 | + inblock = 1; | |
| 136 | + } | |
| 137 | + } | |
| 138 | + | |
| 139 | + if(inblock){ | |
| 140 | + mblock[nmblock].end = i; | |
| 141 | + nmblock++; | |
| 142 | + } | |
| 143 | + if(menu == nil) | |
| 144 | + return; | |
| 145 | + if(nmblock < 2){ | |
| 146 | + print("incomplete menu specification\n"); | |
| 147 | + return; | |
| 148 | + } | |
| 149 | + | |
| 150 | + for(i = menu->start; i < menu->end; i++){ | |
| 151 | + p = line[i]; | |
| 152 | + if(cistrncmp(p, "menuitem=", 9) == 0){ | |
| 153 | + p += 9; | |
| 154 | + if((mb = findblock(p, &q)) == nil){ | |
| 155 | + print("no block for menuitem %s\n", p); | |
| 156 | + return; | |
| 157 | + } | |
| 158 | + if(q != nil) | |
| 159 | + mitem[nmitem].tag = q; | |
| 160 | + else | |
| 161 | + mitem[nmitem].tag = mb->name; | |
| 162 | + mitem[nmitem].mb = mb; | |
| 163 | + nmitem++; | |
| 164 | + } | |
| 165 | + else if(cistrncmp(p, "menudefault=", 12) == 0){ | |
| 166 | + p += 12; | |
| 167 | + if((mi = finditem(p, &q)) == nil){ | |
| 168 | + print("no item for menudefault %s\n", p); | |
| 169 | + return; | |
| 170 | + } | |
| 171 | + if(q != nil) | |
| 172 | + mtimeout = strtol(q, 0, 0); | |
| 173 | + sprint(mdefaultbuf, "%ld", mi-mitem+1); | |
| 174 | + mdefault = mdefaultbuf; | |
| 175 | + } | |
| 176 | + else if(cistrncmp(p, "menuconsole=", 12) == 0){ | |
| 177 | + p += 12; | |
| 178 | + p = comma(p, &q); | |
| 179 | + consinit(p, q); | |
| 180 | + } | |
| 181 | + else{ | |
| 182 | + print("invalid line in [menu] block - %s\n", p); | |
| 183 | + return; | |
| 184 | + } | |
| 185 | + } | |
| 186 | + | |
| 187 | +again: | |
| 188 | + print("\nPlan 9 Startup Menu:\n====================\n"); | |
| 189 | + for(i = 0; i < nmitem; i++) | |
| 190 | + print(" %d. %s\n", i+1, mitem[i].tag); | |
| 191 | + for(;;){ | |
| 192 | + getstr("Selection", buf, sizeof(buf), mdefault, mtimeout); | |
| 193 | + mtimeout = 0; | |
| 194 | + i = strtol(buf, &p, 0)-1; | |
| 195 | + if(i < 0 || i >= nmitem) | |
| 196 | + goto again; | |
| 197 | + switch(*p){ | |
| 198 | + case 'p': | |
| 199 | + case 'P': | |
| 200 | + show = 1; | |
| 201 | + print("\n"); | |
| 202 | + break; | |
| 203 | + case 0: | |
| 204 | + show = 0; | |
| 205 | + break; | |
| 206 | + default: | |
| 207 | + continue; | |
| 208 | + | |
| 209 | + } | |
| 210 | + mi = &mitem[i]; | |
| 211 | + | |
| 212 | + p = str; | |
| 213 | + p += sprint(p, "menuitem=%s\n", mi->mb->name); | |
| 214 | + for(i = 0; i < nmblock; i++){ | |
| 215 | + mb = &mblock[i]; | |
| 216 | + if(mi->mb != mb && cistrcmp(mb->name, "common") != 0) | |
| 217 | + continue; | |
| 218 | + for(n = mb->start; n < mb->end; n++) | |
| 219 | + p += sprint(p, "%s\n", line[n]); | |
| 220 | + } | |
| 221 | + | |
| 222 | + if(show){ | |
| 223 | + for(q = str; q < p; q += i){ | |
| 224 | + if((i = print(q)) <= 0) | |
| 225 | + break; | |
| 226 | + } | |
| 227 | + goto again; | |
| 228 | + } | |
| 229 | + break; | |
| 230 | + } | |
| 231 | + print("\n"); | |
| 232 | +} | |
| 233 | + | |
| 234 | +/* | |
| 235 | +static void | |
| 236 | +msleep(int msec) | |
| 237 | +{ | |
| 238 | + ulong start; | |
| 239 | + | |
| 240 | + for(start = m->ticks; TK2MS(m->ticks - start) < msec; ) | |
| 241 | + ; | |
| 242 | +} | |
| 243 | +*/ | |
| 244 | + | |
| 245 | +void | |
| 246 | +readlsconf(void) | |
| 247 | +{ | |
| 248 | + uchar *p; | |
| 249 | + | |
| 250 | + p = (uchar*)CONFADDR; | |
| 251 | + for(;;) { | |
| 252 | + if(strcmp((char*)p, "APM") == 0){ | |
| 253 | + apm.haveinfo = 1; | |
| 254 | + apm.ax = *(ushort*)(p+4); | |
| 255 | + apm.cx = *(ushort*)(p+6); | |
| 256 | + apm.dx = *(ushort*)(p+8); | |
| 257 | + apm.di = *(ushort*)(p+10); | |
| 258 | + apm.ebx = *(ulong*)(p+12); | |
| 259 | + apm.esi = *(ulong*)(p+16); | |
| 260 | + print("apm ax=%x cx=%x dx=%x di=%x ebx=%x esi=%x\n", | |
| 261 | + apm.ax, apm.cx, apm.dx, apm.di, apm.ebx, apm.esi); | |
| 262 | + p += 20; | |
| 263 | + continue; | |
| 264 | + } | |
| 265 | + break; | |
| 266 | + } | |
| 267 | +} | |
| 268 | + | |
| 269 | +char* | |
| 270 | +getconf(char *name) | |
| 271 | +{ | |
| 272 | + int i, n, nmatch; | |
| 273 | + char buf[20]; | |
| 274 | + | |
| 275 | + nmatch = 0; | |
| 276 | + for(i = 0; i < nconf; i++) | |
| 277 | + if(cistrcmp(confname[i], name) == 0) | |
| 278 | + nmatch++; | |
| 279 | + | |
| 280 | + switch(nmatch) { | |
| 281 | + default: | |
| 282 | + print("\n"); | |
| 283 | + nmatch = 0; | |
| 284 | + for(i = 0; i < nconf; i++) | |
| 285 | + if(cistrcmp(confname[i], name) == 0) | |
| 286 | + print("%d. %s\n", ++nmatch, confval[i]); | |
| 287 | + print("%d. none of the above\n", ++nmatch); | |
| 288 | + do { | |
| 289 | + getstr(name, buf, sizeof(buf), nil, 0); | |
| 290 | + n = atoi(buf); | |
| 291 | + } while(n < 1 || n > nmatch); | |
| 292 | + | |
| 293 | + for(i = 0; i < nconf; i++) | |
| 294 | + if(cistrcmp(confname[i], name) == 0) | |
| 295 | + if(--n == 0) | |
| 296 | + return confval[i]; | |
| 297 | + break; | |
| 298 | + | |
| 299 | + case 1: | |
| 300 | + for(i = 0; i < nconf; i++) | |
| 301 | + if(cistrcmp(confname[i], name) == 0) | |
| 302 | + return confval[i]; | |
| 303 | + break; | |
| 304 | + | |
| 305 | + case 0: | |
| 306 | + break; | |
| 307 | + } | |
| 308 | + return nil; | |
| 309 | +} | |
| 310 | + | |
| 311 | +void | |
| 312 | +addconf(char *fmt, ...) | |
| 313 | +{ | |
| 314 | + va_list arg; | |
| 315 | + | |
| 316 | + va_start(arg, fmt); | |
| 317 | + vseprint(BOOTARGS+strlen(BOOTARGS), BOOTARGS+BOOTARGSLEN, fmt, arg); | |
| 318 | + va_end(arg); | |
| 319 | +} | |
| 320 | + | |
| 321 | +void | |
| 322 | +changeconf(char *fmt, ...) | |
| 323 | +{ | |
| 324 | + va_list arg; | |
| 325 | + char *p, *q, pref[20], buf[128]; | |
| 326 | + | |
| 327 | + va_start(arg, fmt); | |
| 328 | + vseprint(buf, buf+sizeof buf, fmt, arg); | |
| 329 | + va_end(arg); | |
| 330 | + strncpy(pref+1, buf, 19); | |
| 331 | + pref[19] = '\0'; | |
| 332 | + if(p = strchr(pref, '=')) | |
| 333 | + *(p+1) = '\0'; | |
| 334 | + else | |
| 335 | + print("warning: did not change %s in plan9.ini\n", buf); | |
| 336 | + | |
| 337 | + /* find old line by looking for \nwhat= */ | |
| 338 | + pref[0] = '\n'; | |
| 339 | + if(strncmp(BOOTARGS, pref+1, strlen(pref+1)) == 0) | |
| 340 | + p = BOOTARGS; | |
| 341 | + else if(p = strstr(BOOTARGS, pref)) | |
| 342 | + p++; | |
| 343 | + else | |
| 344 | + p = nil; | |
| 345 | + | |
| 346 | + /* move rest of args up, deleting what= line. */ | |
| 347 | + if(p != nil && (q = strchr(p, '\n')) != nil) | |
| 348 | + memmove(p, q+1, strlen(q+1)+1); | |
| 349 | + | |
| 350 | + /* add replacement to end */ | |
| 351 | + addconf("%s", buf); | |
| 352 | +} | |
| 353 | + | |
| 354 | +/* | |
| 355 | + * read configuration file | |
| 356 | + */ | |
| 357 | +static char inibuf[BOOTARGSLEN]; | |
| 358 | +static char id[8] = "ZORT 0\r\n"; | |
| 359 | + | |
| 360 | +int | |
| 361 | +dotini(Fs *fs) | |
| 362 | +{ | |
| 363 | + File rc; | |
| 364 | + int blankline, i, incomment, inspace, n; | |
| 365 | + char *cp, *p, *q, *line[MAXCONF]; | |
| 366 | + | |
| 367 | + if(fswalk(fs, *ini, &rc) <= 0) | |
| 368 | + return -1; | |
| 369 | + | |
| 370 | + cp = inibuf; | |
| 371 | + *cp = 0; | |
| 372 | + n = fsread(&rc, cp, BOOTARGSLEN-1); | |
| 373 | + if(n <= 0) | |
| 374 | + return -1; | |
| 375 | + | |
| 376 | + cp[n] = 0; | |
| 377 | + | |
| 378 | + /* | |
| 379 | + * Strip out '\r', change '\t' -> ' '. | |
| 380 | + * Change runs of spaces into single spaces. | |
| 381 | + * Strip out trailing spaces, blank lines. | |
| 382 | + * | |
| 383 | + * We do this before we make the copy so that if we | |
| 384 | + * need to change the copy, it is already fairly clean. | |
| 385 | + * The main need is in the case when plan9.ini has been | |
| 386 | + * padded with lots of trailing spaces, as is the case | |
| 387 | + * for those created during a distribution install. | |
| 388 | + */ | |
| 389 | + p = cp; | |
| 390 | + blankline = 1; | |
| 391 | + incomment = inspace = 0; | |
| 392 | + for(q = cp; *q; q++){ | |
| 393 | + if(*q == '\r') | |
| 394 | + continue; | |
| 395 | + if(*q == '\t') | |
| 396 | + *q = ' '; | |
| 397 | + if(*q == ' '){ | |
| 398 | + inspace = 1; | |
| 399 | + continue; | |
| 400 | + } | |
| 401 | + if(*q == '\n'){ | |
| 402 | + if(!blankline){ | |
| 403 | + if(!incomment) | |
| 404 | + *p++ = '\n'; | |
| 405 | + blankline = 1; | |
| 406 | + } | |
| 407 | + incomment = inspace = 0; | |
| 408 | + continue; | |
| 409 | + } | |
| 410 | + if(inspace){ | |
| 411 | + if(!blankline && !incomment) | |
| 412 | + *p++ = ' '; | |
| 413 | + inspace = 0; | |
| 414 | + } | |
| 415 | + if(blankline && *q == '#') | |
| 416 | + incomment = 1; | |
| 417 | + blankline = 0; | |
| 418 | + if(!incomment) | |
| 419 | + *p++ = *q; | |
| 420 | + } | |
| 421 | + if(p > cp && p[-1] != '\n') | |
| 422 | + *p++ = '\n'; | |
| 423 | + *p++ = 0; | |
| 424 | + n = p-cp; | |
| 425 | + | |
| 426 | + parsemenu(cp, BOOTARGS, n); | |
| 427 | + | |
| 428 | + /* | |
| 429 | + * Keep a copy. | |
| 430 | + * We could change this to pass the parsed strings | |
| 431 | + * to the booted programme instead of the raw | |
| 432 | + * string, then it only gets done once. | |
| 433 | + */ | |
| 434 | + if(strncmp(cp, id, sizeof(id))){ | |
| 435 | + memmove(BOOTARGS, id, sizeof(id)); | |
| 436 | + if(n+1+sizeof(id) >= BOOTARGSLEN) | |
| 437 | + n -= sizeof(id); | |
| 438 | + memmove(BOOTARGS+sizeof(id), cp, n+1); | |
| 439 | + } | |
| 440 | + else | |
| 441 | + memmove(BOOTARGS, cp, n+1); | |
| 442 | + | |
| 443 | + n = getfields(cp, line, MAXCONF, '\n'); | |
| 444 | + for(i = 0; i < n; i++){ | |
| 445 | + cp = strchr(line[i], '='); | |
| 446 | + if(cp == 0) | |
| 447 | + continue; | |
| 448 | + *cp++ = 0; | |
| 449 | + if(cp - line[i] >= NAMELEN+1) | |
| 450 | + *(line[i]+NAMELEN-1) = 0; | |
| 451 | + confname[nconf] = line[i]; | |
| 452 | + confval[nconf] = cp; | |
| 453 | + nconf++; | |
| 454 | + } | |
| 455 | + return 0; | |
| 456 | +} | |
| 457 | + | |
| 458 | +static int | |
| 459 | +parseether(uchar *to, char *from) | |
| 460 | +{ | |
| 461 | + char nip[4]; | |
| 462 | + char *p; | |
| 463 | + int i; | |
| 464 | + | |
| 465 | + p = from; | |
| 466 | + while(*p == ' ') | |
| 467 | + ++p; | |
| 468 | + for(i = 0; i < 6; i++){ | |
| 469 | + if(*p == 0) | |
| 470 | + return -1; | |
| 471 | + nip[0] = *p++; | |
| 472 | + if(*p == 0) | |
| 473 | + return -1; | |
| 474 | + nip[1] = *p++; | |
| 475 | + nip[2] = 0; | |
| 476 | + to[i] = strtoul(nip, 0, 16); | |
| 477 | + if(*p == ':') | |
| 478 | + p++; | |
| 479 | + } | |
| 480 | + return 0; | |
| 481 | +} | |
| 482 | + | |
| 483 | +int | |
| 484 | +isaconfig(char *class, int ctlrno, ISAConf *isa) | |
| 485 | +{ | |
| 486 | + char cc[NAMELEN], *p, *q, *r; | |
| 487 | + int n; | |
| 488 | + | |
| 489 | + sprint(cc, "%s%d", class, ctlrno); | |
| 490 | + for(n = 0; n < nconf; n++){ | |
| 491 | + if(cistrncmp(confname[n], cc, NAMELEN)) | |
| 492 | + continue; | |
| 493 | + isa->nopt = 0; | |
| 494 | + p = confval[n]; | |
| 495 | + while(*p){ | |
| 496 | + while(*p == ' ' || *p == '\t') | |
| 497 | + p++; | |
| 498 | + if(*p == '\0') | |
| 499 | + break; | |
| 500 | + if(cistrncmp(p, "type=", 5) == 0){ | |
| 501 | + p += 5; | |
| 502 | + for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){ | |
| 503 | + if(*p == '\0' || *p == ' ' || *p == '\t') | |
| 504 | + break; | |
| 505 | + *q = *p++; | |
| 506 | + } | |
| 507 | + *q = '\0'; | |
| 508 | + } | |
| 509 | + else if(cistrncmp(p, "port=", 5) == 0) | |
| 510 | + isa->port = strtoul(p+5, &p, 0); | |
| 511 | + else if(cistrncmp(p, "irq=", 4) == 0) | |
| 512 | + isa->irq = strtoul(p+4, &p, 0); | |
| 513 | + else if(cistrncmp(p, "mem=", 4) == 0) | |
| 514 | + isa->mem = strtoul(p+4, &p, 0); | |
| 515 | + else if(cistrncmp(p, "size=", 5) == 0) | |
| 516 | + isa->size = strtoul(p+5, &p, 0); | |
| 517 | + else if(cistrncmp(p, "ea=", 3) == 0){ | |
| 518 | + if(parseether(isa->ea, p+3) == -1) | |
| 519 | + memset(isa->ea, 0, 6); | |
| 520 | + } | |
| 521 | + else if(isa->nopt < NISAOPT){ | |
| 522 | + r = isa->opt[isa->nopt]; | |
| 523 | + while(*p && *p != ' ' && *p != '\t'){ | |
| 524 | + *r++ = *p++; | |
| 525 | + if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1) | |
| 526 | + break; | |
| 527 | + } | |
| 528 | + *r = '\0'; | |
| 529 | + isa->nopt++; | |
| 530 | + } | |
| 531 | + while(*p && *p != ' ' && *p != '\t') | |
| 532 | + p++; | |
| 533 | + } | |
| 534 | + return 1; | |
| 535 | + } | |
| 536 | + return 0; | |
| 537 | +} | |
| @@ -0,0 +1,236 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "io.h" | |
| 7 | + | |
| 8 | +IOQ consiq; | |
| 9 | +IOQ consoq; | |
| 10 | + | |
| 11 | +static int useuart; | |
| 12 | + | |
| 13 | +int debug = 0; | |
| 14 | + | |
| 15 | +void | |
| 16 | +kbdchar(int c) | |
| 17 | +{ | |
| 18 | + c &= 0x7F; | |
| 19 | + if(c == 0x10) | |
| 20 | + warp86("\n^P\n", 0); | |
| 21 | + if(c == 0x12) | |
| 22 | + debug = !debug; | |
| 23 | + consiq.putc(&consiq, c); | |
| 24 | +} | |
| 25 | + | |
| 26 | +static int | |
| 27 | +consputc(void) | |
| 28 | +{ | |
| 29 | + return consoq.getc(&consoq); | |
| 30 | +} | |
| 31 | + | |
| 32 | +void | |
| 33 | +kbdinit(void) | |
| 34 | +{ | |
| 35 | + i8042init(); | |
| 36 | + qinit(&consiq); | |
| 37 | +} | |
| 38 | + | |
| 39 | +void | |
| 40 | +consinit(char* name, char* speed) | |
| 41 | +{ | |
| 42 | + int baud, port; | |
| 43 | + | |
| 44 | + if(name == nil || cistrcmp(name, "cga") == 0) | |
| 45 | + return; | |
| 46 | + port = strtoul(name, 0, 0); | |
| 47 | + if(port < 0 || port > 1) | |
| 48 | + return; | |
| 49 | + if(speed == nil || (baud = strtoul(speed, 0, 0)) == 0) | |
| 50 | + baud = 9600; | |
| 51 | + | |
| 52 | + qinit(&consoq); | |
| 53 | + | |
| 54 | + uartspecial(port, kbdchar, consputc, baud); | |
| 55 | + useuart = 1; | |
| 56 | + uartputs(&consoq, "\n", 1); | |
| 57 | +} | |
| 58 | + | |
| 59 | +void | |
| 60 | +consdrain(void) | |
| 61 | +{ | |
| 62 | + if(useuart) | |
| 63 | + uartdrain(); | |
| 64 | +} | |
| 65 | + | |
| 66 | +void | |
| 67 | +consputs(char* s, int n) | |
| 68 | +{ | |
| 69 | + cgascreenputs(s, n); | |
| 70 | + if(useuart) | |
| 71 | + uartputs(&consoq, s, n); | |
| 72 | +} | |
| 73 | + | |
| 74 | +void | |
| 75 | +warp86(char* s, ulong) | |
| 76 | +{ | |
| 77 | + if(s != nil) | |
| 78 | + print(s); | |
| 79 | + spllo(); | |
| 80 | + consdrain(); | |
| 81 | + | |
| 82 | + i8042reset(); | |
| 83 | + print("Takes a licking and keeps on ticking...\n"); | |
| 84 | + for(;;) | |
| 85 | + idle(); | |
| 86 | +} | |
| 87 | + | |
| 88 | +static int | |
| 89 | +getline(char *buf, int size, int timeout) | |
| 90 | +{ | |
| 91 | + int c, i=0; | |
| 92 | + ulong start; | |
| 93 | + char echo; | |
| 94 | + | |
| 95 | + for (;;) { | |
| 96 | + start = m->ticks; | |
| 97 | + do{ | |
| 98 | + /* timeout seconds to first char */ | |
| 99 | + if(timeout && ((m->ticks - start) > timeout*HZ)) | |
| 100 | + return -2; | |
| 101 | + c = consiq.getc(&consiq); | |
| 102 | + }while(c == -1); | |
| 103 | + timeout = 0; | |
| 104 | + | |
| 105 | + if(c == '\r') | |
| 106 | + c = '\n'; /* turn carriage return into newline */ | |
| 107 | + if(c == '\177') | |
| 108 | + c = '\010'; /* turn delete into backspace */ | |
| 109 | + if(c == '\025') | |
| 110 | + echo = '\n'; /* echo ^U as a newline */ | |
| 111 | + else | |
| 112 | + echo = c; | |
| 113 | + consputs(&echo, 1); | |
| 114 | + | |
| 115 | + if(c == '\010'){ | |
| 116 | + if(i > 0) | |
| 117 | + i--; /* bs deletes last character */ | |
| 118 | + continue; | |
| 119 | + } | |
| 120 | + /* a newline ends a line */ | |
| 121 | + if (c == '\n') | |
| 122 | + break; | |
| 123 | + /* ^U wipes out the line */ | |
| 124 | + if (c =='\025') | |
| 125 | + return -1; | |
| 126 | + if(i == size) | |
| 127 | + return size; | |
| 128 | + buf[i++] = c; | |
| 129 | + } | |
| 130 | + buf[i] = 0; | |
| 131 | + return i; | |
| 132 | +} | |
| 133 | + | |
| 134 | +int | |
| 135 | +getstr(char *prompt, char *buf, int size, char *def, int timeout) | |
| 136 | +{ | |
| 137 | + int len, isdefault; | |
| 138 | + char pbuf[PRINTSIZE]; | |
| 139 | + | |
| 140 | + buf[0] = 0; | |
| 141 | + isdefault = (def && *def); | |
| 142 | + if(isdefault == 0){ | |
| 143 | + timeout = 0; | |
| 144 | + sprint(pbuf, "%s: ", prompt); | |
| 145 | + } | |
| 146 | + else if(timeout) | |
| 147 | + sprint(pbuf, "%s[default==%s (%ds timeout)]: ", prompt, def, timeout); | |
| 148 | + else | |
| 149 | + sprint(pbuf, "%s[default==%s]: ", prompt, def); | |
| 150 | + for (;;) { | |
| 151 | + print(pbuf); | |
| 152 | + len = getline(buf, size, timeout); | |
| 153 | + switch(len){ | |
| 154 | + case 0: | |
| 155 | + /* RETURN */ | |
| 156 | + if(isdefault) | |
| 157 | + break; | |
| 158 | + continue; | |
| 159 | + case -1: | |
| 160 | + /* ^U typed */ | |
| 161 | + continue; | |
| 162 | + case -2: | |
| 163 | + /* timeout, use default */ | |
| 164 | + consputs("\n", 1); | |
| 165 | + len = 0; | |
| 166 | + break; | |
| 167 | + default: | |
| 168 | + break; | |
| 169 | + } | |
| 170 | + if(len >= size){ | |
| 171 | + print("line too long\n"); | |
| 172 | + continue; | |
| 173 | + } | |
| 174 | + break; | |
| 175 | + } | |
| 176 | + if(len == 0 && isdefault) | |
| 177 | + strcpy(buf, def); | |
| 178 | + return 0; | |
| 179 | +} | |
| 180 | + | |
| 181 | +int | |
| 182 | +print(char *fmt, ...) | |
| 183 | +{ | |
| 184 | + int n; | |
| 185 | + va_list arg; | |
| 186 | + char buf[PRINTSIZE]; | |
| 187 | + | |
| 188 | + va_start(arg, fmt); | |
| 189 | + n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; | |
| 190 | + va_end(arg); | |
| 191 | + consputs(buf, n); | |
| 192 | + | |
| 193 | + return n; | |
| 194 | +} | |
| 195 | + | |
| 196 | +int | |
| 197 | +sprint(char *s, char *fmt, ...) | |
| 198 | +{ | |
| 199 | + int n; | |
| 200 | + va_list arg; | |
| 201 | + | |
| 202 | + va_start(arg, fmt); | |
| 203 | + n = vseprint(s, s+PRINTSIZE, fmt, arg) - s; | |
| 204 | + va_end(arg); | |
| 205 | + | |
| 206 | + return n; | |
| 207 | +} | |
| 208 | + | |
| 209 | +void | |
| 210 | +panic(char *fmt, ...) | |
| 211 | +{ | |
| 212 | + int n; | |
| 213 | + va_list arg; | |
| 214 | + char buf[PRINTSIZE]; | |
| 215 | + | |
| 216 | + strcpy(buf, "panic: "); | |
| 217 | + va_start(arg, fmt); | |
| 218 | + n = vseprint(buf+7, buf+sizeof(buf), fmt, arg) - buf; | |
| 219 | + va_end(arg); | |
| 220 | + buf[n] = '\n'; | |
| 221 | + consputs(buf, n+1); | |
| 222 | + | |
| 223 | +//floppymemwrite(); | |
| 224 | +//splhi(); for(;;); | |
| 225 | + if(etherdetach) | |
| 226 | + etherdetach(); | |
| 227 | + if(sddetach) | |
| 228 | + sddetach(); | |
| 229 | + | |
| 230 | + consputs("\nPress almost any key to reset...", 32); | |
| 231 | + spllo(); | |
| 232 | + while(consiq.getc(&consiq) == -1) | |
| 233 | + ; | |
| 234 | + | |
| 235 | + warp86(nil, 0); | |
| 236 | +} | |
| @@ -0,0 +1,212 @@ | ||
| 1 | +typedef struct List { | |
| 2 | + void *next; | |
| 3 | +} List; | |
| 4 | + | |
| 5 | +typedef struct Alarm Alarm; | |
| 6 | +typedef struct Alarm { | |
| 7 | + List; | |
| 8 | + int busy; | |
| 9 | + long dt; | |
| 10 | + void (*f)(Alarm*); | |
| 11 | + void *arg; | |
| 12 | +} Alarm; | |
| 13 | + | |
| 14 | +typedef struct Apminfo { | |
| 15 | + int haveinfo; | |
| 16 | + int ax; | |
| 17 | + int cx; | |
| 18 | + int dx; | |
| 19 | + int di; | |
| 20 | + int ebx; | |
| 21 | + int esi; | |
| 22 | +} Apminfo; | |
| 23 | + | |
| 24 | +typedef struct Block Block; | |
| 25 | +struct Block { | |
| 26 | + Block* next; | |
| 27 | + uchar* rp; /* first unconsumed byte */ | |
| 28 | + uchar* wp; /* first empty byte */ | |
| 29 | + uchar* lim; /* 1 past the end of the buffer */ | |
| 30 | + uchar* base; /* start of the buffer */ | |
| 31 | + ulong flag; | |
| 32 | +}; | |
| 33 | +#define BLEN(s) ((s)->wp - (s)->rp) | |
| 34 | + | |
| 35 | +typedef struct IOQ IOQ; | |
| 36 | +typedef struct IOQ { | |
| 37 | + uchar buf[4096]; | |
| 38 | + uchar *in; | |
| 39 | + uchar *out; | |
| 40 | + int state; | |
| 41 | + int (*getc)(IOQ*); | |
| 42 | + int (*putc)(IOQ*, int); | |
| 43 | + void *ptr; | |
| 44 | +}; | |
| 45 | + | |
| 46 | +enum { | |
| 47 | + Eaddrlen = 6, | |
| 48 | + /* next two exclude 4-byte ether CRC */ | |
| 49 | + ETHERMINTU = 60, /* minimum transmit size */ | |
| 50 | + ETHERMAXTU = 1514, /* maximum transmit size */ | |
| 51 | + ETHERHDRSIZE = 14, /* size of an ethernet header */ | |
| 52 | + | |
| 53 | + MaxEther = 6, | |
| 54 | +}; | |
| 55 | + | |
| 56 | +typedef struct { | |
| 57 | + uchar d[Eaddrlen]; | |
| 58 | + uchar s[Eaddrlen]; | |
| 59 | + uchar type[2]; | |
| 60 | + uchar data[1500]; | |
| 61 | + uchar crc[4]; | |
| 62 | +} Etherpkt; | |
| 63 | + | |
| 64 | +extern uchar broadcast[Eaddrlen]; | |
| 65 | + | |
| 66 | +typedef struct Ureg Ureg; | |
| 67 | + | |
| 68 | +typedef struct Segdesc { | |
| 69 | + ulong d0; | |
| 70 | + ulong d1; | |
| 71 | +} Segdesc; | |
| 72 | + | |
| 73 | +typedef struct Mach { | |
| 74 | + ulong ticks; /* of the clock since boot time */ | |
| 75 | + void *alarm; /* alarms bound to this clock */ | |
| 76 | +} Mach; | |
| 77 | + | |
| 78 | +extern Mach *m; | |
| 79 | + | |
| 80 | +#define I_MAGIC ((((4*11)+0)*11)+7) | |
| 81 | + | |
| 82 | +typedef struct Exec Exec; | |
| 83 | +struct Exec | |
| 84 | +{ | |
| 85 | + uchar magic[4]; /* magic number */ | |
| 86 | + uchar text[4]; /* size of text segment */ | |
| 87 | + uchar data[4]; /* size of initialized data */ | |
| 88 | + uchar bss[4]; /* size of uninitialized data */ | |
| 89 | + uchar syms[4]; /* size of symbol table */ | |
| 90 | + uchar entry[4]; /* entry point */ | |
| 91 | + uchar spsz[4]; /* size of sp/pc offset table */ | |
| 92 | + uchar pcsz[4]; /* size of pc/line number table */ | |
| 93 | +}; | |
| 94 | + | |
| 95 | +/* | |
| 96 | + * a parsed .ini line | |
| 97 | + */ | |
| 98 | +#define ISAOPTLEN 32 | |
| 99 | +#define NISAOPT 8 | |
| 100 | + | |
| 101 | +typedef struct ISAConf { | |
| 102 | + char type[NAMELEN]; | |
| 103 | + ulong port; | |
| 104 | + ulong irq; | |
| 105 | + ulong mem; | |
| 106 | + ulong size; | |
| 107 | + uchar ea[6]; | |
| 108 | + | |
| 109 | + int nopt; | |
| 110 | + char opt[NISAOPT][ISAOPTLEN]; | |
| 111 | +} ISAConf; | |
| 112 | + | |
| 113 | +typedef struct Pcidev Pcidev; | |
| 114 | +typedef struct PCMmap PCMmap; | |
| 115 | + | |
| 116 | +#define BOOTLINE ((char*)CONFADDR) | |
| 117 | + | |
| 118 | +enum { | |
| 119 | + MB = (1024*1024), | |
| 120 | +}; | |
| 121 | +#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1)) | |
| 122 | + | |
| 123 | + | |
| 124 | +typedef struct Type Type; | |
| 125 | +typedef struct Medium Medium; | |
| 126 | +typedef struct Boot Boot; | |
| 127 | + | |
| 128 | +enum { /* type */ | |
| 129 | + Tnil = 0x00, | |
| 130 | + | |
| 131 | + Tfloppy = 0x01, | |
| 132 | + Tsd = 0x02, | |
| 133 | + Tether = 0x03, | |
| 134 | + Tcd = 0x04, | |
| 135 | + | |
| 136 | + Tany = -1, | |
| 137 | +}; | |
| 138 | + | |
| 139 | +enum { /* name and flag */ | |
| 140 | + Fnone = 0x00, | |
| 141 | + | |
| 142 | + Nfs = 0x00, | |
| 143 | + Ffs = (1<<Nfs), | |
| 144 | + Nboot = 0x01, | |
| 145 | + Fboot = (1<<Nboot), | |
| 146 | + Nbootp = 0x02, | |
| 147 | + Fbootp = (1<<Nbootp), | |
| 148 | + NName = 3, | |
| 149 | + | |
| 150 | + Fany = Fbootp|Fboot|Ffs, | |
| 151 | + | |
| 152 | + Fini = 0x10, | |
| 153 | + Fprobe = 0x80, | |
| 154 | +}; | |
| 155 | + | |
| 156 | +typedef struct Type { | |
| 157 | + int type; | |
| 158 | + int flag; | |
| 159 | + int (*init)(void); | |
| 160 | + void (*initdev)(int, char*); | |
| 161 | + void* (*getfspart)(int, char*, int); /* actually returns Dos* */ | |
| 162 | + void (*addconf)(int); | |
| 163 | + int (*boot)(int, char*, Boot*); | |
| 164 | + void (*printdevs)(int); | |
| 165 | + char** parts; | |
| 166 | + char** inis; | |
| 167 | + int mask; | |
| 168 | + Medium* media; | |
| 169 | +} Type; | |
| 170 | + | |
| 171 | +extern void (*etherdetach)(void); | |
| 172 | +extern void (*floppydetach)(void); | |
| 173 | +extern void (*sddetach)(void); | |
| 174 | + | |
| 175 | +typedef struct Lock { /* for ilock, iunlock */ | |
| 176 | + int locked; | |
| 177 | + int spl; | |
| 178 | +} Lock; | |
| 179 | + | |
| 180 | +enum { /* returned by bootpass */ | |
| 181 | + MORE, ENOUGH, FAIL | |
| 182 | +}; | |
| 183 | +enum { | |
| 184 | + INITKERNEL, | |
| 185 | + READEXEC, | |
| 186 | + READ9TEXT, | |
| 187 | + READ9DATA, | |
| 188 | + READGZIP, | |
| 189 | + READEHDR, | |
| 190 | + READPHDR, | |
| 191 | + READEPAD, | |
| 192 | + READEDATA, | |
| 193 | + TRYBOOT, | |
| 194 | + INIT9LOAD, | |
| 195 | + READ9LOAD, | |
| 196 | + FAILED | |
| 197 | +}; | |
| 198 | + | |
| 199 | +struct Boot { | |
| 200 | + int state; | |
| 201 | + | |
| 202 | + Exec exec; | |
| 203 | + char *bp; /* base ptr */ | |
| 204 | + char *wp; /* write ptr */ | |
| 205 | + char *ep; /* end ptr */ | |
| 206 | +}; | |
| 207 | + | |
| 208 | +extern int debug; | |
| 209 | +extern Apminfo apm; | |
| 210 | +extern char *defaultpartition; | |
| 211 | +extern int iniread; | |
| 212 | +extern int pxe; | |
| @@ -0,0 +1,853 @@ | ||
| 1 | +#include <u.h> | |
| 2 | + | |
| 3 | +#include "lib.h" | |
| 4 | +#include "mem.h" | |
| 5 | +#include "dat.h" | |
| 6 | +#include "fns.h" | |
| 7 | +#include "io.h" | |
| 8 | +#include "ureg.h" | |
| 9 | + | |
| 10 | +#include "fs.h" | |
| 11 | +#include "devfloppy.h" | |
| 12 | + | |
| 13 | + | |
| 14 | +/* Intel 82077A (8272A compatible) floppy controller */ | |
| 15 | + | |
| 16 | +/* This module expects the following functions to be defined | |
| 17 | + * elsewhere: | |
| 18 | + * | |
| 19 | + * inb() | |
| 20 | + * outb() | |
| 21 | + * floppyexec() | |
| 22 | + * floppyeject() | |
| 23 | + * floppysetup0() | |
| 24 | + * floppysetup1() | |
| 25 | + * dmainit() | |
| 26 | + * dmasetup() | |
| 27 | + * dmaend() | |
| 28 | + * | |
| 29 | + * On DMA systems, floppyexec() should be an empty function; | |
| 30 | + * on non-DMA systems, dmaend() should be an empty function; | |
| 31 | + * dmasetup() may enforce maximum transfer sizes. | |
| 32 | + */ | |
| 33 | + | |
| 34 | +enum { | |
| 35 | + /* file types */ | |
| 36 | + Qdir= 0, | |
| 37 | + Qdata= (1<<2), | |
| 38 | + Qctl= (2<<2), | |
| 39 | + Qmask= (3<<2), | |
| 40 | + | |
| 41 | + DMAchan= 2, /* floppy dma channel */ | |
| 42 | +}; | |
| 43 | + | |
| 44 | +#define DPRINT if(0)print | |
| 45 | + | |
| 46 | +FType floppytype[] = | |
| 47 | +{ | |
| 48 | + { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, }, | |
| 49 | + { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, }, | |
| 50 | + { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, }, | |
| 51 | + { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, }, | |
| 52 | + { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, }, | |
| 53 | + { "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, }, | |
| 54 | + { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, }, | |
| 55 | +}; | |
| 56 | + | |
| 57 | +/* | |
| 58 | + * bytes per sector encoding for the controller. | |
| 59 | + * - index for b2c is is (bytes per sector/128). | |
| 60 | + * - index for c2b is code from b2c | |
| 61 | + */ | |
| 62 | +static int b2c[] = | |
| 63 | +{ | |
| 64 | +[1] 0, | |
| 65 | +[2] 1, | |
| 66 | +[4] 2, | |
| 67 | +[8] 3, | |
| 68 | +}; | |
| 69 | +static int c2b[] = | |
| 70 | +{ | |
| 71 | + 128, | |
| 72 | + 256, | |
| 73 | + 512, | |
| 74 | + 1024, | |
| 75 | +}; | |
| 76 | + | |
| 77 | +FController fl; | |
| 78 | + | |
| 79 | +#define MOTORBIT(i) (1<<((i)+4)) | |
| 80 | + | |
| 81 | +/* | |
| 82 | + * predeclared | |
| 83 | + */ | |
| 84 | +static int cmddone(void*); | |
| 85 | +static void floppyformat(FDrive*, char*); | |
| 86 | +static void floppykproc(void*); | |
| 87 | +static void floppypos(FDrive*,long); | |
| 88 | +static int floppyrecal(FDrive*); | |
| 89 | +static int floppyresult(void); | |
| 90 | +static void floppyrevive(void); | |
| 91 | +static vlong pcfloppyseek(FDrive*, vlong); | |
| 92 | +static int floppysense(void); | |
| 93 | +static void floppywait(int); | |
| 94 | +static long floppyxfer(FDrive*, int, void*, long, long); | |
| 95 | + | |
| 96 | +static void | |
| 97 | +fldump(void) | |
| 98 | +{ | |
| 99 | + DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb), | |
| 100 | + inb(Pdor), inb(Pmsr), inb(Pdir)); | |
| 101 | +} | |
| 102 | + | |
| 103 | +static void | |
| 104 | +floppyalarm(Alarm* a) | |
| 105 | +{ | |
| 106 | + FDrive *dp; | |
| 107 | + | |
| 108 | + for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){ | |
| 109 | + if((fl.motor&MOTORBIT(dp->dev)) && TK2SEC(m->ticks - dp->lasttouched) > 5) | |
| 110 | + floppyoff(dp); | |
| 111 | + } | |
| 112 | + | |
| 113 | + alarm(5*1000, floppyalarm, 0); | |
| 114 | + cancel(a); | |
| 115 | +} | |
| 116 | + | |
| 117 | +/* | |
| 118 | + * set floppy drive to its default type | |
| 119 | + */ | |
| 120 | +static void | |
| 121 | +floppysetdef(FDrive *dp) | |
| 122 | +{ | |
| 123 | + FType *t; | |
| 124 | + | |
| 125 | + for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++) | |
| 126 | + if(dp->dt == t->dt){ | |
| 127 | + dp->t = t; | |
| 128 | + break; | |
| 129 | + } | |
| 130 | +} | |
| 131 | + | |
| 132 | +static void | |
| 133 | +_floppydetach(void) | |
| 134 | +{ | |
| 135 | + /* | |
| 136 | + * stop the motors | |
| 137 | + */ | |
| 138 | + fl.motor = 0; | |
| 139 | + delay(10); | |
| 140 | + outb(Pdor, fl.motor | Fintena | Fena); | |
| 141 | + delay(10); | |
| 142 | +} | |
| 143 | + | |
| 144 | +int | |
| 145 | +floppyinit(void) | |
| 146 | +{ | |
| 147 | + FDrive *dp; | |
| 148 | + FType *t; | |
| 149 | + ulong maxtsize; | |
| 150 | + int mask; | |
| 151 | + | |
| 152 | + dmainit(DMAchan); | |
| 153 | + | |
| 154 | + floppysetup0(&fl); | |
| 155 | + | |
| 156 | + /* | |
| 157 | + * init dependent parameters | |
| 158 | + */ | |
| 159 | + maxtsize = 0; | |
| 160 | + for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){ | |
| 161 | + t->cap = t->bytes * t->heads * t->sectors * t->tracks; | |
| 162 | + t->bcode = b2c[t->bytes/128]; | |
| 163 | + t->tsize = t->bytes * t->sectors; | |
| 164 | + if(maxtsize < t->tsize) | |
| 165 | + maxtsize = t->tsize; | |
| 166 | + } | |
| 167 | + | |
| 168 | + fl.selected = fl.d; | |
| 169 | + | |
| 170 | + floppydetach = _floppydetach; | |
| 171 | + floppydetach(); | |
| 172 | + | |
| 173 | + /* | |
| 174 | + * init drives | |
| 175 | + */ | |
| 176 | + mask = 0; | |
| 177 | + for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){ | |
| 178 | + dp->dev = dp - fl.d; | |
| 179 | + if(dp->dt == Tnone) | |
| 180 | + continue; | |
| 181 | + mask |= 1<<dp->dev; | |
| 182 | + floppysetdef(dp); | |
| 183 | + dp->cyl = -1; /* because we don't know */ | |
| 184 | + dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024); | |
| 185 | + dp->ccyl = -1; | |
| 186 | + dp->vers = 0; | |
| 187 | + dp->maxtries = 5; | |
| 188 | + } | |
| 189 | + | |
| 190 | + /* | |
| 191 | + * first operation will recalibrate | |
| 192 | + */ | |
| 193 | + fl.confused = 1; | |
| 194 | + | |
| 195 | + floppysetup1(&fl); | |
| 196 | + | |
| 197 | + /* to turn the motor off when inactive */ | |
| 198 | + alarm(5*1000, floppyalarm, 0); | |
| 199 | + | |
| 200 | + return mask; | |
| 201 | +} | |
| 202 | + | |
| 203 | +void | |
| 204 | +floppyinitdev(int i, char *name) | |
| 205 | +{ | |
| 206 | + if(i >= fl.ndrive) | |
| 207 | + panic("floppyinitdev"); | |
| 208 | + sprint(name, "fd%d", i); | |
| 209 | +} | |
| 210 | + | |
| 211 | +void | |
| 212 | +floppyprintdevs(int i) | |
| 213 | +{ | |
| 214 | + if(i >= fl.ndrive) | |
| 215 | + panic("floppyprintdevs"); | |
| 216 | + print(" fd%d", i); | |
| 217 | +} | |
| 218 | + | |
| 219 | +int | |
| 220 | +floppyboot(int dev, char *file, Boot *b) | |
| 221 | +{ | |
| 222 | + Fs *fs; | |
| 223 | + | |
| 224 | + if(strncmp(file, "dos!", 4) == 0) | |
| 225 | + file += 4; | |
| 226 | + else if(strchr(file, '!') || strcmp(file, "")==0) { | |
| 227 | + print("syntax is fd0!file\n"); | |
| 228 | + return -1; | |
| 229 | + } | |
| 230 | + | |
| 231 | + fs = floppygetfspart(dev, "dos", 1); | |
| 232 | + if(fs == nil) | |
| 233 | + return -1; | |
| 234 | + | |
| 235 | + return fsboot(fs, file, b); | |
| 236 | +} | |
| 237 | + | |
| 238 | +void | |
| 239 | +floppyprintbootdevs(int dev) | |
| 240 | +{ | |
| 241 | + print(" fd%d", dev); | |
| 242 | +} | |
| 243 | + | |
| 244 | +/* | |
| 245 | + * check if the floppy has been replaced under foot. cause | |
| 246 | + * an error if it has. | |
| 247 | + * | |
| 248 | + * a seek and a read clears the condition. this was determined | |
| 249 | + * experimentally, there has to be a better way. | |
| 250 | + * | |
| 251 | + * if the read fails, cycle through the possible floppy | |
| 252 | + * density till one works or we've cycled through all | |
| 253 | + * possibilities for this drive. | |
| 254 | + */ | |
| 255 | +static int | |
| 256 | +changed(FDrive *dp) | |
| 257 | +{ | |
| 258 | + FType *start; | |
| 259 | + | |
| 260 | + /* | |
| 261 | + * if floppy has changed or first time through | |
| 262 | + */ | |
| 263 | + if((inb(Pdir)&Fchange) || dp->vers == 0){ | |
| 264 | + DPRINT("changed\n"); | |
| 265 | + fldump(); | |
| 266 | + dp->vers++; | |
| 267 | + floppysetdef(dp); | |
| 268 | + dp->maxtries = 3; | |
| 269 | + start = dp->t; | |
| 270 | + | |
| 271 | + /* flopppyon fails if there's no drive */ | |
| 272 | + dp->confused = 1; /* make floppyon recal */ | |
| 273 | + if(floppyon(dp) < 0) | |
| 274 | + return -1; | |
| 275 | + | |
| 276 | + pcfloppyseek(dp, dp->t->heads*dp->t->tsize); | |
| 277 | + | |
| 278 | + while(floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize) <= 0){ | |
| 279 | + | |
| 280 | + /* | |
| 281 | + * if the xfer attempt doesn't clear the changed bit, | |
| 282 | + * there's no floppy in the drive | |
| 283 | + */ | |
| 284 | + if(inb(Pdir)&Fchange) | |
| 285 | + return -1; | |
| 286 | + | |
| 287 | + while(++dp->t){ | |
| 288 | + if(dp->t == &floppytype[nelem(floppytype)]) | |
| 289 | + dp->t = floppytype; | |
| 290 | + if(dp->dt == dp->t->dt) | |
| 291 | + break; | |
| 292 | + } | |
| 293 | + | |
| 294 | + /* flopppyon fails if there's no drive */ | |
| 295 | + if(floppyon(dp) < 0) | |
| 296 | + return -1; | |
| 297 | + | |
| 298 | + DPRINT("changed: trying %s\n", dp->t->name); | |
| 299 | + fldump(); | |
| 300 | + if(dp->t == start) | |
| 301 | + return -1; | |
| 302 | + } | |
| 303 | + } | |
| 304 | + | |
| 305 | + return 0; | |
| 306 | +} | |
| 307 | + | |
| 308 | +static int | |
| 309 | +readtrack(FDrive *dp, int cyl, int head) | |
| 310 | +{ | |
| 311 | + int i, nn, sofar; | |
| 312 | + ulong pos; | |
| 313 | + | |
| 314 | + nn = dp->t->tsize; | |
| 315 | + if(dp->ccyl==cyl && dp->chead==head) | |
| 316 | + return nn; | |
| 317 | + pos = (cyl*dp->t->heads+head) * nn; | |
| 318 | + for(sofar = 0; sofar < nn; sofar += i){ | |
| 319 | + dp->ccyl = -1; | |
| 320 | + i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar); | |
| 321 | + if(i <= 0) | |
| 322 | + return -1; | |
| 323 | + } | |
| 324 | + dp->ccyl = cyl; | |
| 325 | + dp->chead = head; | |
| 326 | + return nn; | |
| 327 | +} | |
| 328 | + | |
| 329 | +long | |
| 330 | +floppyread(Fs *fs, void *a, long n) | |
| 331 | +{ | |
| 332 | + FDrive *dp; | |
| 333 | + long rv, offset; | |
| 334 | + int sec, head, cyl; | |
| 335 | + long len; | |
| 336 | + uchar *aa; | |
| 337 | + | |
| 338 | + aa = a; | |
| 339 | + dp = &fl.d[fs->dev]; | |
| 340 | + | |
| 341 | + offset = dp->offset; | |
| 342 | + floppyon(dp); | |
| 343 | + if(changed(dp)) | |
| 344 | + return -1; | |
| 345 | + | |
| 346 | + for(rv = 0; rv < n; rv += len){ | |
| 347 | + /* | |
| 348 | + * all xfers come out of the track cache | |
| 349 | + */ | |
| 350 | + dp->len = n - rv; | |
| 351 | + floppypos(dp, offset+rv); | |
| 352 | + cyl = dp->tcyl; | |
| 353 | + head = dp->thead; | |
| 354 | + len = dp->len; | |
| 355 | + sec = dp->tsec; | |
| 356 | + if(readtrack(dp, cyl, head) < 0) | |
| 357 | + break; | |
| 358 | + memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len); | |
| 359 | + } | |
| 360 | + dp->offset = offset+rv; | |
| 361 | + | |
| 362 | + return rv; | |
| 363 | +} | |
| 364 | + | |
| 365 | +void* | |
| 366 | +floppygetfspart(int i, char *name, int chatty) | |
| 367 | +{ | |
| 368 | + static Fs fs; | |
| 369 | + | |
| 370 | + if(strcmp(name, "dos") != 0){ | |
| 371 | + if(chatty) | |
| 372 | + print("unknown partition fd%d!%s (use fd%d!dos)\n", i, name, i); | |
| 373 | + return nil; | |
| 374 | + } | |
| 375 | + | |
| 376 | + fs.dev = i; | |
| 377 | + fs.diskread = floppyread; | |
| 378 | + fs.diskseek = floppyseek; | |
| 379 | + | |
| 380 | + /* sometimes we get spurious errors and doing it again works */ | |
| 381 | + if(dosinit(&fs) < 0 && dosinit(&fs) < 0){ | |
| 382 | + if(chatty) | |
| 383 | + print("fd%d!%s does not contain a FAT file system\n", i, name); | |
| 384 | + return nil; | |
| 385 | + } | |
| 386 | + return &fs; | |
| 387 | +} | |
| 388 | + | |
| 389 | +static int | |
| 390 | +return0(void*) | |
| 391 | +{ | |
| 392 | + return 0; | |
| 393 | +} | |
| 394 | + | |
| 395 | +static void | |
| 396 | +timedsleep(int (*f)(void*), void* arg, int ms) | |
| 397 | +{ | |
| 398 | + int s; | |
| 399 | + ulong end; | |
| 400 | + | |
| 401 | + end = m->ticks + 1 + MS2TK(ms); | |
| 402 | + while(m->ticks < end && !(*f)(arg)){ | |
| 403 | + s = spllo(); | |
| 404 | + delay(10); | |
| 405 | + splx(s); | |
| 406 | + } | |
| 407 | +} | |
| 408 | + | |
| 409 | +/* | |
| 410 | + * start a floppy drive's motor. | |
| 411 | + */ | |
| 412 | +static int | |
| 413 | +floppyon(FDrive *dp) | |
| 414 | +{ | |
| 415 | + int alreadyon; | |
| 416 | + int tries; | |
| 417 | + | |
| 418 | + if(fl.confused) | |
| 419 | + floppyrevive(); | |
| 420 | + | |
| 421 | + /* start motor and select drive */ | |
| 422 | + dp->lasttouched = m->ticks; | |
| 423 | + alreadyon = fl.motor & MOTORBIT(dp->dev); | |
| 424 | + if(!alreadyon){ | |
| 425 | + fl.motor |= MOTORBIT(dp->dev); | |
| 426 | + outb(Pdor, fl.motor | Fintena | Fena | dp->dev); | |
| 427 | + /* wait for drive to spin up */ | |
| 428 | + timedsleep(return0, 0, 750); | |
| 429 | + | |
| 430 | + /* clear any pending interrupts */ | |
| 431 | + floppysense(); | |
| 432 | + } | |
| 433 | + | |
| 434 | + /* set transfer rate */ | |
| 435 | + if(fl.rate != dp->t->rate){ | |
| 436 | + fl.rate = dp->t->rate; | |
| 437 | + outb(Pdsr, fl.rate); | |
| 438 | + } | |
| 439 | + | |
| 440 | + /* get drive to a known cylinder */ | |
| 441 | + if(dp->confused) | |
| 442 | + for(tries = 0; tries < 4; tries++) | |
| 443 | + if(floppyrecal(dp) >= 0) | |
| 444 | + break; | |
| 445 | + dp->lasttouched = m->ticks; | |
| 446 | + fl.selected = dp; | |
| 447 | + if(dp->confused) | |
| 448 | + return -1; | |
| 449 | + return 0; | |
| 450 | +} | |
| 451 | + | |
| 452 | +/* | |
| 453 | + * stop the floppy if it hasn't been used in 5 seconds | |
| 454 | + */ | |
| 455 | +static void | |
| 456 | +floppyoff(FDrive *dp) | |
| 457 | +{ | |
| 458 | + fl.motor &= ~MOTORBIT(dp->dev); | |
| 459 | + outb(Pdor, fl.motor | Fintena | Fena | dp->dev); | |
| 460 | +} | |
| 461 | + | |
| 462 | +/* | |
| 463 | + * send a command to the floppy | |
| 464 | + */ | |
| 465 | +static int | |
| 466 | +floppycmd(void) | |
| 467 | +{ | |
| 468 | + int i; | |
| 469 | + int tries; | |
| 470 | + | |
| 471 | + fl.nstat = 0; | |
| 472 | + for(i = 0; i < fl.ncmd; i++){ | |
| 473 | + for(tries = 0; ; tries++){ | |
| 474 | + if((inb(Pmsr)&(Ffrom|Fready)) == Fready) | |
| 475 | + break; | |
| 476 | + if(tries > 1000){ | |
| 477 | + DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i); | |
| 478 | + fldump(); | |
| 479 | + | |
| 480 | + /* empty fifo, might have been a bad command */ | |
| 481 | + floppyresult(); | |
| 482 | + return -1; | |
| 483 | + } | |
| 484 | + microdelay(1); | |
| 485 | + } | |
| 486 | + outb(Pfdata, fl.cmd[i]); | |
| 487 | + } | |
| 488 | + return 0; | |
| 489 | +} | |
| 490 | + | |
| 491 | +/* | |
| 492 | + * get a command result from the floppy | |
| 493 | + * | |
| 494 | + * when the controller goes ready waiting for a command | |
| 495 | + * (instead of sending results), we're done | |
| 496 | + * | |
| 497 | + */ | |
| 498 | +static int | |
| 499 | +floppyresult(void) | |
| 500 | +{ | |
| 501 | + int i, s; | |
| 502 | + int tries; | |
| 503 | + | |
| 504 | + /* get the result of the operation */ | |
| 505 | + for(i = 0; i < sizeof(fl.stat); i++){ | |
| 506 | + /* wait for status byte */ | |
| 507 | + for(tries = 0; ; tries++){ | |
| 508 | + s = inb(Pmsr)&(Ffrom|Fready); | |
| 509 | + if(s == Fready){ | |
| 510 | + fl.nstat = i; | |
| 511 | + return fl.nstat; | |
| 512 | + } | |
| 513 | + if(s == (Ffrom|Fready)) | |
| 514 | + break; | |
| 515 | + if(tries > 1000){ | |
| 516 | + DPRINT("floppyresult: %d stats\n", i); | |
| 517 | + fldump(); | |
| 518 | + fl.confused = 1; | |
| 519 | + return -1; | |
| 520 | + } | |
| 521 | + microdelay(1); | |
| 522 | + } | |
| 523 | + fl.stat[i] = inb(Pfdata); | |
| 524 | + } | |
| 525 | + fl.nstat = sizeof(fl.stat); | |
| 526 | + return fl.nstat; | |
| 527 | +} | |
| 528 | + | |
| 529 | +/* | |
| 530 | + * calculate physical address of a logical byte offset into the disk | |
| 531 | + * | |
| 532 | + * truncate dp->length if it crosses a track boundary | |
| 533 | + */ | |
| 534 | +static void | |
| 535 | +floppypos(FDrive *dp, long off) | |
| 536 | +{ | |
| 537 | + int lsec; | |
| 538 | + int ltrack; | |
| 539 | + int end; | |
| 540 | + | |
| 541 | + lsec = off/dp->t->bytes; | |
| 542 | + ltrack = lsec/dp->t->sectors; | |
| 543 | + dp->tcyl = ltrack/dp->t->heads; | |
| 544 | + dp->tsec = (lsec % dp->t->sectors) + 1; | |
| 545 | + dp->thead = (lsec/dp->t->sectors) % dp->t->heads; | |
| 546 | + | |
| 547 | + /* | |
| 548 | + * can't read across track boundaries. | |
| 549 | + * if so, decrement the bytes to be read. | |
| 550 | + */ | |
| 551 | + end = (ltrack+1)*dp->t->sectors*dp->t->bytes; | |
| 552 | + if(off+dp->len > end) | |
| 553 | + dp->len = end - off; | |
| 554 | +} | |
| 555 | + | |
| 556 | +/* | |
| 557 | + * get the interrupt cause from the floppy. | |
| 558 | + */ | |
| 559 | +static int | |
| 560 | +floppysense(void) | |
| 561 | +{ | |
| 562 | + fl.ncmd = 0; | |
| 563 | + fl.cmd[fl.ncmd++] = Fsense; | |
| 564 | + if(floppycmd() < 0) | |
| 565 | + return -1; | |
| 566 | + if(floppyresult() < 2){ | |
| 567 | + DPRINT("can't read sense response\n"); | |
| 568 | + fldump(); | |
| 569 | + fl.confused = 1; | |
| 570 | + return -1; | |
| 571 | + } | |
| 572 | + return 0; | |
| 573 | +} | |
| 574 | + | |
| 575 | +static int | |
| 576 | +cmddone(void *a) | |
| 577 | +{ | |
| 578 | + USED(a); | |
| 579 | + return fl.ncmd == 0; | |
| 580 | +} | |
| 581 | + | |
| 582 | +/* | |
| 583 | + * Wait for a floppy interrupt. If none occurs in 5 seconds, we | |
| 584 | + * may have missed one. This only happens on some portables which | |
| 585 | + * do power management behind our backs. Call the interrupt | |
| 586 | + * routine to try to clear any conditions. | |
| 587 | + */ | |
| 588 | +static void | |
| 589 | +floppywait(int slow) | |
| 590 | +{ | |
| 591 | + timedsleep(cmddone, 0, slow ? 5000 : 1000); | |
| 592 | + if(!cmddone(0)){ | |
| 593 | + floppyintr(0); | |
| 594 | + fl.confused = 1; | |
| 595 | + } | |
| 596 | +} | |
| 597 | + | |
| 598 | +/* | |
| 599 | + * we've lost the floppy position, go to cylinder 0. | |
| 600 | + */ | |
| 601 | +static int | |
| 602 | +floppyrecal(FDrive *dp) | |
| 603 | +{ | |
| 604 | + dp->ccyl = -1; | |
| 605 | + dp->cyl = -1; | |
| 606 | + | |
| 607 | + fl.ncmd = 0; | |
| 608 | + fl.cmd[fl.ncmd++] = Frecal; | |
| 609 | + fl.cmd[fl.ncmd++] = dp->dev; | |
| 610 | + if(floppycmd() < 0) | |
| 611 | + return -1; | |
| 612 | + floppywait(1); | |
| 613 | + if(fl.nstat < 2){ | |
| 614 | + DPRINT("recalibrate: confused %ux\n", inb(Pmsr)); | |
| 615 | + fl.confused = 1; | |
| 616 | + return -1; | |
| 617 | + } | |
| 618 | + if((fl.stat[0] & (Codemask|Seekend)) != Seekend){ | |
| 619 | + DPRINT("recalibrate: failed\n"); | |
| 620 | + dp->confused = 1; | |
| 621 | + return -1; | |
| 622 | + } | |
| 623 | + dp->cyl = fl.stat[1]; | |
| 624 | + if(dp->cyl != 0){ | |
| 625 | + DPRINT("recalibrate: wrong cylinder %d\n", dp->cyl); | |
| 626 | + dp->cyl = -1; | |
| 627 | + dp->confused = 1; | |
| 628 | + return -1; | |
| 629 | + } | |
| 630 | + | |
| 631 | + dp->confused = 0; | |
| 632 | + return 0; | |
| 633 | +} | |
| 634 | + | |
| 635 | +/* | |
| 636 | + * if the controller or a specific drive is in a confused state, | |
| 637 | + * reset it and get back to a kown state | |
| 638 | + */ | |
| 639 | +static void | |
| 640 | +floppyrevive(void) | |
| 641 | +{ | |
| 642 | + FDrive *dp; | |
| 643 | + | |
| 644 | + /* | |
| 645 | + * reset the controller if it's confused | |
| 646 | + */ | |
| 647 | + if(fl.confused){ | |
| 648 | + DPRINT("floppyrevive in\n"); | |
| 649 | + fldump(); | |
| 650 | + | |
| 651 | + /* reset controller and turn all motors off */ | |
| 652 | + splhi(); | |
| 653 | + fl.ncmd = 1; | |
| 654 | + fl.cmd[0] = 0; | |
| 655 | + outb(Pdor, 0); | |
| 656 | + delay(10); | |
| 657 | + outb(Pdor, Fintena|Fena); | |
| 658 | + delay(10); | |
| 659 | + spllo(); | |
| 660 | + fl.motor = 0; | |
| 661 | + fl.confused = 0; | |
| 662 | + floppywait(0); | |
| 663 | + | |
| 664 | + /* mark all drives in an unknown state */ | |
| 665 | + for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++) | |
| 666 | + dp->confused = 1; | |
| 667 | + | |
| 668 | + /* set rate to a known value */ | |
| 669 | + outb(Pdsr, 0); | |
| 670 | + fl.rate = 0; | |
| 671 | + | |
| 672 | + DPRINT("floppyrevive out\n"); | |
| 673 | + fldump(); | |
| 674 | + } | |
| 675 | +} | |
| 676 | + | |
| 677 | +/* | |
| 678 | + * seek to the target cylinder | |
| 679 | + * | |
| 680 | + * interrupt, no results | |
| 681 | + */ | |
| 682 | +static vlong | |
| 683 | +pcfloppyseek(FDrive *dp, vlong off) | |
| 684 | +{ | |
| 685 | + floppypos(dp, off); | |
| 686 | + if(dp->cyl == dp->tcyl){ | |
| 687 | + dp->offset = off; | |
| 688 | + return off; | |
| 689 | + } | |
| 690 | + dp->cyl = -1; | |
| 691 | + | |
| 692 | + fl.ncmd = 0; | |
| 693 | + fl.cmd[fl.ncmd++] = Fseek; | |
| 694 | + fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; | |
| 695 | + fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps; | |
| 696 | + if(floppycmd() < 0) | |
| 697 | + return -1; | |
| 698 | + floppywait(1); | |
| 699 | + if(fl.nstat < 2){ | |
| 700 | + DPRINT("seek: confused\n"); | |
| 701 | + fl.confused = 1; | |
| 702 | + return -1; | |
| 703 | + } | |
| 704 | + if((fl.stat[0] & (Codemask|Seekend)) != Seekend){ | |
| 705 | + DPRINT("seek: failed\n"); | |
| 706 | + dp->confused = 1; | |
| 707 | + return -1; | |
| 708 | + } | |
| 709 | + | |
| 710 | + dp->cyl = dp->tcyl; | |
| 711 | + dp->offset = off; | |
| 712 | + DPRINT("seek to %d succeeded\n", dp->offset); | |
| 713 | + | |
| 714 | + return dp->offset; | |
| 715 | +} | |
| 716 | + | |
| 717 | +/* | |
| 718 | + * read or write to floppy. try up to three times. | |
| 719 | + */ | |
| 720 | +static long | |
| 721 | +floppyxfer(FDrive *dp, int cmd, void *a, long off, long n) | |
| 722 | +{ | |
| 723 | + long offset; | |
| 724 | + int tries; | |
| 725 | + | |
| 726 | + if(off >= dp->t->cap) | |
| 727 | + return 0; | |
| 728 | + if(off + n > dp->t->cap) | |
| 729 | + n = dp->t->cap - off; | |
| 730 | + | |
| 731 | + /* retry on error (until it gets ridiculous) */ | |
| 732 | + for(tries = 0; tries < dp->maxtries; tries++){ | |
| 733 | + | |
| 734 | + dp->len = n; | |
| 735 | + if(pcfloppyseek(dp, off) < 0){ | |
| 736 | + DPRINT("xfer: seek failed\n"); | |
| 737 | + dp->confused = 1; | |
| 738 | + continue; | |
| 739 | + } | |
| 740 | + | |
| 741 | + /* | |
| 742 | + * set up the dma (dp->len may be trimmed) | |
| 743 | + */ | |
| 744 | + dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread); | |
| 745 | + if(dp->len < 0){ | |
| 746 | + buggery: | |
| 747 | + dmaend(DMAchan); | |
| 748 | + continue; | |
| 749 | + } | |
| 750 | + | |
| 751 | + /* | |
| 752 | + * start operation | |
| 753 | + */ | |
| 754 | + fl.ncmd = 0; | |
| 755 | + fl.cmd[fl.ncmd++] = cmd | (dp->t->heads > 1 ? Fmulti : 0); | |
| 756 | + fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; | |
| 757 | + fl.cmd[fl.ncmd++] = dp->tcyl; | |
| 758 | + fl.cmd[fl.ncmd++] = dp->thead; | |
| 759 | + fl.cmd[fl.ncmd++] = dp->tsec; | |
| 760 | + fl.cmd[fl.ncmd++] = dp->t->bcode; | |
| 761 | + fl.cmd[fl.ncmd++] = dp->t->sectors; | |
| 762 | + fl.cmd[fl.ncmd++] = dp->t->gpl; | |
| 763 | + fl.cmd[fl.ncmd++] = 0xFF; | |
| 764 | + if(floppycmd() < 0) | |
| 765 | + goto buggery; | |
| 766 | + | |
| 767 | + /* | |
| 768 | + * give bus to DMA, floppyintr() will read result | |
| 769 | + */ | |
| 770 | + floppywait(0); | |
| 771 | + dmaend(DMAchan); | |
| 772 | + | |
| 773 | + /* | |
| 774 | + * check for errors | |
| 775 | + */ | |
| 776 | + if(fl.nstat < 7){ | |
| 777 | + DPRINT("xfer: confused\n"); | |
| 778 | + fl.confused = 1; | |
| 779 | + continue; | |
| 780 | + } | |
| 781 | + if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){ | |
| 782 | + DPRINT("xfer: failed %ux %ux %ux\n", fl.stat[0], | |
| 783 | + fl.stat[1], fl.stat[2]); | |
| 784 | + DPRINT("offset %lud len %ld\n", off, dp->len); | |
| 785 | + if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun){ | |
| 786 | + DPRINT("DMA overrun: retry\n"); | |
| 787 | + } else | |
| 788 | + dp->confused = 1; | |
| 789 | + continue; | |
| 790 | + } | |
| 791 | + | |
| 792 | + /* | |
| 793 | + * check for correct cylinder | |
| 794 | + */ | |
| 795 | + offset = fl.stat[3] * dp->t->heads + fl.stat[4]; | |
| 796 | + offset = offset*dp->t->sectors + fl.stat[5] - 1; | |
| 797 | + offset = offset * c2b[fl.stat[6]]; | |
| 798 | + if(offset != off+dp->len){ | |
| 799 | + DPRINT("xfer: ends on wrong cyl\n"); | |
| 800 | + dp->confused = 1; | |
| 801 | + continue; | |
| 802 | + } | |
| 803 | + | |
| 804 | + dp->lasttouched = m->ticks; | |
| 805 | + dp->maxtries = 20; | |
| 806 | + return dp->len; | |
| 807 | + } | |
| 808 | + | |
| 809 | + return -1; | |
| 810 | +} | |
| 811 | + | |
| 812 | +/* | |
| 813 | +void | |
| 814 | +floppymemwrite(void) | |
| 815 | +{ | |
| 816 | + int i; | |
| 817 | + int n; | |
| 818 | + uchar *a; | |
| 819 | + FDrive *dp; | |
| 820 | + | |
| 821 | + dp = &fl.d[0]; | |
| 822 | + a = (uchar*)0x80000000; | |
| 823 | + n = 0; | |
| 824 | + while(n < 1440*1024){ | |
| 825 | + i = floppyxfer(dp, Fwrite, a+n, n, 1440*1024-n); | |
| 826 | + if(i <= 0) | |
| 827 | + break; | |
| 828 | + n += i; | |
| 829 | + } | |
| 830 | + print("floppymemwrite wrote %d bytes\n", n); | |
| 831 | +splhi(); for(;;); | |
| 832 | +} | |
| 833 | +*/ | |
| 834 | + | |
| 835 | +static void | |
| 836 | +floppyintr(Ureg *ur) | |
| 837 | +{ | |
| 838 | + USED(ur); | |
| 839 | + switch(fl.cmd[0]&~Fmulti){ | |
| 840 | + case Fread: | |
| 841 | + case Fwrite: | |
| 842 | + case Fformat: | |
| 843 | + case Fdumpreg: | |
| 844 | + floppyresult(); | |
| 845 | + break; | |
| 846 | + case Fseek: | |
| 847 | + case Frecal: | |
| 848 | + default: | |
| 849 | + floppysense(); /* to clear interrupt */ | |
| 850 | + break; | |
| 851 | + } | |
| 852 | + fl.ncmd = 0; | |
| 853 | +} | |
| @@ -0,0 +1,196 @@ | ||
| 1 | +typedef struct FController FController; | |
| 2 | +typedef struct FDrive FDrive; | |
| 3 | +typedef struct FType FType; | |
| 4 | + | |
| 5 | +static void floppyintr(Ureg*); | |
| 6 | +static int floppyon(FDrive*); | |
| 7 | +static void floppyoff(FDrive*); | |
| 8 | +static void floppysetdef(FDrive*); | |
| 9 | + | |
| 10 | +/* | |
| 11 | + * a floppy drive | |
| 12 | + */ | |
| 13 | +struct FDrive | |
| 14 | +{ | |
| 15 | + FType *t; /* floppy type */ | |
| 16 | + int dt; /* drive type */ | |
| 17 | + int dev; | |
| 18 | + | |
| 19 | + ulong lasttouched; /* time last touched */ | |
| 20 | + int cyl; /* current arm position */ | |
| 21 | + int confused; /* needs to be recalibrated */ | |
| 22 | + int offset; /* current offset */ | |
| 23 | + int vers; | |
| 24 | + int maxtries; | |
| 25 | + | |
| 26 | + int tcyl; /* target cylinder */ | |
| 27 | + int thead; /* target head */ | |
| 28 | + int tsec; /* target sector */ | |
| 29 | + long len; /* size of xfer */ | |
| 30 | + | |
| 31 | + uchar *cache; /* track cache */ | |
| 32 | + int ccyl; | |
| 33 | + int chead; | |
| 34 | + | |
| 35 | +// Rendez r; /* waiting here for motor to spin up */ | |
| 36 | + void *aux; | |
| 37 | +}; | |
| 38 | + | |
| 39 | +/* | |
| 40 | + * controller for 4 floppys | |
| 41 | + */ | |
| 42 | +struct FController | |
| 43 | +{ | |
| 44 | +// QLock; /* exclusive access to the contoller */ | |
| 45 | + | |
| 46 | + int ndrive; | |
| 47 | + FDrive *d; /* the floppy drives */ | |
| 48 | + FDrive *selected; | |
| 49 | + int rate; /* current rate selected */ | |
| 50 | + uchar cmd[14]; /* command */ | |
| 51 | + int ncmd; /* # command bytes */ | |
| 52 | + uchar stat[14]; /* command status */ | |
| 53 | + int nstat; /* # status bytes */ | |
| 54 | + int confused; /* controler needs to be reset */ | |
| 55 | +// Rendez r; /* wait here for command termination */ | |
| 56 | + int motor; /* bit mask of spinning disks */ | |
| 57 | +// Rendez kr; /* for motor watcher */ | |
| 58 | +}; | |
| 59 | + | |
| 60 | +/* | |
| 61 | + * floppy types (all MFM encoding) | |
| 62 | + */ | |
| 63 | +struct FType | |
| 64 | +{ | |
| 65 | + char *name; | |
| 66 | + int dt; /* compatible drive type */ | |
| 67 | + int bytes; /* bytes/sector */ | |
| 68 | + int sectors; /* sectors/track */ | |
| 69 | + int heads; /* number of heads */ | |
| 70 | + int steps; /* steps per cylinder */ | |
| 71 | + int tracks; /* tracks/disk */ | |
| 72 | + int gpl; /* intersector gap length for read/write */ | |
| 73 | + int fgpl; /* intersector gap length for format */ | |
| 74 | + int rate; /* rate code */ | |
| 75 | + | |
| 76 | + /* | |
| 77 | + * these depend on previous entries and are set filled in | |
| 78 | + * by floppyinit | |
| 79 | + */ | |
| 80 | + int bcode; /* coded version of bytes for the controller */ | |
| 81 | + long cap; /* drive capacity in bytes */ | |
| 82 | + long tsize; /* track size in bytes */ | |
| 83 | +}; | |
| 84 | +/* bits in the registers */ | |
| 85 | +enum | |
| 86 | +{ | |
| 87 | + /* status registers a & b */ | |
| 88 | + Psra= 0x3f0, | |
| 89 | + Psrb= 0x3f1, | |
| 90 | + | |
| 91 | + /* digital output register */ | |
| 92 | + Pdor= 0x3f2, | |
| 93 | + Fintena= 0x8, /* enable floppy interrupt */ | |
| 94 | + Fena= 0x4, /* 0 == reset controller */ | |
| 95 | + | |
| 96 | + /* main status register */ | |
| 97 | + Pmsr= 0x3f4, | |
| 98 | + Fready= 0x80, /* ready to be touched */ | |
| 99 | + Ffrom= 0x40, /* data from controller */ | |
| 100 | + Ffloppybusy= 0x10, /* operation not over */ | |
| 101 | + | |
| 102 | + /* data register */ | |
| 103 | + Pfdata= 0x3f5, | |
| 104 | + Frecal= 0x07, /* recalibrate cmd */ | |
| 105 | + Fseek= 0x0f, /* seek cmd */ | |
| 106 | + Fsense= 0x08, /* sense cmd */ | |
| 107 | + Fread= 0x66, /* read cmd */ | |
| 108 | + Freadid= 0x4a, /* read track id */ | |
| 109 | + Fspec= 0x03, /* set hold times */ | |
| 110 | + Fwrite= 0x45, /* write cmd */ | |
| 111 | + Fformat= 0x4d, /* format cmd */ | |
| 112 | + Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */ | |
| 113 | + Fdumpreg= 0x0e, /* dump internal registers */ | |
| 114 | + | |
| 115 | + /* digital input register */ | |
| 116 | + Pdir= 0x3F7, /* disk changed port (read only) */ | |
| 117 | + Pdsr= 0x3F7, /* data rate select port (write only) */ | |
| 118 | + Fchange= 0x80, /* disk has changed */ | |
| 119 | + | |
| 120 | + /* status 0 byte */ | |
| 121 | + Drivemask= 3<<0, | |
| 122 | + Seekend= 1<<5, | |
| 123 | + Codemask= (3<<6)|(3<<3), | |
| 124 | + Cmdexec= 1<<6, | |
| 125 | + | |
| 126 | + /* status 1 byte */ | |
| 127 | + Overrun= 0x10, | |
| 128 | +}; | |
| 129 | + | |
| 130 | +/* | |
| 131 | + * types of drive (from PC equipment byte) | |
| 132 | + */ | |
| 133 | +enum | |
| 134 | +{ | |
| 135 | + Tnone= 0, | |
| 136 | + T360kb= 1, | |
| 137 | + T1200kb= 2, | |
| 138 | + T720kb= 3, | |
| 139 | + T1440kb= 4, | |
| 140 | +}; | |
| 141 | + | |
| 142 | +static void | |
| 143 | +pcfloppyintr(Ureg *ur, void *a) | |
| 144 | +{ | |
| 145 | + USED(a); | |
| 146 | + | |
| 147 | + floppyintr(ur); | |
| 148 | +} | |
| 149 | + | |
| 150 | +void | |
| 151 | +floppysetup0(FController *fl) | |
| 152 | +{ | |
| 153 | + uchar equip; | |
| 154 | + | |
| 155 | + /* | |
| 156 | + * Read nvram for types of floppies 0 & 1. | |
| 157 | + * Always try floppy 0. | |
| 158 | + */ | |
| 159 | + equip = nvramread(0x10); | |
| 160 | + fl->ndrive = 1; | |
| 161 | + | |
| 162 | + if(equip & 0xf) | |
| 163 | + fl->ndrive++; | |
| 164 | + | |
| 165 | + /* | |
| 166 | + * Allocate the drive storage. | |
| 167 | + * There's always one. | |
| 168 | + */ | |
| 169 | + fl->d = xalloc(fl->ndrive*sizeof(FDrive)); | |
| 170 | + fl->d[0].dt = (equip >> 4) & 0xf; | |
| 171 | + if(fl->d[0].dt == Tnone) | |
| 172 | + fl->d[0].dt = T1440kb; | |
| 173 | + | |
| 174 | + if(fl->ndrive == 2) | |
| 175 | + fl->d[1].dt = equip & 0xf; | |
| 176 | +} | |
| 177 | + | |
| 178 | +void | |
| 179 | +floppysetup1(FController*) | |
| 180 | +{ | |
| 181 | +// intrenable(VectorFLOPPY, pcfloppyintr, fl, BUSUNKNOWN); | |
| 182 | + setvec(VectorFLOPPY, pcfloppyintr, 0); | |
| 183 | +} | |
| 184 | + | |
| 185 | + | |
| 186 | +static vlong pcfloppyseek(FDrive*, vlong); | |
| 187 | +FController fl; | |
| 188 | + | |
| 189 | +vlong | |
| 190 | +floppyseek(Fs *fs, vlong off) | |
| 191 | +{ | |
| 192 | + FDrive *dp; | |
| 193 | + | |
| 194 | + dp = &fl.d[fs->dev]; | |
| 195 | + return pcfloppyseek(dp, off); | |
| 196 | +} | |
| @@ -0,0 +1,1205 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "mem.h" | |
| 4 | +#include "dat.h" | |
| 5 | +#include "fns.h" | |
| 6 | +#include "error.h" | |
| 7 | +#include "io.h" | |
| 8 | + | |
| 9 | +/* | |
| 10 | + * Support for up to 4 Slot card slots. Generalizing above that is hard | |
| 11 | + * since addressing is not obvious. - presotto | |
| 12 | + * | |
| 13 | + * WARNING: This has never been tried with more than one card slot. | |
| 14 | + */ | |
| 15 | + | |
| 16 | +/* | |
| 17 | + * Intel 82365SL PCIC controller for the PCMCIA or | |
| 18 | + * Cirrus Logic PD6710/PD6720 which is mostly register compatible | |
| 19 | + */ | |
| 20 | +enum | |
| 21 | +{ | |
| 22 | + /* | |
| 23 | + * registers indices | |
| 24 | + */ | |
| 25 | + Rid= 0x0, /* identification and revision */ | |
| 26 | + Ris= 0x1, /* interface status */ | |
| 27 | + Rpc= 0x2, /* power control */ | |
| 28 | + Foutena= (1<<7), /* output enable */ | |
| 29 | + Fautopower= (1<<5), /* automatic power switching */ | |
| 30 | + Fcardena= (1<<4), /* PC card enable */ | |
| 31 | + Rigc= 0x3, /* interrupt and general control */ | |
| 32 | + Fiocard= (1<<5), /* I/O card (vs memory) */ | |
| 33 | + Fnotreset= (1<<6), /* reset if not set */ | |
| 34 | + FSMIena= (1<<4), /* enable change interrupt on SMI */ | |
| 35 | + Rcsc= 0x4, /* card status change */ | |
| 36 | + Rcscic= 0x5, /* card status change interrupt config */ | |
| 37 | + Fchangeena= (1<<3), /* card changed */ | |
| 38 | + Fbwarnena= (1<<1), /* card battery warning */ | |
| 39 | + Fbdeadena= (1<<0), /* card battery dead */ | |
| 40 | + Rwe= 0x6, /* address window enable */ | |
| 41 | + Fmem16= (1<<5), /* use A23-A12 to decode address */ | |
| 42 | + Rio= 0x7, /* I/O control */ | |
| 43 | + Fwidth16= (1<<0), /* 16 bit data width */ | |
| 44 | + Fiocs16= (1<<1), /* IOCS16 determines data width */ | |
| 45 | + Fzerows= (1<<2), /* zero wait state */ | |
| 46 | + Ftiming= (1<<3), /* timing register to use */ | |
| 47 | + Riobtm0lo= 0x8, /* I/O address 0 start low byte */ | |
| 48 | + Riobtm0hi= 0x9, /* I/O address 0 start high byte */ | |
| 49 | + Riotop0lo= 0xa, /* I/O address 0 stop low byte */ | |
| 50 | + Riotop0hi= 0xb, /* I/O address 0 stop high byte */ | |
| 51 | + Riobtm1lo= 0xc, /* I/O address 1 start low byte */ | |
| 52 | + Riobtm1hi= 0xd, /* I/O address 1 start high byte */ | |
| 53 | + Riotop1lo= 0xe, /* I/O address 1 stop low byte */ | |
| 54 | + Riotop1hi= 0xf, /* I/O address 1 stop high byte */ | |
| 55 | + Rmap= 0x10, /* map 0 */ | |
| 56 | + | |
| 57 | + /* | |
| 58 | + * CL-PD67xx extension registers | |
| 59 | + */ | |
| 60 | + Rmisc1= 0x16, /* misc control 1 */ | |
| 61 | + F5Vdetect= (1<<0), | |
| 62 | + Fvcc3V= (1<<1), | |
| 63 | + Fpmint= (1<<2), | |
| 64 | + Fpsirq= (1<<3), | |
| 65 | + Fspeaker= (1<<4), | |
| 66 | + Finpack= (1<<7), | |
| 67 | + Rfifo= 0x17, /* fifo control */ | |
| 68 | + Fflush= (1<<7), /* flush fifo */ | |
| 69 | + Rmisc2= 0x1E, /* misc control 2 */ | |
| 70 | + Flowpow= (1<<1), /* low power mode */ | |
| 71 | + Rchipinfo= 0x1F, /* chip information */ | |
| 72 | + Ratactl= 0x26, /* ATA control */ | |
| 73 | + | |
| 74 | + /* | |
| 75 | + * offsets into the system memory address maps | |
| 76 | + */ | |
| 77 | + Mbtmlo= 0x0, /* System mem addr mapping start low byte */ | |
| 78 | + Mbtmhi= 0x1, /* System mem addr mapping start high byte */ | |
| 79 | + F16bit= (1<<7), /* 16-bit wide data path */ | |
| 80 | + Mtoplo= 0x2, /* System mem addr mapping stop low byte */ | |
| 81 | + Mtophi= 0x3, /* System mem addr mapping stop high byte */ | |
| 82 | + Ftimer1= (1<<6), /* timer set 1 */ | |
| 83 | + Mofflo= 0x4, /* Card memory offset address low byte */ | |
| 84 | + Moffhi= 0x5, /* Card memory offset address high byte */ | |
| 85 | + Fregactive= (1<<6), /* attribute memory */ | |
| 86 | + | |
| 87 | + Mbits= 13, /* msb of Mchunk */ | |
| 88 | + Mchunk= 1<<Mbits, /* logical mapping granularity */ | |
| 89 | + Nmap= 4, /* max number of maps to use */ | |
| 90 | + | |
| 91 | + /* | |
| 92 | + * configuration registers - they start at an offset in attribute | |
| 93 | + * memory found in the CIS. | |
| 94 | + */ | |
| 95 | + Rconfig= 0, | |
| 96 | + Creset= (1<<7), /* reset device */ | |
| 97 | + Clevel= (1<<6), /* level sensitive interrupt line */ | |
| 98 | + | |
| 99 | + Maxctab= 8, /* maximum configuration table entries */ | |
| 100 | +}; | |
| 101 | + | |
| 102 | +static int pcmcia_pcmspecial(char *, ISAConf *); | |
| 103 | +static void pcmcia_pcmspecialclose(int); | |
| 104 | + | |
| 105 | +#define MAP(x,o) (Rmap + (x)*0x8 + o) | |
| 106 | + | |
| 107 | +typedef struct I82365 I82365; | |
| 108 | +typedef struct Slot Slot; | |
| 109 | +typedef struct Conftab Conftab; | |
| 110 | +typedef struct Cisdat Cisdat; | |
| 111 | +/* a controller */ | |
| 112 | +enum | |
| 113 | +{ | |
| 114 | + Ti82365, | |
| 115 | + Tpd6710, | |
| 116 | + Tpd6720, | |
| 117 | + Tvg46x, | |
| 118 | +}; | |
| 119 | +struct I82365 | |
| 120 | +{ | |
| 121 | + int type; | |
| 122 | + int dev; | |
| 123 | + int nslot; | |
| 124 | + int xreg; /* index register address */ | |
| 125 | + int dreg; /* data register address */ | |
| 126 | + int irq; | |
| 127 | +}; | |
| 128 | +static I82365 *controller[4]; | |
| 129 | +static int ncontroller; | |
| 130 | + | |
| 131 | +/* configuration table entry */ | |
| 132 | +struct Conftab | |
| 133 | +{ | |
| 134 | + int index; | |
| 135 | + ushort irqs; /* legal irqs */ | |
| 136 | + uchar irqtype; | |
| 137 | + uchar bit16; /* true for 16 bit access */ | |
| 138 | + struct { | |
| 139 | + ulong start; | |
| 140 | + ulong len; | |
| 141 | + } io[16]; | |
| 142 | + int nio; | |
| 143 | + uchar vpp1; | |
| 144 | + uchar vpp2; | |
| 145 | + uchar memwait; | |
| 146 | + ulong maxwait; | |
| 147 | + ulong readywait; | |
| 148 | + ulong otherwait; | |
| 149 | +}; | |
| 150 | + | |
| 151 | +/* cis memory walking */ | |
| 152 | +struct Cisdat | |
| 153 | +{ | |
| 154 | + uchar *cisbase; | |
| 155 | + int cispos; | |
| 156 | + int cisskip; | |
| 157 | + int cislen; | |
| 158 | +}; | |
| 159 | + | |
| 160 | +/* a card slot */ | |
| 161 | +struct Slot | |
| 162 | +{ | |
| 163 | + Lock; | |
| 164 | + int ref; | |
| 165 | + | |
| 166 | + I82365 *cp; /* controller for this slot */ | |
| 167 | + long memlen; /* memory length */ | |
| 168 | + uchar base; /* index register base */ | |
| 169 | + uchar slotno; /* slot number */ | |
| 170 | + | |
| 171 | + /* status */ | |
| 172 | + uchar special; /* in use for a special device */ | |
| 173 | + uchar already; /* already inited */ | |
| 174 | + uchar occupied; | |
| 175 | + uchar battery; | |
| 176 | + uchar wrprot; | |
| 177 | + uchar powered; | |
| 178 | + uchar configed; | |
| 179 | + uchar enabled; | |
| 180 | + uchar busy; | |
| 181 | + | |
| 182 | + /* cis info */ | |
| 183 | + char verstr[512]; /* version string */ | |
| 184 | + uchar cpresent; /* config registers present */ | |
| 185 | + ulong caddr; /* relative address of config registers */ | |
| 186 | + int nctab; /* number of config table entries */ | |
| 187 | + Conftab ctab[Maxctab]; | |
| 188 | + Conftab *def; /* default conftab */ | |
| 189 | + | |
| 190 | + /* for walking through cis */ | |
| 191 | + Cisdat; | |
| 192 | + | |
| 193 | + /* memory maps */ | |
| 194 | + Lock mlock; /* lock down the maps */ | |
| 195 | + int time; | |
| 196 | + PCMmap mmap[Nmap]; /* maps, last is always for the kernel */ | |
| 197 | +}; | |
| 198 | +static Slot *slot; | |
| 199 | +static Slot *lastslot; | |
| 200 | +static nslot; | |
| 201 | + | |
| 202 | +static void cisread(Slot*); | |
| 203 | +static void i82365intr(Ureg*, void*); | |
| 204 | +static void i82365reset(void); | |
| 205 | +static int pcmio(int, ISAConf*); | |
| 206 | +static long pcmread(int, int, void*, long, vlong); | |
| 207 | +static long pcmwrite(int, int, void*, long, vlong); | |
| 208 | + | |
| 209 | +static void i82365dump(Slot*); | |
| 210 | + | |
| 211 | +void | |
| 212 | +devi82365link(void) | |
| 213 | +{ | |
| 214 | + static int already; | |
| 215 | + | |
| 216 | + if(already) | |
| 217 | + return; | |
| 218 | + already = 1; | |
| 219 | + | |
| 220 | + if (_pcmspecial) | |
| 221 | + return; | |
| 222 | + | |
| 223 | + _pcmspecial = pcmcia_pcmspecial; | |
| 224 | + _pcmspecialclose = pcmcia_pcmspecialclose; | |
| 225 | +} | |
| 226 | + | |
| 227 | +/* | |
| 228 | + * reading and writing card registers | |
| 229 | + */ | |
| 230 | +static uchar | |
| 231 | +rdreg(Slot *pp, int index) | |
| 232 | +{ | |
| 233 | + outb(pp->cp->xreg, pp->base + index); | |
| 234 | + return inb(pp->cp->dreg); | |
| 235 | +} | |
| 236 | +static void | |
| 237 | +wrreg(Slot *pp, int index, uchar val) | |
| 238 | +{ | |
| 239 | + outb(pp->cp->xreg, pp->base + index); | |
| 240 | + outb(pp->cp->dreg, val); | |
| 241 | +} | |
| 242 | + | |
| 243 | +/* | |
| 244 | + * get info about card | |
| 245 | + */ | |
| 246 | +static void | |
| 247 | +slotinfo(Slot *pp) | |
| 248 | +{ | |
| 249 | + uchar isr; | |
| 250 | + | |
| 251 | + isr = rdreg(pp, Ris); | |
| 252 | + pp->occupied = (isr & (3<<2)) == (3<<2); | |
| 253 | + pp->powered = isr & (1<<6); | |
| 254 | + pp->battery = (isr & 3) == 3; | |
| 255 | + pp->wrprot = isr & (1<<4); | |
| 256 | + pp->busy = isr & (1<<5); | |
| 257 | +} | |
| 258 | + | |
| 259 | +static int | |
| 260 | +vcode(int volt) | |
| 261 | +{ | |
| 262 | + switch(volt){ | |
| 263 | + case 5: | |
| 264 | + return 1; | |
| 265 | + case 12: | |
| 266 | + return 2; | |
| 267 | + default: | |
| 268 | + return 0; | |
| 269 | + } | |
| 270 | +} | |
| 271 | + | |
| 272 | +/* | |
| 273 | + * enable the slot card | |
| 274 | + */ | |
| 275 | +static void | |
| 276 | +slotena(Slot *pp) | |
| 277 | +{ | |
| 278 | + if(pp->enabled) | |
| 279 | + return; | |
| 280 | + | |
| 281 | + /* power up and unreset, wait's are empirical (???) */ | |
| 282 | + wrreg(pp, Rpc, Fautopower|Foutena|Fcardena); | |
| 283 | + delay(300); | |
| 284 | + wrreg(pp, Rigc, 0); | |
| 285 | + delay(100); | |
| 286 | + wrreg(pp, Rigc, Fnotreset); | |
| 287 | + delay(500); | |
| 288 | + | |
| 289 | + /* get configuration */ | |
| 290 | + slotinfo(pp); | |
| 291 | + if(pp->occupied){ | |
| 292 | + cisread(pp); | |
| 293 | + pp->enabled = 1; | |
| 294 | + } else | |
| 295 | + wrreg(pp, Rpc, Fautopower); | |
| 296 | +} | |
| 297 | + | |
| 298 | +/* | |
| 299 | + * disable the slot card | |
| 300 | + */ | |
| 301 | +static void | |
| 302 | +slotdis(Slot *pp) | |
| 303 | +{ | |
| 304 | + wrreg(pp, Rpc, 0); /* turn off card power */ | |
| 305 | + wrreg(pp, Rwe, 0); /* no windows */ | |
| 306 | + pp->enabled = 0; | |
| 307 | +} | |
| 308 | + | |
| 309 | +/* | |
| 310 | + * status change interrupt | |
| 311 | + */ | |
| 312 | +static void | |
| 313 | +i82365intr(Ureg *, void *) | |
| 314 | +{ | |
| 315 | + uchar csc, was; | |
| 316 | + Slot *pp; | |
| 317 | + | |
| 318 | + if(slot == 0) | |
| 319 | + return; | |
| 320 | + | |
| 321 | + for(pp = slot; pp < lastslot; pp++){ | |
| 322 | + csc = rdreg(pp, Rcsc); | |
| 323 | + was = pp->occupied; | |
| 324 | + slotinfo(pp); | |
| 325 | + if(csc & (1<<3) && was != pp->occupied){ | |
| 326 | + if(!pp->occupied) | |
| 327 | + slotdis(pp); | |
| 328 | + } | |
| 329 | + } | |
| 330 | +} | |
| 331 | + | |
| 332 | +enum | |
| 333 | +{ | |
| 334 | + Mshift= 12, | |
| 335 | + Mgran= (1<<Mshift), /* granularity of maps */ | |
| 336 | + Mmask= ~(Mgran-1), /* mask for address bits important to the chip */ | |
| 337 | +}; | |
| 338 | + | |
| 339 | +/* | |
| 340 | + * get a map for pc card region, return corrected len | |
| 341 | + */ | |
| 342 | +PCMmap* | |
| 343 | +pcmmap(int slotno, ulong offset, int len, int attr) | |
| 344 | +{ | |
| 345 | + Slot *pp; | |
| 346 | + uchar we, bit; | |
| 347 | + PCMmap *m, *nm; | |
| 348 | + int i; | |
| 349 | + ulong e; | |
| 350 | + | |
| 351 | + pp = slot + slotno; | |
| 352 | + lock(&pp->mlock); | |
| 353 | + | |
| 354 | + /* convert offset to granularity */ | |
| 355 | + if(len <= 0) | |
| 356 | + len = 1; | |
| 357 | + e = ROUND(offset+len, Mgran); | |
| 358 | + offset &= Mmask; | |
| 359 | + len = e - offset; | |
| 360 | + | |
| 361 | + /* look for a map that covers the right area */ | |
| 362 | + we = rdreg(pp, Rwe); | |
| 363 | + bit = 1; | |
| 364 | + nm = 0; | |
| 365 | + for(m = pp->mmap; m < &pp->mmap[Nmap]; m++){ | |
| 366 | + if((we & bit)) | |
| 367 | + if(m->attr == attr) | |
| 368 | + if(offset >= m->ca && e <= m->cea){ | |
| 369 | + | |
| 370 | + m->ref++; | |
| 371 | + unlock(&pp->mlock); | |
| 372 | + return m; | |
| 373 | + } | |
| 374 | + bit <<= 1; | |
| 375 | + if(nm == 0 && m->ref == 0) | |
| 376 | + nm = m; | |
| 377 | + } | |
| 378 | + m = nm; | |
| 379 | + if(m == 0){ | |
| 380 | + unlock(&pp->mlock); | |
| 381 | + return 0; | |
| 382 | + } | |
| 383 | + | |
| 384 | + /* if isa space isn't big enough, free it and get more */ | |
| 385 | + if(m->len < len){ | |
| 386 | + if(m->isa){ | |
| 387 | + umbfree(m->isa, m->len); | |
| 388 | + m->len = 0; | |
| 389 | + } | |
| 390 | + m->isa = PADDR(umbmalloc(0, len, Mgran)); | |
| 391 | + if(m->isa == 0){ | |
| 392 | + print("pcmmap %d: out of isa space\n", len); | |
| 393 | + unlock(&pp->mlock); | |
| 394 | + return 0; | |
| 395 | + } | |
| 396 | + m->len = len; | |
| 397 | + } | |
| 398 | + | |
| 399 | + /* set up new map */ | |
| 400 | + m->ca = offset; | |
| 401 | + m->cea = m->ca + m->len; | |
| 402 | + m->attr = attr; | |
| 403 | + i = m-pp->mmap; | |
| 404 | + bit = 1<<i; | |
| 405 | + wrreg(pp, Rwe, we & ~bit); /* disable map before changing it */ | |
| 406 | + wrreg(pp, MAP(i, Mbtmlo), m->isa>>Mshift); | |
| 407 | + wrreg(pp, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit); | |
| 408 | + wrreg(pp, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift); | |
| 409 | + wrreg(pp, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8))); | |
| 410 | + offset -= m->isa; | |
| 411 | + offset &= (1<<25)-1; | |
| 412 | + offset >>= Mshift; | |
| 413 | + wrreg(pp, MAP(i, Mofflo), offset); | |
| 414 | + wrreg(pp, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0)); | |
| 415 | + wrreg(pp, Rwe, we | bit); /* enable map */ | |
| 416 | + m->ref = 1; | |
| 417 | + | |
| 418 | + unlock(&pp->mlock); | |
| 419 | + return m; | |
| 420 | +} | |
| 421 | + | |
| 422 | +void | |
| 423 | +pcmunmap(int slotno, PCMmap* m) | |
| 424 | +{ | |
| 425 | + Slot *pp; | |
| 426 | + | |
| 427 | + pp = slot + slotno; | |
| 428 | + lock(&pp->mlock); | |
| 429 | + m->ref--; | |
| 430 | + unlock(&pp->mlock); | |
| 431 | +} | |
| 432 | + | |
| 433 | +static void | |
| 434 | +increfp(Slot *pp) | |
| 435 | +{ | |
| 436 | + lock(pp); | |
| 437 | + if(pp->ref++ == 0) | |
| 438 | + slotena(pp); | |
| 439 | + unlock(pp); | |
| 440 | +} | |
| 441 | + | |
| 442 | +static void | |
| 443 | +decrefp(Slot *pp) | |
| 444 | +{ | |
| 445 | + lock(pp); | |
| 446 | + if(pp->ref-- == 1) | |
| 447 | + slotdis(pp); | |
| 448 | + unlock(pp); | |
| 449 | +} | |
| 450 | + | |
| 451 | +/* | |
| 452 | + * look for a card whose version contains 'idstr' | |
| 453 | + */ | |
| 454 | +static int | |
| 455 | +pcmcia_pcmspecial(char *idstr, ISAConf *isa) | |
| 456 | +{ | |
| 457 | + Slot *pp; | |
| 458 | + extern char *strstr(char*, char*); | |
| 459 | + int enabled; | |
| 460 | + | |
| 461 | + i82365reset(); | |
| 462 | + for(pp = slot; pp < lastslot; pp++){ | |
| 463 | + if(pp->special) | |
| 464 | + continue; /* already taken */ | |
| 465 | + enabled = 0; | |
| 466 | + /* make sure we don't power on cards when we already know what's | |
| 467 | + * in them. We'll reread every two minutes if necessary | |
| 468 | + */ | |
| 469 | + if (pp->verstr[0] == '\0') { | |
| 470 | + increfp(pp); | |
| 471 | + enabled++; | |
| 472 | + } | |
| 473 | + | |
| 474 | + if(pp->occupied) { | |
| 475 | + if(strstr(pp->verstr, idstr)) { | |
| 476 | + if (!enabled) | |
| 477 | + increfp(pp); | |
| 478 | + if(isa == 0 || pcmio(pp->slotno, isa) == 0){ | |
| 479 | + pp->special = 1; | |
| 480 | + return pp->slotno; | |
| 481 | + } | |
| 482 | + } | |
| 483 | + } else | |
| 484 | + pp->special = 1; | |
| 485 | + if (enabled) | |
| 486 | + decrefp(pp); | |
| 487 | + } | |
| 488 | + return -1; | |
| 489 | +} | |
| 490 | + | |
| 491 | +static void | |
| 492 | +pcmcia_pcmspecialclose(int slotno) | |
| 493 | +{ | |
| 494 | + Slot *pp; | |
| 495 | + | |
| 496 | + print("pcmspecialclose called\n"); | |
| 497 | + if(slotno >= nslot) | |
| 498 | + panic("pcmspecialclose"); | |
| 499 | + pp = slot + slotno; | |
| 500 | + pp->special = 0; | |
| 501 | + decrefp(pp); | |
| 502 | +} | |
| 503 | + | |
| 504 | +static char *chipname[] = | |
| 505 | +{ | |
| 506 | +[Ti82365] "Intel 82365SL", | |
| 507 | +[Tpd6710] "Cirrus Logic PD6710", | |
| 508 | +[Tpd6720] "Cirrus Logic PD6720", | |
| 509 | +[Tvg46x] "Vadem VG-46x", | |
| 510 | +}; | |
| 511 | + | |
| 512 | +static I82365* | |
| 513 | +i82365probe(int x, int d, int dev) | |
| 514 | +{ | |
| 515 | + uchar c, id; | |
| 516 | + I82365 *cp; | |
| 517 | + ISAConf isa; | |
| 518 | + int i, nslot; | |
| 519 | + | |
| 520 | + outb(x, Rid + (dev<<7)); | |
| 521 | + id = inb(d); | |
| 522 | + if((id & 0xf0) != 0x80) | |
| 523 | + return 0; /* not this family */ | |
| 524 | + | |
| 525 | + cp = xalloc(sizeof(I82365)); | |
| 526 | + cp->xreg = x; | |
| 527 | + cp->dreg = d; | |
| 528 | + cp->dev = dev; | |
| 529 | + cp->type = Ti82365; | |
| 530 | + cp->nslot = 2; | |
| 531 | + | |
| 532 | + switch(id){ | |
| 533 | + case 0x82: | |
| 534 | + case 0x83: | |
| 535 | + case 0x84: | |
| 536 | + /* could be a cirrus */ | |
| 537 | + outb(x, Rchipinfo + (dev<<7)); | |
| 538 | + outb(d, 0); | |
| 539 | + c = inb(d); | |
| 540 | + if((c & 0xc0) != 0xc0) | |
| 541 | + break; | |
| 542 | + c = inb(d); | |
| 543 | + if((c & 0xc0) != 0x00) | |
| 544 | + break; | |
| 545 | + if(c & 0x20){ | |
| 546 | + cp->type = Tpd6720; | |
| 547 | + } else { | |
| 548 | + cp->type = Tpd6710; | |
| 549 | + cp->nslot = 1; | |
| 550 | + } | |
| 551 | + | |
| 552 | + /* low power mode */ | |
| 553 | + outb(x, Rmisc2 + (dev<<7)); | |
| 554 | + c = inb(d); | |
| 555 | + outb(d, c & ~Flowpow); | |
| 556 | + break; | |
| 557 | + } | |
| 558 | + | |
| 559 | + if(cp->type == Ti82365){ | |
| 560 | + outb(x, 0x0E + (dev<<7)); | |
| 561 | + outb(x, 0x37 + (dev<<7)); | |
| 562 | + outb(x, 0x3A + (dev<<7)); | |
| 563 | + c = inb(d); | |
| 564 | + outb(d, c|0xC0); | |
| 565 | + outb(x, Rid + (dev<<7)); | |
| 566 | + c = inb(d); | |
| 567 | + if(c != id && !(c & 0x08)) | |
| 568 | + print("#y%d: id %uX changed to %uX\n", ncontroller, id, c); | |
| 569 | + if(c & 0x08) | |
| 570 | + cp->type = Tvg46x; | |
| 571 | + outb(x, 0x3A + (dev<<7)); | |
| 572 | + c = inb(d); | |
| 573 | + outb(d, c & ~0xC0); | |
| 574 | + } | |
| 575 | + | |
| 576 | + memset(&isa, 0, sizeof(ISAConf)); | |
| 577 | + if(isaconfig("pcmcia", ncontroller, &isa) && isa.irq) | |
| 578 | + cp->irq = isa.irq; | |
| 579 | + else | |
| 580 | + cp->irq = VectorPCMCIA - VectorPIC; | |
| 581 | + | |
| 582 | + for(i = 0; i < isa.nopt; i++){ | |
| 583 | + if(cistrncmp(isa.opt[i], "nslot=", 6)) | |
| 584 | + continue; | |
| 585 | + nslot = strtol(&isa.opt[i][6], nil, 0); | |
| 586 | + if(nslot > 0 && nslot <= 2) | |
| 587 | + cp->nslot = nslot; | |
| 588 | + } | |
| 589 | + | |
| 590 | + controller[ncontroller++] = cp; | |
| 591 | + return cp; | |
| 592 | +} | |
| 593 | + | |
| 594 | +static void | |
| 595 | +i82365dump(Slot *pp) | |
| 596 | +{ | |
| 597 | + int i; | |
| 598 | + | |
| 599 | + for(i = 0; i < 0x40; i++){ | |
| 600 | + if((i&0x0F) == 0) | |
| 601 | + print("\n%2.2uX: ", i); | |
| 602 | + if(((i+1) & 0x0F) == 0x08) | |
| 603 | + print(" - "); | |
| 604 | + print("%2.2uX ", rdreg(pp, i)); | |
| 605 | + } | |
| 606 | + print("\n"); | |
| 607 | +} | |
| 608 | + | |
| 609 | +/* | |
| 610 | + * set up for slot cards | |
| 611 | + */ | |
| 612 | +static void | |
| 613 | +i82365reset(void) | |
| 614 | +{ | |
| 615 | + static int already; | |
| 616 | + int i, j; | |
| 617 | + I82365 *cp; | |
| 618 | + Slot *pp; | |
| 619 | + | |
| 620 | + if(already) | |
| 621 | + return; | |
| 622 | + already = 1; | |
| 623 | + | |
| 624 | + | |
| 625 | + /* look for controllers */ | |
| 626 | + i82365probe(0x3E0, 0x3E1, 0); | |
| 627 | + i82365probe(0x3E0, 0x3E1, 1); | |
| 628 | + i82365probe(0x3E2, 0x3E3, 0); | |
| 629 | + i82365probe(0x3E2, 0x3E3, 1); | |
| 630 | + | |
| 631 | + for(i = 0; i < ncontroller; i++) | |
| 632 | + nslot += controller[i]->nslot; | |
| 633 | + slot = xalloc(nslot * sizeof(Slot)); | |
| 634 | + | |
| 635 | + /* if the card is there turn on 5V power to keep its battery alive */ | |
| 636 | + lastslot = slot; | |
| 637 | + for(i = 0; i < ncontroller; i++){ | |
| 638 | + cp = controller[i]; | |
| 639 | + print("#y%d: %d slot %s: port 0x%uX irq %d\n", | |
| 640 | + i, cp->nslot, chipname[cp->type], cp->xreg, cp->irq); | |
| 641 | + for(j = 0; j < cp->nslot; j++){ | |
| 642 | + pp = lastslot++; | |
| 643 | + pp->slotno = pp - slot; | |
| 644 | + pp->memlen = 64*MB; | |
| 645 | + pp->base = (cp->dev<<7) | (j<<6); | |
| 646 | + pp->cp = cp; | |
| 647 | + slotdis(pp); | |
| 648 | + | |
| 649 | + /* interrupt on status change */ | |
| 650 | + wrreg(pp, Rcscic, (cp->irq<<4) | Fchangeena); | |
| 651 | + rdreg(pp, Rcsc); | |
| 652 | + } | |
| 653 | + | |
| 654 | + /* for card management interrupts */ | |
| 655 | + setvec(cp->irq+VectorPIC, i82365intr, 0); | |
| 656 | + } | |
| 657 | +} | |
| 658 | + | |
| 659 | +/* | |
| 660 | + * configure the Slot for IO. We assume very heavily that we can read | |
| 661 | + * configuration info from the CIS. If not, we won't set up correctly. | |
| 662 | + */ | |
| 663 | +static int | |
| 664 | +pcmio(int slotno, ISAConf *isa) | |
| 665 | +{ | |
| 666 | + uchar we, x, *p; | |
| 667 | + Slot *pp; | |
| 668 | + Conftab *ct, *et, *t; | |
| 669 | + PCMmap *m; | |
| 670 | + int i, index, irq; | |
| 671 | + char *cp; | |
| 672 | + | |
| 673 | + irq = isa->irq; | |
| 674 | + if(irq == 2) | |
| 675 | + irq = 9; | |
| 676 | + | |
| 677 | + if(slotno > nslot) | |
| 678 | + return -1; | |
| 679 | + pp = slot + slotno; | |
| 680 | + | |
| 681 | + if(!pp->occupied) | |
| 682 | + return -1; | |
| 683 | + | |
| 684 | + et = &pp->ctab[pp->nctab]; | |
| 685 | + | |
| 686 | + ct = 0; | |
| 687 | + for(i = 0; i < isa->nopt; i++){ | |
| 688 | + if(strncmp(isa->opt[i], "index=", 6)) | |
| 689 | + continue; | |
| 690 | + index = strtol(&isa->opt[i][6], &cp, 0); | |
| 691 | + if(cp == &isa->opt[i][6] || index >= pp->nctab) | |
| 692 | + return -1; | |
| 693 | + ct = &pp->ctab[index]; | |
| 694 | + } | |
| 695 | + if(ct == 0){ | |
| 696 | + | |
| 697 | + /* assume default is right */ | |
| 698 | + if(pp->def) | |
| 699 | + ct = pp->def; | |
| 700 | + else | |
| 701 | + ct = pp->ctab; | |
| 702 | + | |
| 703 | + /* try for best match */ | |
| 704 | + if(ct->nio == 0 | |
| 705 | + || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){ | |
| 706 | + for(t = pp->ctab; t < et; t++) | |
| 707 | + if(t->nio | |
| 708 | + && t->io[0].start == isa->port | |
| 709 | + && ((1<<irq) & t->irqs)){ | |
| 710 | + ct = t; | |
| 711 | + break; | |
| 712 | + } | |
| 713 | + } | |
| 714 | + if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){ | |
| 715 | + for(t = pp->ctab; t < et; t++) | |
| 716 | + if(t->nio && ((1<<irq) & t->irqs)){ | |
| 717 | + ct = t; | |
| 718 | + break; | |
| 719 | + } | |
| 720 | + } | |
| 721 | + if(ct->nio == 0){ | |
| 722 | + for(t = pp->ctab; t < et; t++) | |
| 723 | + if(t->nio){ | |
| 724 | + ct = t; | |
| 725 | + break; | |
| 726 | + } | |
| 727 | + } | |
| 728 | + } | |
| 729 | + | |
| 730 | + if(ct == et || ct->nio == 0) | |
| 731 | + return -1; | |
| 732 | + if(isa->port == 0 && ct->io[0].start == 0) | |
| 733 | + return -1; | |
| 734 | + | |
| 735 | + /* route interrupts */ | |
| 736 | + isa->irq = irq; | |
| 737 | + wrreg(pp, Rigc, irq | Fnotreset | Fiocard); | |
| 738 | + | |
| 739 | + /* set power and enable device */ | |
| 740 | + x = vcode(ct->vpp1); | |
| 741 | + wrreg(pp, Rpc, x|Fautopower|Foutena|Fcardena); | |
| 742 | + | |
| 743 | + /* 16-bit data path */ | |
| 744 | + if(ct->bit16) | |
| 745 | + x = Ftiming|Fiocs16|Fwidth16; | |
| 746 | + else | |
| 747 | + x = Ftiming; | |
| 748 | + if(ct->nio == 2 && ct->io[1].start) | |
| 749 | + x |= x<<4; | |
| 750 | + wrreg(pp, Rio, x); | |
| 751 | + | |
| 752 | + /* enable io port map 0 */ | |
| 753 | + if(isa->port == 0) | |
| 754 | + isa->port = ct->io[0].start; | |
| 755 | + we = rdreg(pp, Rwe); | |
| 756 | + wrreg(pp, Riobtm0lo, isa->port); | |
| 757 | + wrreg(pp, Riobtm0hi, isa->port>>8); | |
| 758 | + i = isa->port+ct->io[0].len-1; | |
| 759 | + wrreg(pp, Riotop0lo, i); | |
| 760 | + wrreg(pp, Riotop0hi, i>>8); | |
| 761 | + we |= 1<<6; | |
| 762 | + if(ct->nio == 2 && ct->io[1].start){ | |
| 763 | + wrreg(pp, Riobtm1lo, ct->io[1].start); | |
| 764 | + wrreg(pp, Riobtm1hi, ct->io[1].start>>8); | |
| 765 | + i = ct->io[1].start+ct->io[1].len-1; | |
| 766 | + wrreg(pp, Riotop1lo, i); | |
| 767 | + wrreg(pp, Riotop1hi, i>>8); | |
| 768 | + we |= 1<<7; | |
| 769 | + } | |
| 770 | + wrreg(pp, Rwe, we); | |
| 771 | + | |
| 772 | + /* only touch Rconfig if it is present */ | |
| 773 | + if(pp->cpresent & (1<<Rconfig)){ | |
| 774 | + /* Reset adapter */ | |
| 775 | + m = pcmmap(slotno, pp->caddr + Rconfig, 1, 1); | |
| 776 | + p = KADDR(m->isa + pp->caddr + Rconfig - m->ca); | |
| 777 | + | |
| 778 | + /* set configuration and interrupt type */ | |
| 779 | + x = ct->index; | |
| 780 | + if((ct->irqtype & 0x20) && ((ct->irqtype & 0x40)==0 || isa->irq>7)) | |
| 781 | + x |= Clevel; | |
| 782 | + *p = x; | |
| 783 | + delay(5); | |
| 784 | + | |
| 785 | + pcmunmap(slotno, m); | |
| 786 | + } | |
| 787 | + return 0; | |
| 788 | +} | |
| 789 | + | |
| 790 | +/* | |
| 791 | + * read and crack the card information structure enough to set | |
| 792 | + * important parameters like power | |
| 793 | + */ | |
| 794 | +static void tcfig(Slot*, Cisdat*, int); | |
| 795 | +static void tentry(Slot*, Cisdat*, int); | |
| 796 | +static void tvers1(Slot*, Cisdat*, int); | |
| 797 | + | |
| 798 | +struct { | |
| 799 | + int n; | |
| 800 | + void (*parse)(Slot*, Cisdat*, int); | |
| 801 | +} cistab[] = { | |
| 802 | + 0x15, tvers1, | |
| 803 | + 0x1A, tcfig, | |
| 804 | + 0x1B, tentry, | |
| 805 | +}; | |
400 more lines aren’t shown here.
This diff is large: its 1958 lines aren’t shown here.
This diff is large: its 618 lines aren’t shown here.
This diff is large: its 246 lines aren’t shown here.
This diff is large: its 583 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 283 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 1653 lines aren’t shown here.
This diff is large: its 212 lines aren’t shown here.
This diff is large: its 540 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 615 lines aren’t shown here.
This diff is large: its 848 lines aren’t shown here.
This diff is large: its 882 lines aren’t shown here.
This diff is large: its 826 lines aren’t shown here.
This diff is large: its 716 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 156 lines aren’t shown here.
This diff is large: its 1899 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 1707 lines aren’t shown here.
This diff is large: its 225 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 677 lines aren’t shown here.
This diff is large: its 156 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 200 lines aren’t shown here.
This diff is large: its 202 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 490 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 257 lines aren’t shown here.
This diff is large: its 1080 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 564 lines aren’t shown here.
This diff is large: its 260 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 505 lines aren’t shown here.
This diff is large: its 242 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 345 lines aren’t shown here.
This diff is large: its 373 lines aren’t shown here.
Binary file not shown.
This diff is large: its 345 lines aren’t shown here.
Binary file not shown.
This diff is large: its 328 lines aren’t shown here.
This diff is large: its 363 lines aren’t shown here.
This diff is large: its 853 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 2121 lines aren’t shown here.
This diff is large: its 770 lines aren’t shown here.
This diff is large: its 1640 lines aren’t shown here.
This diff is large: its 1295 lines aren’t shown here.
This diff is large: its 377 lines aren’t shown here.
This diff is large: its 332 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 313 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 503 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 155 lines aren’t shown here.
This diff is large: its 182 lines aren’t shown here.
This diff is large: its 182 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 333 lines aren’t shown here.
This diff is large: its 615 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 556 lines aren’t shown here.
This diff is large: its 227 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 774 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 483 lines aren’t shown here.
This diff is large: its 428 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 553 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 436 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 191 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 217 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 280 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 510 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 174 lines aren’t shown here.
This diff is large: its 174 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 217 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 231 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 333 lines aren’t shown here.
This diff is large: its 615 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 412 lines aren’t shown here.
This diff is large: its 532 lines aren’t shown here.
This diff is large: its 213 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 1988 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 361 lines aren’t shown here.
This diff is large: its 188 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 464 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 389 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 419 lines aren’t shown here.
This diff is large: its 528 lines aren’t shown here.
Empty file added.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 180 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
Binary file not shown.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 243 lines aren’t shown here.
Binary file not shown.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 234 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 235 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 178 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 136 lines aren’t shown here.
This diff is large: its 1201 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 703 lines aren’t shown here.
This diff is large: its 180 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 256 lines aren’t shown here.
This diff is large: its 201 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 267 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 136 lines aren’t shown here.
This diff is large: its 372 lines aren’t shown here.
This diff is large: its 1057 lines aren’t shown here.
This diff is large: its 169 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 352 lines aren’t shown here.
This diff is large: its 175 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 140 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 618 lines aren’t shown here.
This diff is large: its 370 lines aren’t shown here.
This diff is large: its 1065 lines aren’t shown here.
This diff is large: its 830 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 971 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 606 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 302 lines aren’t shown here.
This diff is large: its 796 lines aren’t shown here.
This diff is large: its 720 lines aren’t shown here.
This diff is large: its 335 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 982 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 582 lines aren’t shown here.
This diff is large: its 140 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 620 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 393 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 629 lines aren’t shown here.
This diff is large: its 599 lines aren’t shown here.
This diff is large: its 613 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 211 lines aren’t shown here.
This diff is large: its 614 lines aren’t shown here.
This diff is large: its 698 lines aren’t shown here.
This diff is large: its 621 lines aren’t shown here.
This diff is large: its 214 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 384 lines aren’t shown here.
This diff is large: its 274 lines aren’t shown here.
This diff is large: its 406 lines aren’t shown here.
This diff is large: its 240 lines aren’t shown here.
This diff is large: its 611 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 614 lines aren’t shown here.
This diff is large: its 210 lines aren’t shown here.
This diff is large: its 232 lines aren’t shown here.
This diff is large: its 682 lines aren’t shown here.
This diff is large: its 232 lines aren’t shown here.
This diff is large: its 521 lines aren’t shown here.
This diff is large: its 1420 lines aren’t shown here.
This diff is large: its 448 lines aren’t shown here.
This diff is large: its 153 lines aren’t shown here.
This diff is large: its 867 lines aren’t shown here.
This diff is large: its 793 lines aren’t shown here.
This diff is large: its 283 lines aren’t shown here.
This diff is large: its 491 lines aren’t shown here.
This diff is large: its 918 lines aren’t shown here.
This diff is large: its 292 lines aren’t shown here.
This diff is large: its 324 lines aren’t shown here.
This diff is large: its 1409 lines aren’t shown here.
This diff is large: its 806 lines aren’t shown here.
This diff is large: its 674 lines aren’t shown here.
This diff is large: its 731 lines aren’t shown here.
This diff is large: its 1722 lines aren’t shown here.
This diff is large: its 858 lines aren’t shown here.
This diff is large: its 853 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 748 lines aren’t shown here.
This diff is large: its 186 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 154 lines aren’t shown here.
This diff is large: its 264 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 1657 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 193 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 1086 lines aren’t shown here.
This diff is large: its 3178 lines aren’t shown here.
This diff is large: its 650 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 377 lines aren’t shown here.
This diff is large: its 136 lines aren’t shown here.
This diff is large: its 291 lines aren’t shown here.
This diff is large: its 1057 lines aren’t shown here.
This diff is large: its 763 lines aren’t shown here.
This diff is large: its 1308 lines aren’t shown here.
This diff is large: its 180 lines aren’t shown here.
Binary file not shown.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 173 lines aren’t shown here.
This diff is large: its 186 lines aren’t shown here.
This diff is large: its 256 lines aren’t shown here.
This diff is large: its 201 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 918 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 489 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 390 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 349 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 1187 lines aren’t shown here.
This diff is large: its 414 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 199 lines aren’t shown here.
This diff is large: its 225 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 483 lines aren’t shown here.
This diff is large: its 561 lines aren’t shown here.
This diff is large: its 565 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 253 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 484 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 217 lines aren’t shown here.
This diff is large: its 473 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 162 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 288 lines aren’t shown here.
This diff is large: its 219 lines aren’t shown here.
This diff is large: its 720 lines aren’t shown here.
This diff is large: its 1041 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 484 lines aren’t shown here.
This diff is large: its 169 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 290 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 526 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 167 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 766 lines aren’t shown here.
This diff is large: its 932 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 745 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 1170 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 484 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 321 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 405 lines aren’t shown here.
This diff is large: its 318 lines aren’t shown here.
This diff is large: its 138 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 245 lines aren’t shown here.
This diff is large: its 1008 lines aren’t shown here.
Binary file not shown.
This diff is large: its 499 lines aren’t shown here.
This diff is large: its 630 lines aren’t shown here.
This diff is large: its 161 lines aren’t shown here.
This diff is large: its 1557 lines aren’t shown here.
This diff is large: its 667 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 696 lines aren’t shown here.
This diff is large: its 180 lines aren’t shown here.
This diff is large: its 1195 lines aren’t shown here.
This diff is large: its 244 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 618 lines aren’t shown here.
This diff is large: its 1077 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 498 lines aren’t shown here.
This diff is large: its 1451 lines aren’t shown here.
This diff is large: its 290 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 529 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 971 lines aren’t shown here.
This diff is large: its 440 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 686 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 833 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 244 lines aren’t shown here.
This diff is large: its 555 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 379 lines aren’t shown here.
This diff is large: its 152 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 204 lines aren’t shown here.
This diff is large: its 1119 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 941 lines aren’t shown here.
This diff is large: its 369 lines aren’t shown here.
This diff is large: its 540 lines aren’t shown here.
This diff is large: its 1083 lines aren’t shown here.
This diff is large: its 1045 lines aren’t shown here.
This diff is large: its 347 lines aren’t shown here.
This diff is large: its 246 lines aren’t shown here.
This diff is large: its 673 lines aren’t shown here.
This diff is large: its 1064 lines aren’t shown here.
This diff is large: its 1950 lines aren’t shown here.
This diff is large: its 653 lines aren’t shown here.
This diff is large: its 462 lines aren’t shown here.
This diff is large: its 1827 lines aren’t shown here.
This diff is large: its 952 lines aren’t shown here.
This diff is large: its 621 lines aren’t shown here.
This diff is large: its 309 lines aren’t shown here.
This diff is large: its 238 lines aren’t shown here.
This diff is large: its 231 lines aren’t shown here.
This diff is large: its 1829 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 524 lines aren’t shown here.
This diff is large: its 641 lines aren’t shown here.
This diff is large: its 272 lines aren’t shown here.
This diff is large: its 756 lines aren’t shown here.
This diff is large: its 1368 lines aren’t shown here.
This diff is large: its 1326 lines aren’t shown here.
This diff is large: its 995 lines aren’t shown here.
This diff is large: its 813 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 174 lines aren’t shown here.
This diff is large: its 2133 lines aren’t shown here.
This diff is large: its 1225 lines aren’t shown here.
This diff is large: its 4859 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 1969 lines aren’t shown here.
This diff is large: its 735 lines aren’t shown here.
This diff is large: its 781 lines aren’t shown here.
This diff is large: its 197 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 372 lines aren’t shown here.
This diff is large: its 184 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 744 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 329 lines aren’t shown here.
This diff is large: its 315 lines aren’t shown here.
This diff is large: its 200 lines aren’t shown here.
This diff is large: its 324 lines aren’t shown here.
This diff is large: its 478 lines aren’t shown here.
This diff is large: its 954 lines aren’t shown here.
This diff is large: its 458 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 571 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 322 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 816 lines aren’t shown here.
This diff is large: its 226 lines aren’t shown here.
This diff is large: its 140 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 155 lines aren’t shown here.
This diff is large: its 253 lines aren’t shown here.
This diff is large: its 1342 lines aren’t shown here.
This diff is large: its 2849 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 214 lines aren’t shown here.
This diff is large: its 154 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 411 lines aren’t shown here.
This diff is large: its 174 lines aren’t shown here.
This diff is large: its 2139 lines aren’t shown here.
This diff is large: its 774 lines aren’t shown here.
This diff is large: its 449 lines aren’t shown here.
This diff is large: its 2207 lines aren’t shown here.
This diff is large: its 1250 lines aren’t shown here.
This diff is large: its 395 lines aren’t shown here.
This diff is large: its 572 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 741 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 138 lines aren’t shown here.
This diff is large: its 161 lines aren’t shown here.
This diff is large: its 1539 lines aren’t shown here.
This diff is large: its 242 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 191 lines aren’t shown here.
This diff is large: its 246 lines aren’t shown here.
This diff is large: its 292 lines aren’t shown here.
This diff is large: its 278 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 226 lines aren’t shown here.
This diff is large: its 271 lines aren’t shown here.
This diff is large: its 275 lines aren’t shown here.
This diff is large: its 283 lines aren’t shown here.
This diff is large: its 1251 lines aren’t shown here.
This diff is large: its 290 lines aren’t shown here.
This diff is large: its 604 lines aren’t shown here.
This diff is large: its 542 lines aren’t shown here.
This diff is large: its 374 lines aren’t shown here.
This diff is large: its 237 lines aren’t shown here.
This diff is large: its 621 lines aren’t shown here.
This diff is large: its 572 lines aren’t shown here.
This diff is large: its 587 lines aren’t shown here.
This diff is large: its 217 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 387 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 1269 lines aren’t shown here.
This diff is large: its 328 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 908 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 964 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 1432 lines aren’t shown here.
This diff is large: its 540 lines aren’t shown here.
This diff is large: its 435 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 948 lines aren’t shown here.
This diff is large: its 1166 lines aren’t shown here.
This diff is large: its 151 lines aren’t shown here.
This diff is large: its 1207 lines aren’t shown here.
This diff is large: its 249 lines aren’t shown here.
This diff is large: its 1275 lines aren’t shown here.
This diff is large: its 1001 lines aren’t shown here.
This diff is large: its 2089 lines aren’t shown here.
This diff is large: its 606 lines aren’t shown here.
This diff is large: its 152 lines aren’t shown here.
This diff is large: its 366 lines aren’t shown here.
This diff is large: its 339 lines aren’t shown here.
This diff is large: its 642 lines aren’t shown here.
This diff is large: its 1366 lines aren’t shown here.
This diff is large: its 228 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 231 lines aren’t shown here.
This diff is large: its 1532 lines aren’t shown here.
This diff is large: its 744 lines aren’t shown here.
This diff is large: its 1205 lines aren’t shown here.
This diff is large: its 1091 lines aren’t shown here.
This diff is large: its 228 lines aren’t shown here.
This diff is large: its 465 lines aren’t shown here.
This diff is large: its 280 lines aren’t shown here.
This diff is large: its 723 lines aren’t shown here.
This diff is large: its 1511 lines aren’t shown here.
This diff is large: its 154 lines aren’t shown here.
This diff is large: its 1475 lines aren’t shown here.
This diff is large: its 447 lines aren’t shown here.
This diff is large: its 727 lines aren’t shown here.
This diff is large: its 1437 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 916 lines aren’t shown here.
This diff is large: its 181 lines aren’t shown here.
This diff is large: its 749 lines aren’t shown here.
This diff is large: its 418 lines aren’t shown here.
This diff is large: its 1126 lines aren’t shown here.
This diff is large: its 186 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 627 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 239 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 217 lines aren’t shown here.
This diff is large: its 1326 lines aren’t shown here.
This diff is large: its 168 lines aren’t shown here.
This diff is large: its 135 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 180 lines aren’t shown here.
This diff is large: its 338 lines aren’t shown here.
This diff is large: its 305 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 1031 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 212 lines aren’t shown here.
This diff is large: its 187 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 217 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 672 lines aren’t shown here.
This diff is large: its 135 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 279 lines aren’t shown here.
This diff is large: its 162 lines aren’t shown here.
This diff is large: its 278 lines aren’t shown here.
This diff is large: its 674 lines aren’t shown here.
This diff is large: its 320 lines aren’t shown here.
This diff is large: its 153 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 789 lines aren’t shown here.
This diff is large: its 1530 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 113 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 359 lines aren’t shown here.
This diff is large: its 1126 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 284 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 247 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 319 lines aren’t shown here.
This diff is large: its 618 lines aren’t shown here.
This diff is large: its 170 lines aren’t shown here.
This diff is large: its 1071 lines aren’t shown here.
This diff is large: its 245 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 484 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 562 lines aren’t shown here.
This diff is large: its 549 lines aren’t shown here.
This diff is large: its 253 lines aren’t shown here.
This diff is large: its 384 lines aren’t shown here.
This diff is large: its 361 lines aren’t shown here.
This diff is large: its 588 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 429 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 393 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 318 lines aren’t shown here.
This diff is large: its 618 lines aren’t shown here.
This diff is large: its 166 lines aren’t shown here.
This diff is large: its 762 lines aren’t shown here.
This diff is large: its 378 lines aren’t shown here.
This diff is large: its 170 lines aren’t shown here.
This diff is large: its 782 lines aren’t shown here.
This diff is large: its 234 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 484 lines aren’t shown here.
This diff is large: its 588 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 275 lines aren’t shown here.
This diff is large: its 531 lines aren’t shown here.
This diff is large: its 247 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 361 lines aren’t shown here.
This diff is large: its 501 lines aren’t shown here.
This diff is large: its 366 lines aren’t shown here.
This diff is large: its 162 lines aren’t shown here.
This diff is large: its 602 lines aren’t shown here.
This diff is large: its 184 lines aren’t shown here.
This diff is large: its 589 lines aren’t shown here.
This diff is large: its 704 lines aren’t shown here.
This diff is large: its 698 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 1149 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 333 lines aren’t shown here.
This diff is large: its 245 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 609 lines aren’t shown here.
This diff is large: its 695 lines aren’t shown here.
This diff is large: its 1152 lines aren’t shown here.
This diff is large: its 570 lines aren’t shown here.
This diff is large: its 728 lines aren’t shown here.
This diff is large: its 1484 lines aren’t shown here.
This diff is large: its 202 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 1434 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 330 lines aren’t shown here.
This diff is large: its 278 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 421 lines aren’t shown here.
This diff is large: its 1385 lines aren’t shown here.
This diff is large: its 222 lines aren’t shown here.
This diff is large: its 499 lines aren’t shown here.
This diff is large: its 710 lines aren’t shown here.
This diff is large: its 629 lines aren’t shown here.
This diff is large: its 199 lines aren’t shown here.
This diff is large: its 403 lines aren’t shown here.
This diff is large: its 480 lines aren’t shown here.
This diff is large: its 926 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 1397 lines aren’t shown here.
This diff is large: its 426 lines aren’t shown here.
This diff is large: its 340 lines aren’t shown here.
This diff is large: its 320 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 175 lines aren’t shown here.
This diff is large: its 1061 lines aren’t shown here.
This diff is large: its 1222 lines aren’t shown here.
This diff is large: its 695 lines aren’t shown here.
This diff is large: its 965 lines aren’t shown here.
This diff is large: its 904 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 1535 lines aren’t shown here.
This diff is large: its 269 lines aren’t shown here.
This diff is large: its 335 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 1381 lines aren’t shown here.
This diff is large: its 445 lines aren’t shown here.
This diff is large: its 674 lines aren’t shown here.
This diff is large: its 516 lines aren’t shown here.
This diff is large: its 201 lines aren’t shown here.
This diff is large: its 541 lines aren’t shown here.
This diff is large: its 480 lines aren’t shown here.
This diff is large: its 936 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 524 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 1405 lines aren’t shown here.
This diff is large: its 426 lines aren’t shown here.
This diff is large: its 358 lines aren’t shown here.
This diff is large: its 385 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 175 lines aren’t shown here.
This diff is large: its 1077 lines aren’t shown here.
This diff is large: its 1276 lines aren’t shown here.
This diff is large: its 820 lines aren’t shown here.
This diff is large: its 1047 lines aren’t shown here.
This diff is large: its 941 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 1570 lines aren’t shown here.
This diff is large: its 264 lines aren’t shown here.
This diff is large: its 396 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 1403 lines aren’t shown here.
This diff is large: its 445 lines aren’t shown here.
This diff is large: its 539 lines aren’t shown here.
This diff is large: its 552 lines aren’t shown here.
This diff is large: its 183 lines aren’t shown here.
This diff is large: its 674 lines aren’t shown here.
This diff is large: its 690 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 198 lines aren’t shown here.
This diff is large: its 1157 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 350 lines aren’t shown here.
This diff is large: its 305 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 610 lines aren’t shown here.
This diff is large: its 1441 lines aren’t shown here.
This diff is large: its 1158 lines aren’t shown here.
This diff is large: its 614 lines aren’t shown here.
This diff is large: its 758 lines aren’t shown here.
This diff is large: its 1250 lines aren’t shown here.
This diff is large: its 317 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 252 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 643 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 299 lines aren’t shown here.
This diff is large: its 354 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 1794 lines aren’t shown here.
This diff is large: its 445 lines aren’t shown here.
This diff is large: its 361 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 895 lines aren’t shown here.
This diff is large: its 1558 lines aren’t shown here.
This diff is large: its 254 lines aren’t shown here.
This diff is large: its 943 lines aren’t shown here.
This diff is large: its 1263 lines aren’t shown here.
This diff is large: its 1638 lines aren’t shown here.
This diff is large: its 821 lines aren’t shown here.
This diff is large: its 195 lines aren’t shown here.
This diff is large: its 521 lines aren’t shown here.
This diff is large: its 705 lines aren’t shown here.
This diff is large: its 896 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 446 lines aren’t shown here.
This diff is large: its 1822 lines aren’t shown here.
This diff is large: its 2712 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 338 lines aren’t shown here.
This diff is large: its 375 lines aren’t shown here.
This diff is large: its 283 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 429 lines aren’t shown here.
This diff is large: its 758 lines aren’t shown here.
This diff is large: its 1256 lines aren’t shown here.
This diff is large: its 843 lines aren’t shown here.
This diff is large: its 648 lines aren’t shown here.
This diff is large: its 1411 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 503 lines aren’t shown here.
This diff is large: its 350 lines aren’t shown here.
This diff is large: its 293 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 1493 lines aren’t shown here.
This diff is large: its 655 lines aren’t shown here.
This diff is large: its 764 lines aren’t shown here.
This diff is large: its 1388 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 147 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 318 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 1286 lines aren’t shown here.
This diff is large: its 403 lines aren’t shown here.
This diff is large: its 153 lines aren’t shown here.
This diff is larger than a page shows: the files after these aren’t listed. Clone the repository to see all of it.