1 | file: boot.S 2 | author: chapuni(webmaster@chapuni.com) 3 | ITOH Yasufumi 4 | 5 | $NetBSD: boot.S,v 1.19 2020/01/28 11:57:22 isaki Exp $ 6 7 | 8 | (1) IPL (or previous stage loader) loads first 1KB of this primary 9 | bootloader to (*). (*) is 0x2000 (from FD) or 0x2400 (from SASI/SCSI). 10 | 11 | (2) The first 1KB loads full primary bootloader (including first 1KB) from 12 | the boot partition to 0x3000. And jump to there. 13 | 14 | (3) The full primary bootloader loads the secondary bootloader known as 15 | /boot from its filesystem to 0x6000. And jump to there. 16 | 17 | Therefore, The first 1KB must be relocatable. 18 | The first 1KB must be smaller than or equal to 1024 bytes. 19 | 20 | (1) -> (2) -> (3) 21 | +------------+ +------------+ +------------+ 0x000000 22 | : : : : : : 23 | +------------+ +------------+ +------------+ (*) 24 | | first 1KB | | first 1KB | | first 1KB | 25 | +------------+ +------------+ +------------+ (*)+0x400 26 | : : : : : : 27 | : : +------------+ +------------+ 0x003000 28 | : : |full primary| |full primary| 29 | : : |boot loader | |boot loader | 30 | : : |(text+data) | |(text+data) | 31 | : : +------------+ +------------+ 0x005000 32 | : : |(bss) | |(bss) | 33 | : : +------------+ +------------+ 0x006000 34 | : : : : | /boot | 35 | : : : : +------------+ 36 | : : : : : : 37 | ~ ~ ~ ~ ~ ~ 38 | : : : :<-SP : :<-SP 39 | + - - - - - -+ + - - - - - -+ + - - - - - -+ 0x100000 40 | : : : : : : 41 | 42 43 #include <machine/asm.h> 44 #include "iocscall.h" 45 46 #define SRAM 0x00ED0000 /* SRAM stat addr */ 47 #define SRAM_MEMSZ (SRAM + 8) /* (L) size of main memory */ 48 #define MINMEM 0x00400000 /* at least 4MB required */ 49 50 #define BOOT_ERROR(s) jbsr boot_error; .asciz s; .even 51 52 .globl _C_LABEL(bootufs) 53 .text 54 ASENTRY_NOPROFILE(start) 55 ASENTRY_NOPROFILE(top) 56 bras _ASM_LABEL(entry0) 57 .ascii "SHARP/" 58 .ascii "X680x0" 59 .word 0x8199,0x94e6,0x82ea,0x82bd 60 .word 0x8e9e,0x82c9,0x82cd,0x8cbb 61 .word 0x8ec0,0x93a6,0x94f0,0x8149 62 .word 0 63 | d4 SCSI ID 64 ASENTRY_NOPROFILE(entry0) 65 moveml %d0-%d7/%a0-%a7,_C_LABEL(startregs) 66 lea TEXTADDR:W,%a5 | set base ptr 67 #define _RELOC(adr) %a5@(((adr)-top):W) 68 #define ASRELOC(var) _RELOC(_ASM_LABEL(var)) 69 #define RELOC(var) _RELOC(_C_LABEL(var)) 70 71 lea RELOC(__bss_start),%a1 72 bra _ASM_LABEL(entry) 73 74 | Disklabel= 404bytes 75 | Since LABELOFFSET in <machine/disklabel.h> is 0x40, 76 | entry must be after 0x000001d4 (0x000f01d4) 77 .org 0x40 78 disklabel: 79 .space 404 80 81 ASENTRY_NOPROFILE(entry) 82 movew #_end-1,%d0 | bss end (low word only) 83 84 | clear out bss (must be <= 64KB) 85 subw %a1,%d0 86 clrbss: clrb %a1@+ 87 dbra %d0,clrbss 88 89 movel %d4,RELOC(ID) | SCSI ID (if booted from SCSI) 90 91 lea 0x00100000,%sp | set system stack 92 lea %a5@,%a1 | set load address 93 | a1 will be used later for IOCS calls 94 95 | we use 68020 instructions, and check MPU beforehand 96 | 97 | here d0.w = -1, and the above "subw a1,d0" = 0x9049, and 98 | if MPU <= 010 loads 0x49, 99 | if MPU >= 020 loads 0x90. 100 | This is a move, not a tst instruction 101 | because pc-relative tsts are not available on 000/010. 102 chkmpu: moveb %pc@(clrbss-chkmpu-2:B,%d0:W:2),%d0 | 103B 02xx 103 jmi mpuok | MC68020 or later 104 BOOT_ERROR("MPU 68000?") 105 mpuok: | XXX check for MMU? 106 107 IOCS(__BOOTINF) 108 lsll #8,%d0 | clear MSByte 109 lsrl #8,%d0 | 110 movel %d0,RELOC(BOOT_INFO) 111 112 | 113 | 0x80...0x8F SASI 114 | 0x90...0x93 Floppy 115 | 0xED0000...0xED3FFE SRAM 116 | others ROM (SCSI?) 117 | 118 movel %d0,%d1 119 clrb %d1 120 tstl %d1 121 jne boot_ram_rom 122 | 123 | SASI or Floppy 124 | 125 movel %d0,%d2 126 andib #0xFC,%d0 127 cmpib #0x90,%d0 128 jne boot_dev_unsupported | boot from SASI? 129 | 130 | Floppy 131 | 132 moveb %d2,%d0 133 andib #0x03,%d0 | drive # (head=0) 134 jbsr check_fd_format 135 moveml %d0-%d1,RELOC(FDSECMINMAX) | min and max sec # 136 lslw #8,%d2 137 moveq #0x70,%d1 138 orw %d2,%d1 | PDA*256 + MODE 139 movel %d1,RELOC(FDMODE) 140 movel %d0,%d2 | read position (first sector) 141 movel #8192,%d3 | read bytes 142 IOCS(__B_READ) 143 jra boot_read_done 144 145 #include "chkfmt.s" 146 147 boot_ram_rom: 148 movel %d0,%d1 149 swap %d1 150 cmpiw #0x00ED,%d1 151 jne boot_SCSI 152 | boot from SRAM? 153 154 boot_dev_unsupported: 155 BOOT_ERROR("unsupported boot device") 156 157 | 158 | volatile void BOOT_ERROR(const char *msg); 159 | print error message, wait for key press and reboot 160 | 161 booterr_msg: .ascii "\r\n\n" 162 .ascii BOOT 163 .asciz ": " 164 reboot_msg: .asciz "\r\n[Hit key to reboot]" 165 .even 166 167 ENTRY_NOPROFILE(BOOT_ERROR) 168 addql #4,%sp 169 170 boot_error: lea %pc@(booterr_msg),%a1 171 IOCS(__B_PRINT) 172 moveal %sp@+,%a1 173 IOCS(__B_PRINT) 174 lea %pc@(reboot_msg),%a1 175 IOCS(__B_PRINT) 176 177 | wait for a key press (or release of a modifier) 178 IOCS(__B_KEYINP) 179 180 | issue software reset 181 trap #10 182 | NOTREACHED 183 184 185 | 186 | ROM boot ... probably from SCSI 187 | 188 boot_SCSI: 189 #ifdef SCSI_ADHOC_BOOTPART 190 | 191 | Find out boot partition in an ad hoc manner. 192 | 193 194 | get block length of the SCSI disk 195 SCSIIOCS(__S_READCAP) | using buffer at a1 196 tstl %d0 197 jeq 1f 198 BOOT_ERROR("READCAP failed") 199 1: moveq #0,%d5 200 moveb %a1@(6),%d5 | 1: 256, 2: 512, 4: 1024 201 lsrb #1,%d5 | 0: 256, 1: 512, 2: 1024 202 movel %d5,RELOC(SCSI_BLKLEN) 203 204 | find out the start position of the boot partition 205 | XXX VERY AD HOC 206 | 207 | ROM firmware: 208 | pass read pos (in block #) in d2 209 | Human68k-style partition table does not exist 210 | d2 is 4 at the maximum 211 | SCSI IPLs (genuine and SxSI): 212 | pass read pos (in kilobytes) in d2 213 | d2 is bigger than 0x20 214 | partition table on the memory is destroyed 215 | BOOT MENU Ver.2.22: 216 | passes partition table entry address in a0 217 | d2 is cleared to zero 218 | No other IPL is supported. XXX FIXME 219 tstl %d2 220 jne sc1 221 | no information in d2 -- probably from BOOT MENU 222 | a0 points the partiion table entry 223 movel %a0@(0x0008),%d2 | in KByte 224 sc1: cmpl #0x20,%d2 225 jcs sc2 226 lsll #8,%d2 | clear MSByte 227 lsrl #6,%d2 | 228 lsrl %d5,%d2 | in sector 229 sc2: 230 | read entire boot 231 moveq #8192/256,%d3 | size is 8KB 232 lsrl %d5,%d3 | in sector 233 jbsr scsiread | read at %a1 234 235 cmpil #5,%d2 236 bcc sc3 237 movql #0,%d2 238 sc3: movel %d2,RELOC(SCSI_PARTTOP) 239 #else 240 moveq #1,%d5 | 512bytes/sec 241 movel %d5,%sp@- 242 moveq #8192/512,%d3 | 243 moveq #0x40,%d2 | (sd*a ) 244 SCSIIOCS(__S_READ) 245 #endif 246 247 boot_read_done: 248 jmp first_kbyte 249 250 read_error: BOOT_ERROR("read error") 251 252 #undef RELOC /* base register a5 is no longer available */ 253 #undef ASRELOC 254 #undef _RELOC 255 256 | 257 | read SCSI 258 | 259 | input: d2.l: pos in sector 260 | d3.l: len in sector 261 | d4: target SCSI ID 262 | d5: sector length (0: 256, 1: 512, 2: 1024) 263 | a1: buffer address 264 | destroy: 265 | d0, d1, a1 266 | 267 scsiread: 268 moveml %d2-%d3/%d6-%d7/%a2,%sp@- 269 | if (pos >= 0x200000 || (len > 255 && pos + len >= 0x200000)) 270 | use READEXT 271 | else 272 | use READ 273 moveq #0x20,%d0 274 swap %d0 | d0.l = 0x00200000 275 moveq #0,%d6 276 subqb #1,%d6 | d6.l = 255 277 moveq #8,%d7 278 addb %d5,%d7 | d7.b = (sector length: 0-2) + 8 279 cmpl %d0,%d2 280 jcc scsiread_ext 281 moveq #__S_READ,%d1 282 cmpl %d3,%d6 283 jcc scsiread_noext 284 subl %d2,%d0 | d0.0 = 0x200000 - pos 285 cmpl %d0,%d3 | <= len 286 jcs scsiread_noext | no 287 288 scsiread_ext: | use READEXT 289 extw %d6 | d6.l = 65535 290 moveq #__S_READEXT,%d1 291 292 scsiread_noext: | use READ 293 loop_scsiread: 294 | d1: SCSI IOCS call # 295 | d6: max sector count at a time 296 movel %d3,%a2 | save original len in a2 297 cmpl %d3,%d6 298 jcc 1f 299 movel %d6,%d3 300 1: IOCS(__SCSIDRV) | SCSIIOCS(d1) 301 tstl %d0 302 jne read_error 303 movel %d3,%d0 | addr += read count << (8 + sec len) 304 asll %d7,%d0 305 addl %d0,%a1 306 exg %d3,%a2 | restore original len to d3 307 addl %a2,%d2 | pos += read count 308 subl %a2,%d3 | len -= read count 309 jne loop_scsiread 310 moveml %sp@+,%d2-%d3/%d6-%d7/%a2 311 rts 312 313 | 314 | The former part must reside in the first 1KB. 315 | 316 .globl first_kbyte 317 first_kbyte: 318 |-------------------------------------------------------------------------- 319 | 320 | The latter text+data part is not accessible at the first boot time. 321 | PC-relative can be used from here. 322 | 323 | Initialize the screen here. Some IPL (060turbo ROM or 324 | genuine boot selector) don't initialize the screen. 325 | Such initialization should be done as early as possible 326 | but it's too severe to place it in first_kbyte area. 327 | Therefore do it here. 328 moveq #0x10,%d1 329 IOCS(__CRTMOD) 330 331 jmp _C_LABEL(bootufs) | 0x0Fxxxx 332 333 .word 0 334 335 | int badbaddr __P((void *adr)); 336 | check if the given address is valid for byte read 337 | return: 0: valid, 1: not valid 338 339 ENTRY_NOPROFILE(badbaddr) 340 lea 0x0008:W,%a1 | MPU Bus Error vector 341 moveq #1,%d0 342 lea %pc@(badr1),%a0 343 movew %sr,%sp@- 344 oriw #0x0700,%sr | keep out interrupts 345 movel %a1@,%sp@- 346 movel %a0,%a1@ | set bus error vector 347 movel %sp,%d1 | save sp 348 moveal %sp@(10),%a0 349 tstb %a0@ | try read... 350 moveq #0,%d0 | this is skipped on bus error 351 badr1: moveal %d1,%sp | restore sp 352 movel %sp@+,%a1@ 353 movew %sp@+,%sr 354 rts 355 356 | void RAW_READ __P((void *buf, u_int32_t blkpos, size_t bytelen)); 357 | inputs: 358 | buf: input buffer address 359 | blkpos: read start position in the partition in 512byte-blocks 360 | bytelen: read length in bytes 361 362 Lraw_read_buf=4+(4*11) 363 Lraw_read_pos_=Lraw_read_buf+4 364 Lraw_read_len=Lraw_read_buf+8 365 366 #ifdef SCSI_ADHOC_BOOTPART 367 | RAW_READ of physical disk 368 ENTRY_NOPROFILE(RAW_READ0) 369 moveq #0,%d0 370 jra raw_read1 371 #endif 372 373 ENTRY_NOPROFILE(RAW_READ) 374 #ifdef SCSI_ADHOC_BOOTPART 375 movel _C_LABEL(SCSI_PARTTOP),%d0 376 raw_read1: 377 #endif 378 moveml %d2-%d7/%a2-%a6,%sp@- 379 moveml %sp@(Lraw_read_buf),%d1-%d3 380 movel %d1,%a1 381 | d2.l: pos in 512byte-blocks 382 | d3.l: length in bytes 383 | a1 (=d1): buffer address 384 385 lea TEXTADDR:W,%a5 | set base ptr 386 #define _RELOC(adr) %a5@(((adr)-top):W) 387 #define ASRELOC(var) _RELOC(_ASM_LABEL(var)) 388 #define RELOC(var) _RELOC(_C_LABEL(var)) 389 390 tstb _RELOC(_C_LABEL(BOOT_INFO)+1) | simple check. may be incorrect! 391 beqs raw_read_floppy 392 393 raw_read_scsi: 394 movel RELOC(ID),%d4 | SCSI ID 395 #ifdef SCSI_ADHOC_BOOTPART 396 movel RELOC(SCSI_BLKLEN),%d5 | sector size: 0-2 397 | XXX length must be sector aligned 398 lsrl #8,%d3 | size in 256byte-blocks 399 lsrl %d5,%d3 | size in sector 400 bcss read_half | minimal error check 401 lsll #1,%d2 | X flag and d2: pos in 256byte-blocks 402 roxrl %d5,%d2 | pos in sector 403 addl %d0,%d2 | physical pos in sector 404 #else 405 moveq #1,%d5 | 512bytes/sec 406 moveq #9,%d0 | shift count 407 addl #511,%d3 408 lsrl %d0,%d3 409 bcss read_half | minimal error check 410 411 addl #0x40,%d2 | 'a' partition starts here 412 #endif 413 | jcc 1f 414 | BOOT_ERROR("out of seek") | pos exceeds 32bit 415 |1: 416 jbsr scsiread 417 bras raw_read_end 418 419 raw_read_floppy: 420 | 421 | Floppy read routine 422 | 423 424 | convert to seek position 425 426 asll #2,%d2 | size in 128byte-blocks 427 428 | sec = raw_read_pos (d2) 429 | sec >>= 7 + (sector length: 0-3) 430 431 lea RELOC(FDSECMINMAX),%a0 432 moveq #0,%d1 433 moveb %a0@,%d1 | d1: sector length (0-3) 434 lsrl %d1,%d2 | d2: pos in sector 435 bcss read_half | error check 436 437 | trk = sec / (# sectors) 438 | sec = sec % (# sectors) 439 440 moveb %a0@(7),%d1 | d1: max sector # 441 subb %a0@(3),%d1 | - min sector # 442 addqb #1,%d1 | d1: # sectors 443 divu %d1,%d2 | d2: (sec << 16) | track 444 445 | position = (sec length << 24) | (track/2 << 16) 446 | | (track%2 << 8) | (min sec # + sec) 447 448 movel %a0@,%d0 | d0: (sec len << 24) | min sec # 449 lsrw #1,%d2 | d2: (sec << 16) | (track / 2) 450 jcc 1f 451 bset #8,%d0 | |= (track % 2) << 8 452 1: swap %d2 | d2: ((track / 2) << 16) | sec 453 addl %d0,%d2 | d2: position 454 455 | read 456 movel RELOC(FDMODE),%d1 | PDA*256 + MODE 457 458 | B_READ (for floppy) 459 | d1.w: PDA x 256 + MODE 460 | PDA: 0x90 (drive 0) ... 0x93 (drive 3) 461 | MODE: bit6: MFM 462 | bit5: retry 463 | bit4: seek 464 | d2.l: position 465 | bit31-24: sector length (0: 128, 1: 256, 2: 512, 3: 1K) 466 | bit23-16: track # (0-79) 467 | bit15-08: side (0 or 1) 468 | bit07-00: sector # (1-) 469 | d3.l: read bytes 470 | a1: read address 471 | return: 472 | d0: bit 31-24 ST0 473 | bit 23-16 ST1 474 | bit 15- 8 ST2 475 | bit 7- 0 C 476 | -1 on parameter error 477 | destroy: d0, d2, d3, a1 478 IOCS(__B_READ) 479 andil #0xf8ffff00,%d0 | check status (must be zero) 480 jne read_error 481 482 raw_read_end: 483 moveml %sp@+,%a2-%a6/%d2-%d7 484 rts 485 #undef _RELOC /* base register a5 is no longer available */ 486 #undef ASRELOC 487 #undef RELOC 488 489 read_half: BOOT_ERROR("read half of block") 490 491 492 ENTRY_NOPROFILE(B_PUTC) 493 movel %sp@(4),%d1 494 IOCS(__B_PUTC) 495 rts 496 497 ENTRY_NOPROFILE(B_PRINT) 498 movel %sp@(4),%a1 499 IOCS(__B_PRINT) 500 rts 501 502 | 503 | void memcpy(void *dst, const void *src, size_t count); 504 | void memmove(void *dst, const void *src, size_t count); 505 | 506 | small and slow memcpy... 507 | THIS FUNCTION DOES NOT CONFORM THE ANSI STANDARD 508 | 509 ENTRY_NOPROFILE(memcpy) 510 ENTRY_NOPROFILE(memmove) 511 lea %sp@(12),%a1 512 movel %a1@,%d1 | count 513 jeq Lmcpret 514 moveal %a1@-,%a0 | src 515 moveal %a1@-,%a1 | dest 516 cmpl %a1,%a0 517 jcc Lmcpfw 518 | copy backward 519 addal %d1,%a0 520 addal %d1,%a1 521 1: moveb %a0@-,%a1@- 522 subql #1,%d1 523 jne 1b 524 jra Lmcpret 525 Lmcpfw: | copy forward 526 1: moveb %a0@+,%a1@+ 527 subql #1,%d1 528 jne 1b 529 Lmcpret: 530 | movel %sp@(8),%d0 | uncomment this to conform ANSI 531 rts 532 533 534 | 535 | global variables 536 | 537 BSS(ID, 4) | SCSI ID 538 BSS(BOOT_INFO, 4) | result of IOCS(__BOOTINF) 539 BSS(FDMODE, 4) | Floppy access mode: PDA x 256 + MODE 540 BSS(FDSECMINMAX, 8) | +0: (min sector) sector length 541 | +1: (min sector) track # 542 | +2: (min sector) side 543 | +3: (min sector) sector # 544 | +4: (max sector) sector length 545 | +5: (max sector) track # 546 | +6: (max sector) side 547 | +7: (max sector) sector # 548 #ifdef SCSI_ADHOC_BOOTPART 549 BSS(SCSI_PARTTOP, 4) | start sector of boot partition 550 BSS(SCSI_BLKLEN ,4) | sector len 0: 256, 1: 512, 2: 1024 551 #endif 552