00001
00002
00003
00004 #define BIOS 1
00005 #define nil 0
00006 #define _POSIX_SOURCE 1
00007 #define _MINIX 1
00008 #include <stddef.h>
00009 #include <sys/types.h>
00010 #include <sys/stat.h>
00011 #include <stdlib.h>
00012 #include <stdio.h>
00013 #include <limits.h>
00014 #include <string.h>
00015 #include <errno.h>
00016 #include <a.out.h>
00017 #include <minix/config.h>
00018 #include <minix/const.h>
00019 #include <minix/type.h>
00020 #include <minix/syslib.h>
00021 #include <kernel/const.h>
00022 #include <kernel/type.h>
00023 #include <ibm/partition.h>
00024 #include "rawfs.h"
00025 #include "image.h"
00026 #include "boot.h"
00027
00028 static int block_size = 0;
00029
00030 #define click_shift clck_shft
00031
00032
00033 #define K_I386 0x0001
00034 #define K_CLAIM 0x0002
00035 #define K_CHMEM 0x0004
00036 #define K_HIGH 0x0008
00037 #define K_HDR 0x0010
00038 #define K_RET 0x0020
00039 #define K_INT86 0x0040
00040 #define K_MEML 0x0080
00041 #define K_BRET 0x0100
00042 #define K_ALL 0x01FF
00043
00044
00045
00046
00047 #define PROCESS_MAX 16
00048 #define KERNEL 0
00049 #define FS 2
00050
00051 struct process {
00052 u32_t entry;
00053 u32_t cs;
00054 u32_t ds;
00055 u32_t data;
00056 u32_t end;
00057 } process[PROCESS_MAX];
00058 int n_procs;
00059
00060
00061 #define MAGIC_OFF 0
00062 #define CLICK_OFF 2
00063 #define FLAGS_OFF 4
00064 #define KERNEL_D_MAGIC 0x526F
00065
00066
00067 #define P_SIZ_OFF 0
00068 #define P_INIT_OFF 4
00069
00070
00071 #define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
00072
00073 void pretty_image(char *image)
00074
00075
00076
00077
00078
00079
00080 {
00081 int up= 0, c;
00082
00083 while ((c= *image++) != 0) {
00084 if (c == '/' || c == '_') c= ' ';
00085
00086 if (c == 'r' && between('0', *image, '9')) {
00087 printf(" revision ");
00088 continue;
00089 }
00090 if (!up && between('a', c, 'z')) c= c - 'a' + 'A';
00091
00092 if (between('A', c, 'Z')) up= 1;
00093
00094 putch(c);
00095 }
00096 }
00097
00098 void raw_clear(u32_t addr, u32_t count)
00099
00100 {
00101 static char zeros[128];
00102 u32_t dst;
00103 u32_t zct;
00104
00105 zct= sizeof(zeros);
00106 if (zct > count) zct= count;
00107 raw_copy(addr, mon2abs(&zeros), zct);
00108 count-= zct;
00109
00110 while (count > 0) {
00111 dst= addr + zct;
00112 if (zct > count) zct= count;
00113 raw_copy(dst, addr, zct);
00114 count-= zct;
00115 zct*= 2;
00116 }
00117 }
00118
00119
00120 #define align(a, n) (((u32_t)(a) + ((u32_t)(n) - 1)) & ~((u32_t)(n) - 1))
00121 unsigned click_shift;
00122 unsigned click_size;
00123 unsigned k_flags;
00124 u32_t reboot_code;
00125
00126 int params2params(char *params, size_t psize)
00127
00128 {
00129 size_t i, n;
00130 environment *e;
00131 char *name, *value;
00132 dev_t dev;
00133
00134 i= 0;
00135 for (e= env; e != nil; e= e->next) {
00136 name= e->name;
00137 value= e->value;
00138
00139 if (!(e->flags & E_VAR)) continue;
00140
00141 if (e->flags & E_DEV) {
00142 if ((dev= name2dev(value)) == -1) return 0;
00143 value= ul2a10((u16_t) dev);
00144 }
00145
00146 n= i + strlen(name) + 1 + strlen(value) + 1;
00147 if (n < psize) {
00148 strcpy(params + i, name);
00149 strcat(params + i, "=");
00150 strcat(params + i, value);
00151 }
00152 i= n;
00153 }
00154
00155 if (!(k_flags & K_MEML)) {
00156
00157
00158 value= ul2a10((mem[0].base + mem[0].size) / 1024);
00159 n= i + 7 + 1 + strlen(value) + 1;
00160 if (n < psize) {
00161 strcpy(params + i, "memsize=");
00162 strcat(params + i, value);
00163 }
00164 i= n;
00165 value= ul2a10(mem[1].size / 1024);
00166 n= i + 7 + 1 + strlen(value) + 1;
00167 if (n < psize) {
00168 strcpy(params + i, "emssize=");
00169 strcat(params + i, value);
00170 }
00171 i= n;
00172 }
00173
00174 if (i >= psize) {
00175 printf("Too many boot parameters\n");
00176 return 0;
00177 }
00178 params[i]= 0;
00179 return 1;
00180 }
00181
00182 void patch_sizes(void)
00183
00184
00185
00186
00187 {
00188 u16_t text_size, data_size;
00189 int i;
00190 struct process *procp, *initp;
00191 u32_t doff;
00192
00193 if (k_flags & K_HDR) return;
00194
00195
00196
00197 doff= process[KERNEL].data + P_SIZ_OFF;
00198
00199 for (i= 0; i < n_procs; i++) {
00200 procp= &process[i];
00201 text_size= (procp->ds - procp->cs) >> click_shift;
00202 data_size= (procp->end - procp->ds) >> click_shift;
00203
00204
00205 put_word(doff, text_size); doff+= 2;
00206 put_word(doff, data_size); doff+= 2;
00207
00208 initp= procp;
00209 }
00210
00211 if (k_flags & (K_HIGH|K_MEML)) return;
00212
00213
00214 put_word(process[FS].data + P_INIT_OFF+0, initp->cs >> click_shift);
00215 put_word(process[FS].data + P_INIT_OFF+2, text_size);
00216 put_word(process[FS].data + P_INIT_OFF+4, data_size);
00217 }
00218
00219 int selected(char *name)
00220
00221 {
00222 char *colon, *label;
00223 int cmp;
00224
00225 if ((colon= strchr(name, ':')) == nil) return 1;
00226 if ((label= b_value("label")) == nil) return 1;
00227
00228 *colon= 0;
00229 cmp= strcmp(label, name);
00230 *colon= ':';
00231 return cmp == 0;
00232 }
00233
00234 u32_t proc_size(struct image_header *hdr)
00235
00236 {
00237 u32_t len= hdr->process.a_text;
00238
00239 if (hdr->process.a_flags & A_PAL) len+= hdr->process.a_hdrlen;
00240 if (hdr->process.a_flags & A_SEP) len= align(len, SECTOR_SIZE);
00241 len= align(len + hdr->process.a_data, SECTOR_SIZE);
00242
00243 return len >> SECTOR_SHIFT;
00244 }
00245
00246 off_t image_off, image_size;
00247 u32_t (*vir2sec)(u32_t vsec);
00248
00249 u32_t file_vir2sec(u32_t vsec)
00250
00251 {
00252 off_t blk;
00253
00254 if(!block_size) { errno = 0; return -1; }
00255
00256 if ((blk= r_vir2abs(vsec / RATIO(block_size))) == -1) {
00257 errno= EIO;
00258 return -1;
00259 }
00260 return blk == 0 ? 0 : lowsec + blk * RATIO(block_size) + vsec % RATIO(block_size);
00261 }
00262
00263 u32_t flat_vir2sec(u32_t vsec)
00264
00265 {
00266 return lowsec + image_off + vsec;
00267 }
00268
00269 char *get_sector(u32_t vsec)
00270
00271
00272
00273
00274 {
00275 u32_t sec;
00276 int r;
00277 #define SECBUFS 16
00278 static char buf[SECBUFS * SECTOR_SIZE];
00279 static size_t count;
00280 static u32_t bufsec;
00281
00282 if (vsec == 0) count= 0;
00283
00284 if ((sec= (*vir2sec)(vsec)) == -1) return nil;
00285
00286 if (sec == 0) {
00287
00288 count= 0;
00289 memset(buf, 0, SECTOR_SIZE);
00290 return buf;
00291 }
00292
00293
00294 if ((sec - bufsec) < count) {
00295 return buf + ((size_t) (sec - bufsec) << SECTOR_SHIFT);
00296 }
00297
00298
00299 count= 0;
00300 bufsec= sec;
00301
00302
00303 while (++count < SECBUFS && !dev_boundary(bufsec + count)) {
00304 vsec++;
00305 if ((sec= (*vir2sec)(vsec)) == -1) break;
00306
00307
00308 if (sec != bufsec + count) break;
00309 }
00310
00311
00312 if ((r= readsectors(mon2abs(buf), bufsec, count)) != 0) {
00313 readerr(bufsec, r);
00314 count= 0;
00315 errno= 0;
00316 return nil;
00317 }
00318 return buf;
00319 }
00320
00321 int get_clickshift(u32_t ksec, struct image_header *hdr)
00322
00323 {
00324 char *textp;
00325
00326 if ((textp= get_sector(ksec)) == nil) return 0;
00327
00328 if (hdr->process.a_flags & A_PAL) textp+= hdr->process.a_hdrlen;
00329 click_shift= * (u16_t *) (textp + CLICK_OFF);
00330 k_flags= * (u16_t *) (textp + FLAGS_OFF);
00331
00332 if ((k_flags & ~K_ALL) != 0) {
00333 printf("%s requires features this monitor doesn't offer\n",
00334 hdr->name);
00335 return 0;
00336 }
00337
00338 if (click_shift < HCLICK_SHIFT || click_shift > 16) {
00339 printf("%s click size is bad\n", hdr->name);
00340 errno= 0;
00341 return 0;
00342 }
00343
00344 click_size= 1 << click_shift;
00345
00346 return 1;
00347 }
00348
00349 int get_segment(u32_t *vsec, long *size, u32_t *addr, u32_t limit)
00350
00351 {
00352 char *buf;
00353 size_t cnt, n;
00354
00355 cnt= 0;
00356 while (*size > 0) {
00357 if (cnt == 0) {
00358 if ((buf= get_sector((*vsec)++)) == nil) return 0;
00359 cnt= SECTOR_SIZE;
00360 }
00361 if (*addr + click_size > limit) { errno= ENOMEM; return 0; }
00362 n= click_size;
00363 if (n > cnt) n= cnt;
00364 raw_copy(*addr, mon2abs(buf), n);
00365 *addr+= n;
00366 *size-= n;
00367 buf+= n;
00368 cnt-= n;
00369 }
00370
00371
00372 n= align(*addr, click_size) - *addr;
00373 raw_clear(*addr, n);
00374 *addr+= n;
00375 *size-= n;
00376 return 1;
00377 }
00378
00379 void exec_image(char *image)
00380
00381 {
00382 char *delayvalue;
00383 int i;
00384 struct image_header hdr;
00385 char *buf;
00386 u32_t vsec, addr, limit, aout, n;
00387 struct process *procp;
00388 long a_text, a_data, a_bss, a_stack;
00389 int banner= 0;
00390 long processor= a2l(b_value("processor"));
00391 u16_t mode;
00392 char *console;
00393 char params[SECTOR_SIZE];
00394 extern char *sbrk(int);
00395
00396
00397 (void) sbrk(0);
00398
00399 printf("\nLoading ");
00400 pretty_image(image);
00401 printf(".\n\n");
00402
00403 vsec= 0;
00404 addr= mem[0].base;
00405 limit= mem[0].base + mem[0].size;
00406 if (limit > caddr) limit= caddr;
00407
00408
00409 aout = (limit -= PROCESS_MAX * A_MINHDR);
00410
00411
00412 raw_clear(aout, PROCESS_MAX * A_MINHDR);
00413
00414
00415 for (i= 0; vsec < image_size; i++) {
00416 if (i == PROCESS_MAX) {
00417 printf("There are more then %d programs in %s\n",
00418 PROCESS_MAX, image);
00419 errno= 0;
00420 return;
00421 }
00422 procp= &process[i];
00423
00424
00425 for (;;) {
00426 if ((buf= get_sector(vsec++)) == nil) return;
00427
00428 memcpy(&hdr, buf, sizeof(hdr));
00429
00430 if (BADMAG(hdr.process)) { errno= ENOEXEC; return; }
00431
00432
00433 if (selected(hdr.name)) break;
00434
00435
00436 vsec+= proc_size(&hdr);
00437 }
00438
00439
00440 if (hdr.process.a_cpu == A_I80386 && processor < 386) {
00441 printf("You can't run a 386 kernel on this 80%ld\n",
00442 processor);
00443 errno= 0;
00444 return;
00445 }
00446
00447
00448 if (i == KERNEL) {
00449 if (!get_clickshift(vsec, &hdr)) return;
00450 addr= align(addr, click_size);
00451 }
00452
00453
00454
00455
00456 hdr.process.a_syms= addr;
00457 raw_copy(aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR);
00458
00459 if (!banner) {
00460 printf(" cs ds text data bss");
00461 if (k_flags & K_CHMEM) printf(" stack");
00462 putch('\n');
00463 banner= 1;
00464 }
00465
00466
00467 a_text= hdr.process.a_text;
00468 a_data= hdr.process.a_data;
00469 a_bss= hdr.process.a_bss;
00470 if (k_flags & K_CHMEM) {
00471 a_stack= hdr.process.a_total - a_data - a_bss;
00472 if (!(hdr.process.a_flags & A_SEP)) a_stack-= a_text;
00473 } else {
00474 a_stack= 0;
00475 }
00476
00477
00478 procp->cs= addr;
00479
00480
00481
00482
00483 procp->entry= hdr.process.a_entry;
00484 if (hdr.process.a_flags & A_PAL) a_text+= hdr.process.a_hdrlen;
00485 if (hdr.process.a_flags & A_UZP) procp->cs-= click_size;
00486
00487
00488 if (hdr.process.a_flags & A_SEP) {
00489
00490 if (!get_segment(&vsec, &a_text, &addr, limit)) return;
00491
00492
00493 procp->ds= addr;
00494 if (hdr.process.a_flags & A_UZP) procp->ds-= click_size;
00495 procp->data= addr;
00496 } else {
00497
00498 procp->data= addr + a_text;
00499 procp->ds= procp->cs;
00500 a_data+= a_text;
00501 }
00502
00503
00504 if (!get_segment(&vsec, &a_data, &addr, limit)) return;
00505
00506
00507 if (i != KERNEL && (k_flags & K_CLAIM)) a_bss= a_stack= 0;
00508
00509 printf("%07lx %07lx %8ld %8ld %8ld",
00510 procp->cs, procp->ds,
00511 hdr.process.a_text, hdr.process.a_data,
00512 hdr.process.a_bss
00513 );
00514 if (k_flags & K_CHMEM) printf(" %8ld", a_stack);
00515
00516 printf(" %s\n", hdr.name);
00517
00518
00519
00520
00521
00522
00523 a_bss+= a_data;
00524 n= align(a_bss, click_size);
00525 a_bss-= n;
00526
00527
00528 if (addr + n > limit) { errno= ENOMEM; return; }
00529 raw_clear(addr, n);
00530 addr+= n;
00531
00532
00533 a_stack+= a_bss;
00534 n= align(a_stack, click_size);
00535 a_stack-= n;
00536
00537
00538 addr+= n;
00539
00540
00541 procp->end= addr;
00542
00543 if (i == 0 && (k_flags & K_HIGH)) {
00544
00545 addr= mem[1].base;
00546 limit= mem[1].base + mem[1].size;
00547 }
00548 }
00549
00550 if ((n_procs= i) == 0) {
00551 printf("There are no programs in %s\n", image);
00552 errno= 0;
00553 return;
00554 }
00555
00556
00557 if (get_word(process[KERNEL].data + MAGIC_OFF) != KERNEL_D_MAGIC) {
00558 printf("Kernel magic number is incorrect\n");
00559 errno= 0;
00560 return;
00561 }
00562
00563
00564 patch_sizes();
00565
00566 #if !DOS
00567 if (!(k_flags & K_MEML)) {
00568
00569 raw_copy(HEADERPOS, aout, PROCESS_MAX * A_MINHDR);
00570 }
00571 #endif
00572
00573
00574 if((delayvalue = b_value("bootdelay")) != nil > 0) {
00575 delay(delayvalue);
00576 }
00577
00578
00579 if (!run_trailer()) { errno= 0; return; }
00580
00581
00582 if (!params2params(params, sizeof(params))) { errno= 0; return; }
00583
00584
00585 if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) {
00586 mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE :
00587 MONO_MODE;
00588 }
00589 set_mode(mode);
00590
00591
00592 (void) dev_close();
00593
00594
00595 minix(process[KERNEL].entry, process[KERNEL].cs,
00596 process[KERNEL].ds, params, sizeof(params), aout);
00597
00598 if (!(k_flags & K_BRET)) {
00599 extern u32_t reboot_code;
00600 raw_copy(mon2abs(params), reboot_code, sizeof(params));
00601 }
00602 parse_code(params);
00603
00604
00605 fsok= -1;
00606 errno= 0;
00607
00608
00609 scan_keyboard();
00610 }
00611
00612 ino_t latest_version(char *version, struct stat *stp)
00613
00614
00615
00616 {
00617 char name[NAME_MAX + 1];
00618 ino_t ino, newest;
00619 time_t mtime;
00620
00621 if ((ino= r_readdir(name)) == 0) { stp->st_mtime= 0; return 0; }
00622
00623 newest= latest_version(version, stp);
00624 mtime= stp->st_mtime;
00625 r_stat(ino, stp);
00626
00627 if (S_ISREG(stp->st_mode) && stp->st_mtime > mtime) {
00628 newest= ino;
00629 strcpy(version, name);
00630 } else {
00631 stp->st_mtime= mtime;
00632 }
00633 return newest;
00634 }
00635
00636 char *select_image(char *image)
00637
00638
00639
00640
00641
00642 {
00643 ino_t image_ino;
00644 struct stat st;
00645
00646 image= strcpy(malloc((strlen(image) + 1 + NAME_MAX + 1)
00647 * sizeof(char)), image);
00648
00649 fsok= r_super(&block_size) != 0;
00650 if (!fsok || (image_ino= r_lookup(ROOT_INO, image)) == 0) {
00651 char *size;
00652
00653 if (numprefix(image, &size) && *size++ == ':'
00654 && numeric(size)) {
00655 vir2sec= flat_vir2sec;
00656 image_off= a2l(image);
00657 image_size= a2l(size);
00658 strcpy(image, "Minix");
00659 return image;
00660 }
00661 if (!fsok)
00662 printf("No image selected\n");
00663 else
00664 printf("Can't load %s: %s\n", image, unix_err(errno));
00665 goto bail_out;
00666 }
00667
00668 r_stat(image_ino, &st);
00669 if (!S_ISREG(st.st_mode)) {
00670 char *version= image + strlen(image);
00671 char dots[NAME_MAX + 1];
00672
00673 if (!S_ISDIR(st.st_mode)) {
00674 printf("%s: %s\n", image, unix_err(ENOTDIR));
00675 goto bail_out;
00676 }
00677 (void) r_readdir(dots);
00678 (void) r_readdir(dots);
00679 *version++= '/';
00680 *version= 0;
00681 if ((image_ino= latest_version(version, &st)) == 0) {
00682 printf("There are no images in %s\n", image);
00683 goto bail_out;
00684 }
00685 r_stat(image_ino, &st);
00686 }
00687 vir2sec= file_vir2sec;
00688 image_size= (st.st_size + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
00689 return image;
00690 bail_out:
00691 free(image);
00692 return nil;
00693 }
00694
00695 void bootminix(void)
00696
00697
00698
00699 {
00700 char *image;
00701
00702 if ((image= select_image(b_value("image"))) == nil) return;
00703
00704 exec_image(image);
00705
00706 switch (errno) {
00707 case ENOEXEC:
00708 printf("%s contains a bad program header\n", image);
00709 break;
00710 case ENOMEM:
00711 printf("Not enough memory to load %s\n", image);
00712 break;
00713 case EIO:
00714 printf("Unsuspected EOF on %s\n", image);
00715 case 0:
00716 ;
00717 }
00718 free(image);
00719 }
00720
00721
00722
00723