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