1 /* $NetBSD: loadbsd.c,v 1.7 1995/05/28 10:56:16 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 <stdio.h> 38 #include <a_out.h> 39 #include <fcntl.h> 40 #include <osbind.h> 41 #include <stdarg.h> 42 #include "loader.h" 43 44 char *Progname; /* How are we called */ 45 int t_flag = 0; /* Just test, do not execute */ 46 int d_flag = 0; /* Output debugging output? */ 47 int s_flag = 0; /* St-ram only */ 48 49 char version[] = "$Revision: 1.7 $"; 50 51 /* 52 * Default name of kernel to boot, large enough to patch 53 */ 54 char kname[80] = "n:/netbsd"; 55 56 static struct { 57 u_char *kp; /* 00: Kernel load address */ 58 long ksize; /* 04: Size of loaded kernel */ 59 u_long entry; /* 08: Kernel entry point */ 60 long stmem_size; /* 12: Size of st-ram */ 61 long ttmem_size; /* 16: Size of tt-ram */ 62 long cputype; /* 20: Type of cpu */ 63 long boothowto; /* 24: How to boot */ 64 long ttmem_start; /* 28: Start of tt-ram */ 65 long esym_loc; /* 32: End of symbol table */ 66 } kparam; 67 68 void get_sys_info(void); 69 void error(char *fmt, ...); 70 void help(void); 71 void usage(void); 72 void start_kernel(void); 73 void do_exit(int); 74 75 int main(argc, argv) 76 int argc; 77 char **argv; 78 { 79 /* 80 * Option parsing 81 */ 82 extern int optind; 83 extern char *optarg; 84 int ch; 85 int fd; 86 long textsz, stringsz; 87 struct exec ehdr; 88 89 Progname = argv[0]; 90 91 kparam.boothowto = RB_SINGLE; 92 93 while ((ch = getopt(argc, argv, "abdhstvDS:T:")) != EOF) { 94 switch(ch) { 95 case 'a': 96 kparam.boothowto &= ~(RB_SINGLE); 97 kparam.boothowto |= RB_AUTOBOOT; 98 break; 99 case 'b': 100 kparam.boothowto |= RB_ASKNAME; 101 break; 102 case 'd': 103 kparam.boothowto |= RB_KDB; 104 break; 105 case 'D': 106 d_flag = 1; 107 break; 108 case 's': 109 s_flag = 1; 110 break; 111 case 'S': 112 kparam.stmem_size = atoi(optarg); 113 break; 114 case 't': 115 t_flag = 1; 116 break; 117 case 'T': 118 kparam.ttmem_size = atoi(optarg); 119 break; 120 case 'v': 121 fprintf(stderr,"%s\r\n", version); 122 break; 123 case 'h': 124 help(); 125 default: 126 usage(); 127 } 128 } 129 argc -= optind; 130 argv += optind; 131 if(argc == 1) 132 strcpy(kname, argv[0]); 133 134 /* 135 * Get system info to pass to NetBSD 136 */ 137 get_sys_info(); 138 139 /* 140 * Find the kernel to boot and read it's exec-header 141 */ 142 if((fd = open(kname, O_RDONLY)) < 0) 143 error("Cannot open kernel '%s'", kname); 144 if(read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) 145 error("Cannot read exec-header of '%s'", kname); 146 if((ehdr.a_magic & 0xffff) != NMAGIC) /* XXX */ 147 error("Not an NMAGIC file '%s'", kname); 148 149 /* 150 * Extract various sizes from the kernel executable 151 */ 152 textsz = (ehdr.a_text + __LDPGSZ - 1) & ~(__LDPGSZ - 1); 153 kparam.esym_loc = 0; 154 kparam.ksize = textsz + ehdr.a_data + ehdr.a_bss; 155 kparam.entry = ehdr.a_entry; 156 157 if(ehdr.a_syms) { 158 if(lseek(fd,ehdr.a_text+ehdr.a_data+ehdr.a_syms+sizeof(ehdr), 0) <= 0) 159 error("Cannot seek to string table in '%s'", kname); 160 if(read(fd, &stringsz, sizeof(long)) != sizeof(long)) 161 error("Cannot read string-table size"); 162 if(lseek(fd, sizeof(ehdr), 0) <= 0) 163 error("Cannot seek back to text start"); 164 kparam.ksize += ehdr.a_syms + sizeof(long) + stringsz; 165 } 166 167 if((kparam.kp = (u_char *)malloc(kparam.ksize)) == NULL) 168 error("Cannot malloc kernel image space"); 169 170 /* 171 * Read text & data, clear bss 172 */ 173 if((read(fd, kparam.kp, ehdr.a_text) != ehdr.a_text) 174 || (read(fd, kparam.kp + textsz, ehdr.a_data) != ehdr.a_data)) 175 error("Unable to read kernel image\n"); 176 memset(kparam.kp + textsz + ehdr.a_data, 0, ehdr.a_bss); 177 178 /* 179 * Read symbol and string table 180 */ 181 if(ehdr.a_syms) { 182 long *p; 183 184 p = (long *)(kparam.kp + textsz + ehdr.a_data + ehdr.a_bss); 185 *p++ = ehdr.a_syms; 186 if(read(fd, (char *)p, ehdr.a_syms) != ehdr.a_syms) 187 error("Cannot read symbol table\n"); 188 p = (long *)((char *)p + ehdr.a_syms); 189 if(read(fd, (char *)p, stringsz) != stringsz) 190 error("Cannot read string table\n"); 191 kparam.esym_loc = (long)((char *)p-(char *)kparam.kp +stringsz); 192 } 193 194 if(d_flag) { 195 fprintf(stderr, "\r\nKernel info:\r\n"); 196 fprintf(stderr, "Kernel loadaddr\t: 0x%08x\r\n", kparam.kp); 197 fprintf(stderr, "Kernel size\t: %10d bytes\r\n", kparam.ksize); 198 fprintf(stderr, "Kernel entry\t: 0x%08x\r\n", kparam.entry); 199 fprintf(stderr, "Kernel esym\t: 0x%08x\r\n", kparam.esym_loc); 200 } 201 202 if(!t_flag) 203 start_kernel(); 204 /* NOT REACHED */ 205 206 fprintf(stderr, "Kernel '%s' was loaded OK\r\n", kname); 207 do_exit(0); 208 } 209 210 /* 211 * Extract memory and cpu/fpu info from system. 212 */ 213 void get_sys_info() 214 { 215 long stck; 216 long *jar; 217 OSH *oshdr; 218 219 kparam.cputype = 0; 220 221 stck = Super(0); 222 223 /* 224 * Some GEMDOS versions use a different year-base in the RTC. 225 */ 226 oshdr = *ADDR_OSHEAD; 227 oshdr = oshdr->os_beg; 228 if((oshdr->os_version >= 0x0300) && (oshdr->os_version < 0x0306)) 229 kparam.cputype |= ATARI_CLKBROKEN; 230 231 if(kparam.stmem_size <= 0) 232 kparam.stmem_size = *ADDR_PHYSTOP; 233 234 if(kparam.ttmem_size) 235 kparam.ttmem_start = TTRAM_BASE; 236 else { 237 if(!s_flag && (*ADDR_CHKRAMTOP == RAM_TOP_MAGIC)) { 238 kparam.ttmem_size = *ADDR_RAMTOP; 239 if(kparam.ttmem_size > TTRAM_BASE) { 240 kparam.ttmem_size -= TTRAM_BASE; 241 kparam.ttmem_start = TTRAM_BASE; 242 } 243 else kparam.ttmem_size = 0; 244 } 245 } 246 247 /* 248 * Scan cookiejar for cpu/fpu types 249 */ 250 jar = *ADDR_P_COOKIE; 251 if(jar != NULL) { 252 do { 253 if(jar[0] == 0x5f435055) { /* _CPU */ 254 switch(jar[1]) { 255 case 0: 256 kparam.cputype |= ATARI_68000; 257 break; 258 case 10: 259 kparam.cputype |= ATARI_68010; 260 break; 261 case 20: 262 kparam.cputype |= ATARI_68020; 263 break; 264 case 30: 265 kparam.cputype |= ATARI_68030; 266 break; 267 case 40: 268 kparam.cputype |= ATARI_68040; 269 break; 270 default: 271 error("Unknown CPU-type"); 272 } 273 } 274 if(jar[0] == 0x5f465055) { /* _FPU */ 275 switch(jar[1]) { 276 case 0x20000: 277 case 0x40000: 278 kparam.cputype |= ATARI_68881; 279 break; 280 case 0x60000: 281 kparam.cputype |= ATARI_68882; 282 break; 283 case 0x80000: 284 kparam.cputype |= ATARI_FPU40; 285 break; 286 default: 287 error("Unknown FPU-type"); 288 } 289 } 290 jar = &jar[2]; 291 } while(jar[-2]); 292 } 293 if(!(kparam.cputype & ATARI_ANYCPU)) 294 error("Cannot determine CPU-type"); 295 if(!(kparam.cputype & ATARI_ANYFPU)) 296 error("Cannot determine FPU-type"); 297 298 Super(stck); 299 300 if(d_flag) { 301 fprintf(stderr, "Machine info:\r\n"); 302 fprintf(stderr, "ST-RAM size\t: %10d bytes\r\n", kparam.stmem_size); 303 fprintf(stderr, "TT-RAM size\t: %10d bytes\r\n", kparam.ttmem_size); 304 fprintf(stderr, "TT-RAM start\t: 0x%08x\r\n", kparam.ttmem_start); 305 fprintf(stderr, "Cpu-type\t: 0x%08x\r\n", kparam.cputype); 306 } 307 } 308 309 void error(char *fmt, ...) 310 { 311 va_list ap; 312 313 va_start(ap, fmt); 314 315 fprintf(stderr, "%s: ", Progname); 316 vfprintf(stderr, fmt, ap); 317 fprintf(stderr, "\r\n"); 318 do_exit(1); 319 /*NOTREACHED*/ 320 } 321 322 void help() 323 { 324 fprintf(stderr, "\r 325 NetBSD loader for the Atari-TT\r 326 \r 327 Usage: %s [-abdhstvD] [-S <stram-size>] [kernel]\r 328 \r 329 Description of options:\r 330 \r 331 \t-a Boot up to multi-user mode.\r 332 \t-b Ask for root device to use.\r 333 \t-d Enter kernel debugger.\r 334 \t-h What your getting right now.\r 335 \t-s Use only ST-compatible RAM\r 336 \t-S Set amount of ST-compatible RAM\r 337 \t-T Set amount of TT-compatible RAM\r 338 \t-t Test the loader. It will do everything except executing the\r 339 \t loaded kernel.\r 340 \t-D printout debugging information while loading\r 341 \t-v Print loader version.\r 342 ", Progname); 343 do_exit(0); 344 } 345 346 void usage() 347 { 348 fprintf(stderr, "Usage: %s [-abdhtv] [kernel]\r\n", Progname); 349 do_exit(1); 350 } 351 352 void do_exit(code) 353 int code; 354 { 355 fprintf(stderr, "\r\nHit <return> to continue..."); 356 (void)getchar(); 357 fprintf(stderr, "\r\n"); 358 exit(code); 359 } 360 361 void start_kernel() 362 { 363 long stck; 364 365 stck = Super(0); 366 startit(); 367 /* NOT REACHED */ 368 369 Super(stck); 370 } 371 372 asm(" 373 .text 374 .globl _startit 375 376 _startit: 377 move.w #0x2700,sr 378 379 | the BSD kernel wants values into the following registers: 380 | d0: ttmem-size 381 | d1: stmem-size 382 | d2: cputype 383 | d3: boothowto 384 | d4: length of loaded kernel 385 | d5: start of fastram 386 | a0: start of loaded kernel 387 | a1: end of symbols (esym) 388 | All other registers zeroed for possible future requirements. 389 390 lea _kparam, a3 | a3 points to parameter block 391 lea _startit,sp | make sure we have a good stack *** 392 move.l (a3),a0 | loaded kernel 393 move.l 8(a3),-(sp) | push entry point *** 394 move.l a0,d0 | offset of loaded kernel 395 add.l d0,(sp) | add offset 396 move.l 12(a3),d1 | stmem-size 397 move.l 16(a3),d0 | ttmem-size 398 move.l 20(a3),d2 | cputype 399 move.l 24(a3),d3 | boothowto 400 move.l 4(a3),d4 | length of loaded kernel 401 move.l 28(a3),d5 | start of fastram 402 move.l 32(a3),a1 | end of symbols 403 sub.l a5,a5 | target, load to 0 404 btst #4, d2 | Is this an 68040? 405 beq not040 406 407 | Turn off 68040 MMU 408 .word 0x4e7b,0xd003 | movec a5,tc 409 .word 0x4e7b,0xd806 | movec a5,urp 410 .word 0x4e7b,0xd807 | movec a5,srp 411 .word 0x4e7b,0xd004 | movec a5,itt0 412 .word 0x4e7b,0xd005 | movec a5,itt1 413 .word 0x4e7b,0xd006 | movec a5,dtt0 414 .word 0x4e7b,0xd007 | movec a5,dtt1 415 bra nott 416 417 not040: 418 lea zero,a3 419 pmove (a3),tcr | Turn off MMU 420 lea nullrp,a3 421 pmove (a3),crp | Turn off MMU some more 422 pmove (a3),srp | Really, really, turn off MMU 423 424 | Turn off 68030 TT registers 425 btst #3, d2 | Is this an 68030? 426 beq.b nott 427 lea zero,a3 428 pmove (a3),tt0 429 pmove (a3),tt1 430 431 nott: 432 moveq.l #0,d6 | would have known contents) 433 moveq.l #0,d7 434 movea.l d6,a2 435 movea.l d6,a3 436 movea.l d6,a4 437 movea.l d6,a5 438 movea.l d6,a6 439 rts | enter kernel at address on stack *** 440 441 442 | A do-nothing MMU root pointer (includes the following long as well) 443 444 nullrp: .long 0x80000202 445 zero: .long 0 446 svsp: .long 0 447 448 "); 449