1 /* $NetBSD: loadbsd.c,v 1.16 2001/09/27 14:29:22 leo Exp $ */ 2 3 /* 4 * Copyright (c) 1995 L. Weppelman 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Leo Weppelman. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * NetBSD loader for the Atari-TT. 35 */ 36 37 #include "exec_elf.h" 38 #include <a_out.h> 39 #include <fcntl.h> 40 #include <stdio.h> 41 #include <osbind.h> 42 #include <stdarg.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 #include "libtos.h" 47 #include "loader.h" 48 49 #ifdef COMPRESSED_READ 50 #define open copen 51 #define read cread 52 #define lseek clseek 53 #define close cclose 54 #endif /* COMPRESSED_READ */ 55 56 char *Progname; /* How are we called */ 57 int d_flag = 0; /* Output debugging output? */ 58 int h_flag = 0; /* show help */ 59 int N_flag = 0; /* No symbols? */ 60 int s_flag = 0; /* St-ram only */ 61 int t_flag = 0; /* Just test, do not execute */ 62 int v_flag = 0; /* show version */ 63 64 const char version[] = "$Revision: 1.16 $"; 65 66 /* 67 * Default name of kernel to boot, large enough to patch 68 */ 69 char kname[80] = "n:/netbsd"; 70 71 static struct kparamb kparam; 72 73 void help PROTO((void)); 74 void usage PROTO((void)); 75 int aout_load PROTO((int)); 76 int elf_load PROTO((int)); 77 void get_sys_info PROTO((void)); 78 void start_kernel PROTO((void)); 79 80 #define ELFMAGIC ((ELFMAG0 << 24) | (ELFMAG1 << 16) | \ 81 (ELFMAG2 << 8) | ELFMAG3) 82 int 83 main(argc, argv) 84 int argc; 85 char **argv; 86 { 87 /* 88 * Option parsing 89 */ 90 extern int optind; 91 extern char *optarg; 92 int ch; 93 int fd; 94 95 init_toslib(argv[0]); 96 Progname = argv[0]; 97 98 kparam.boothowto = RB_SINGLE; 99 100 while ((ch = getopt(argc, argv, "abdDhNstVwo:S:T:")) != -1) { 101 switch (ch) { 102 case 'a': 103 kparam.boothowto &= ~(RB_SINGLE); 104 kparam.boothowto |= RB_AUTOBOOT; 105 break; 106 case 'b': 107 kparam.boothowto |= RB_ASKNAME; 108 break; 109 case 'd': 110 kparam.boothowto |= RB_KDB; 111 break; 112 case 'D': 113 d_flag = 1; 114 break; 115 case 'h': 116 h_flag = 1; 117 break; 118 case 'N': 119 N_flag = 1; 120 break; 121 case 'o': 122 redirect_output(optarg); 123 break; 124 case 's': 125 s_flag = 1; 126 break; 127 case 'S': 128 kparam.stmem_size = atoi(optarg); 129 break; 130 case 't': 131 t_flag = 1; 132 break; 133 case 'T': 134 kparam.ttmem_size = atoi(optarg); 135 break; 136 case 'V': 137 v_flag = 1; 138 break; 139 case 'w': 140 set_wait_for_key(); 141 break; 142 default: 143 usage(); 144 } 145 } 146 argc -= optind; 147 argv += optind; 148 if (argc == 1) 149 strcpy(kname, argv[0]); 150 151 if (h_flag) 152 help(); 153 if (v_flag) 154 eprintf("%s\r\n", version); 155 156 /* 157 * Get system info to pass to NetBSD 158 */ 159 get_sys_info(); 160 161 /* 162 * Find the kernel to boot and read it's exec-header 163 */ 164 if ((fd = open(kname, O_RDONLY)) < 0) 165 fatal(-1, "Cannot open kernel '%s'", kname); 166 if (elf_load(fd) == 0) 167 if (aout_load(fd) == 0) 168 fatal(-1, "Not an ELF or NMAGIC file '%s'", kname); 169 close(fd); 170 171 if (d_flag) { 172 eprintf("\r\nKernel info:\r\n"); 173 eprintf("Kernel loadaddr\t: 0x%08x\r\n", kparam.kp); 174 eprintf("Kernel size\t: %10d bytes\r\n", kparam.ksize); 175 eprintf("Kernel entry\t: 0x%08x\r\n", kparam.entry); 176 eprintf("Kernel esym\t: 0x%08x\r\n", kparam.esym_loc); 177 } 178 179 if (!t_flag) 180 start_kernel(); 181 /* NOT REACHED */ 182 183 eprintf("Kernel '%s' was loaded OK\r\n", kname); 184 xexit(0); 185 return 0; 186 } 187 188 int 189 aout_load(fd) 190 int fd; 191 { 192 long textsz, stringsz; 193 struct exec ehdr; 194 195 lseek(fd, (off_t)0, SEEK_SET); 196 if (read(fd, (char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) 197 return 0; 198 199 if (N_MAGIC(ehdr) != NMAGIC) 200 return 0; 201 202 /* 203 * Extract various sizes from the kernel executable 204 */ 205 textsz = (ehdr.a_text + __LDPGSZ - 1) & ~(__LDPGSZ - 1); 206 kparam.esym_loc = 0; 207 kparam.ksize = textsz + ehdr.a_data + ehdr.a_bss; 208 kparam.entry = ehdr.a_entry; 209 210 if (!N_flag && ehdr.a_syms) { 211 if (lseek(fd,ehdr.a_text+ehdr.a_data+ehdr.a_syms+sizeof(ehdr),0) 212 <= 0) 213 fatal(-1, "Cannot seek to string table in '%s'", kname); 214 if (read(fd, (char *)&stringsz, sizeof(long)) != sizeof(long)) 215 fatal(-1, "Cannot read string-table size"); 216 if (lseek(fd, sizeof(ehdr), 0) <= 0) 217 fatal(-1, "Cannot seek back to text start"); 218 kparam.ksize += ehdr.a_syms + sizeof(long) + stringsz; 219 } 220 221 if ((kparam.kp = (u_char *)malloc(kparam.ksize)) == NULL) 222 fatal(-1, "Cannot malloc kernel image space"); 223 224 /* 225 * Read text & data, clear bss 226 */ 227 if ((read(fd, (char *)kparam.kp, ehdr.a_text) != ehdr.a_text) 228 ||(read(fd,(char *)(kparam.kp+textsz),ehdr.a_data) != ehdr.a_data)) 229 fatal(-1, "Unable to read kernel image\n"); 230 memset(kparam.kp + textsz + ehdr.a_data, 0, ehdr.a_bss); 231 232 /* 233 * Read symbol and string table 234 */ 235 if (!N_flag && ehdr.a_syms) { 236 long *p; 237 238 p = (long *)(kparam.kp + textsz + ehdr.a_data + ehdr.a_bss); 239 *p++ = ehdr.a_syms; 240 if (read(fd, (char *)p, ehdr.a_syms) != ehdr.a_syms) 241 fatal(-1, "Cannot read symbol table\n"); 242 p = (long *)((char *)p + ehdr.a_syms); 243 if (read(fd, (char *)p, stringsz) != stringsz) 244 fatal(-1, "Cannot read string table\n"); 245 kparam.esym_loc = (long)((char *)p-(char *)kparam.kp +stringsz); 246 } 247 248 return 1; 249 } 250 251 int 252 elf_load(fd) 253 int fd; 254 { 255 int i,j; 256 Elf32_Ehdr ehdr; 257 Elf32_Phdr *phdrs; 258 Elf32_Word symsize, symstart; 259 long kernsize; 260 261 lseek(fd, (off_t)0, SEEK_SET); 262 if (read(fd, (char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) 263 return 0; 264 265 if (*((u_int *)ehdr.e_ident) != ELFMAGIC) 266 return 0; 267 268 /* 269 * calculate highest used address 270 */ 271 i = ehdr.e_phnum * sizeof(Elf32_Phdr); 272 if ((phdrs = (Elf32_Phdr *)malloc(i)) == NULL) 273 fatal(-1, "Cannot malloc Elf phdr storage space"); 274 if (read(fd, phdrs, i) != i) 275 fatal(-1, "Cannot read Elf32_Phdrs"); 276 277 kernsize = 0; 278 for (i = 0; i < ehdr.e_phnum; i++) { 279 Elf32_Word sum; 280 281 sum = phdrs[i].p_vaddr + phdrs[i].p_memsz; 282 if ((phdrs[i].p_flags & (PF_W|PF_X)) && (sum > kernsize)) 283 kernsize = sum; 284 } 285 286 /* 287 * look for symbols and calculate the size 288 * XXX: This increases the load time by a factor 2 for gzipped 289 * images! 290 */ 291 symsize = 0; 292 symstart = 0; 293 if (!N_flag) { 294 i = ehdr.e_shnum + 1; 295 if (lseek(fd, (off_t)ehdr.e_shoff, SEEK_SET) != ehdr.e_shoff) 296 fatal(-1, "Cannot seek to e_shoff location"); 297 while (--i) { 298 Elf32_Shdr shdr; 299 300 if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr)) 301 fatal(-1, "Cannot read Elf32_shdr"); 302 if ((shdr.sh_type == SHT_SYMTAB) || (shdr.sh_type == SHT_STRTAB)) 303 symsize += shdr.sh_size; 304 } 305 } 306 307 if (symsize) { 308 symstart = kernsize; 309 kernsize += symsize + sizeof(ehdr) + ehdr.e_shnum*sizeof(Elf32_Shdr); 310 } 311 312 /* 313 * Extract various sizes from the kernel executable 314 */ 315 kparam.esym_loc = symsize ? kernsize : 0; 316 kparam.ksize = kernsize; 317 kparam.entry = ehdr.e_entry; 318 319 if ((kparam.kp = (u_char *)malloc(kparam.ksize)) == NULL) 320 fatal(-1, "Cannot malloc kernel image space"); 321 322 /* 323 * Read text & data, clear bss 324 */ 325 for (i = 0; i < ehdr.e_phnum; i++) { 326 u_char *p; 327 Elf32_Phdr *php = &phdrs[i]; 328 329 if (php->p_flags & (PF_W|PF_X)) { 330 if (lseek(fd, (off_t)php->p_offset, SEEK_SET) != php->p_offset) 331 fatal(-1, "Seek error while reading text segment\n"); 332 p = (u_char *)(kparam.kp) + php->p_vaddr; 333 if (read(fd, p, php->p_filesz) != php->p_filesz) 334 fatal(-1, "Read error in text segment\n"); 335 if (php->p_memsz > php->p_filesz) 336 memset(p + php->p_filesz, 0, php->p_memsz - php->p_filesz); 337 } 338 } 339 340 /* 341 * Read symbols and strings 342 */ 343 if (symsize) { 344 u_char *p, *symtab; 345 int nhdrs; 346 Elf32_Shdr *shp; 347 348 symtab = kparam.kp + symstart; 349 350 p = symtab + sizeof(ehdr); 351 nhdrs = ehdr.e_shnum; 352 if (lseek(fd, (off_t)ehdr.e_shoff, SEEK_SET) != ehdr.e_shoff) 353 fatal(-1, "Error seeking to section headers"); 354 if (read(fd, p, nhdrs * sizeof(*shp)) != nhdrs * sizeof(*shp)) 355 fatal(-1, "Error reading section headers"); 356 shp = (Elf32_Shdr*)p; 357 p += nhdrs * sizeof(*shp); 358 for (i = 0; i < nhdrs; i++) { 359 if (shp[i].sh_type == SHT_SYMTAB) { 360 if (shp[i].sh_offset == 0) 361 continue; 362 /* Got the symbol table. */ 363 if (lseek(fd, (off_t)shp[i].sh_offset, SEEK_SET) != 364 shp[i].sh_offset) 365 fatal(-1, "Error seeking to symbols"); 366 if (read(fd, p, shp[i].sh_size) != shp[i].sh_size) 367 fatal(-1, "Error reading symbols"); 368 shp[i].sh_offset = p - symtab; 369 /* Find the string table to go with it. */ 370 j = shp[i].sh_link; 371 if (shp[j].sh_offset == 0) 372 continue; 373 p += shp[i].sh_size; 374 if (lseek(fd, (off_t)shp[j].sh_offset, SEEK_SET) != 375 shp[j].sh_offset) 376 fatal(-1, "Error seeking to string table"); 377 if (read(fd, p, shp[j].sh_size) != shp[j].sh_size) 378 fatal(-1, "Error reading strings"); 379 shp[j].sh_offset = p - symtab; 380 /* There should only be one symbol table. */ 381 break; 382 } 383 } 384 ehdr.e_shoff = sizeof(ehdr); 385 bcopy(&ehdr, symtab, sizeof(ehdr)); 386 } 387 return 1; 388 } 389 390 /* 391 * Extract memory and cpu/fpu info from system. 392 */ 393 void 394 get_sys_info() 395 { 396 long stck; 397 long *jar; 398 OSH *oshdr; 399 400 kparam.bootflags = 0; 401 402 stck = Super(0); 403 404 /* 405 * Some GEMDOS versions use a different year-base in the RTC. 406 */ 407 oshdr = *ADDR_OSHEAD; 408 oshdr = oshdr->os_beg; 409 if ((oshdr->os_version > 0x0300) && (oshdr->os_version < 0x0306)) 410 kparam.bootflags |= ATARI_CLKBROKEN; 411 412 if (kparam.stmem_size <= 0) 413 kparam.stmem_size = *ADDR_PHYSTOP; 414 415 if (kparam.ttmem_size) 416 kparam.ttmem_start = TTRAM_BASE; 417 else { 418 if (!s_flag && (*ADDR_CHKRAMTOP == RAM_TOP_MAGIC)) { 419 kparam.ttmem_size = *ADDR_RAMTOP; 420 if (kparam.ttmem_size > TTRAM_BASE) { 421 kparam.ttmem_size -= TTRAM_BASE; 422 kparam.ttmem_start = TTRAM_BASE; 423 } 424 else kparam.ttmem_size = 0; 425 } 426 } 427 428 /* 429 * Scan cookiejar for cpu types 430 */ 431 jar = *ADDR_P_COOKIE; 432 if (jar != NULL) { 433 do { 434 if (jar[0] == 0x5f435055) { /* _CPU */ 435 switch (jar[1]) { 436 case 0: 437 kparam.bootflags |= ATARI_68000; 438 break; 439 case 10: 440 kparam.bootflags |= ATARI_68010; 441 break; 442 case 20: 443 kparam.bootflags |= ATARI_68020; 444 break; 445 case 30: 446 kparam.bootflags |= ATARI_68030; 447 break; 448 case 40: 449 kparam.bootflags |= ATARI_68040; 450 break; 451 case 60: 452 kparam.bootflags |= ATARI_68060; 453 break; 454 default: 455 fatal(-1, "Unknown CPU-type"); 456 } 457 } 458 if (jar[0] == 0x42504658) { /* BPFX */ 459 unsigned long *p; 460 461 p = (unsigned long*)jar[1]; 462 463 kparam.ttmem_start = p[1]; 464 kparam.ttmem_size = p[2]; 465 } 466 if (jar[0] == 0x5f435432) { /* _CT2 */ 467 /* 468 * The CT2 board has a different physical base address! 469 */ 470 kparam.ttmem_start = CTRAM_BASE; 471 } 472 jar = &jar[2]; 473 } while (jar[-2]); 474 } 475 if (!(kparam.bootflags & ATARI_ANYCPU)) 476 fatal(-1, "Cannot determine CPU-type"); 477 478 (void)Super(stck); 479 480 if (d_flag) { 481 eprintf("Machine info:\r\n"); 482 eprintf("ST-RAM size\t: %10d bytes\r\n",kparam.stmem_size); 483 eprintf("TT-RAM size\t: %10d bytes\r\n",kparam.ttmem_size); 484 eprintf("TT-RAM start\t: 0x%08x\r\n", kparam.ttmem_start); 485 eprintf("Cpu-type\t: 0x%08x\r\n", kparam.bootflags); 486 } 487 } 488 489 void 490 help() 491 { 492 eprintf("\r 493 NetBSD loader for the Atari-TT\r 494 \r 495 Usage: %s [-abdhstVD] [-S <stram-size>] [-T <ttram-size>] [kernel]\r 496 \r 497 Description of options:\r 498 \r 499 \t-a Boot up to multi-user mode.\r 500 \t-b Ask for root device to use.\r 501 \t-d Enter kernel debugger.\r 502 \t-D printout debug information while loading\r 503 \t-h What you're getting right now.\r 504 `t-N No symbols must be loaded.\r 505 \t-o Write output to both <output file> and stdout.\r 506 \t-s Use only ST-compatible RAM\r 507 \t-S Set amount of ST-compatible RAM\r 508 \t-T Set amount of TT-compatible RAM\r 509 \t-t Test the loader. It will do everything except executing the\r 510 \t loaded kernel.\r 511 \t-V Print loader version.\r 512 \t-w Wait for a keypress before exiting.\r 513 ", Progname); 514 xexit(0); 515 } 516 517 void 518 usage() 519 { 520 eprintf("Usage: %s [-abdhstVD] [-S <stram-size>] " 521 "[-T <ttram-size>] [kernel]\r\n", Progname); 522 xexit(1); 523 } 524 525 void 526 start_kernel() 527 { 528 long stck; 529 530 stck = Super(0); 531 bsd_startup(&kparam); 532 /* NOT REACHED */ 533 534 (void)Super(stck); 535 } 536