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.