1; $NetBSD: start.S,v 1.1 2014/02/24 07:23:43 skrll Exp $ 2 3; Copyright (c) 2003 ITOH Yasufumi. 4; All rights reserved. 5; 6; Redistribution and use in source and binary forms, with or without 7; modification, are permitted provided that the following conditions 8; are met: 9; 1. Redistributions of source code must retain the above copyright 10; notice, this list of conditions and the following disclaimer. 11; 2. Redistributions in binary forms are unlimited. 12; 13; THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' 14; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS 17; BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23; THE POSSIBILITY OF SUCH DAMAGE. 24 25 .level 1.0 26 27 .code 28 .origin 0 29 ; 30 ; LIF (Logical Interchange Format) header 31 ; 32lifhdr: .byte 0x80,0x00 ; LIF magic 33 .string "NetBSD" ; volume label (6 chars, fill with space) 34 .origin 0xf0 35 ; 0xf0 36lif_ipl_addr: 37 .word top-lifhdr ; start at 4KB (must be 2KB aligned) 38lif_ipl_size: 39 .word 0x00001000 ; size 4KB (must be 2KB aligned) 40lif_ipl_entry: 41 .word $START$-top ; entry offset 42 43 ; ipl part 1 starts here 44 .origin 4096 45top: 46 ; 47 ; IPL startup 48 ; 49 ; arg0 = interact flag (1: interactive, 0: otherwise) 50 ; arg1 = address of first doubleword past the end of ipl part 1 51 ; 52 .export $START$,entry 53$START$: 54 b,n start ; 0: entry address 55 56; version of interface of primary to secondary boot 57BOOT_IF_VERSION: .equ 0 58; version 0: arg0 = interact flag, arg1 = version (0), 59; arg2 = end addr, arg3 = selected boot partition 60; r1, r3 - r22, r28, r29, r31 = cleared to zeros 61 62cksum: .word 0 ; 4: checksum will be stored here 63version: .word BOOT_IF_VERSION ; 8: version of interface 64rsvd1: .word 0 ; 12: future use 65rsvd2: .word 0 ; 16: future use 66rsvd3: .word 0 ; 20: future use 67 68start: 69 ; set data pointer for relocatable data access 70 blr %r0,%r27 71 ; get PSW at entry 72 ssm 0,%r4 73 .export $global$,data 74$global$: 75 76 ; save parameters for main 77 copy %arg0,%r3 78 79tmpdiskbufsz: .equ 0x1000 ; 4KB 80tmpdiskbuf_labelsec: .equ 0x0200 ; dbtob(LABELSECTOR) 81tmpdiskbuf_labelsecsz: .equ 512 82tmpdiskbuf_part2: .equ 0x0400 83tmpdiskbuf_part2sz: .equ 0x0400 84tmpdiskbuf_part3: .equ 0x0A00 85tmpdiskbuf_part3sz: .equ 0x0600 86 87part1sz: .equ 0x1000 88 89 ; get next free address 90 .import _end,data 91 addil L%_end-$global$,%r27;%r1 92 ldo R%_end-$global$(%r1),%r1 93 94 ; 32bit environment (and this code) requires stack is 64byte aligned. 95 ldi 64-1,%r2 96 add %r1,%r2,%r1 97 andcm %r1,%r2,%r6 ; r6 = tmp disk buffer 98 ldo tmpdiskbufsz+64(%r6),%sp ; tmp stack 99 100 bl print,%rp 101 ldo str_startup-$global$(%r27),%arg0 102 103 ; 104 ; read part 2 and 3 of ipl (see README.ipl) 105 ; 106 107 ; read disk blocks which contains ipl part 2 and part 3 108 copy %r6,%arg0 109 ldi 0,%arg2 ; offset = 0 110 bl boot_input,%rp 111 ldi tmpdiskbufsz,%arg1 ; read size 112 113 ; part 2 address 114 ldo top-$global$+part1sz(%r27),%r19 115 116 ; copy part 2 117 ldo tmpdiskbuf_part2(%r6),%r20 118 addi,tr tmpdiskbuf_part2sz/4,%r0,%r2 ; loop count, skip next 119cpipl2: stws,ma %r1,4(0,%r19) ; write to dst 120 addib,uv,n -1,%r2,cpipl2 ; check loop condition 121 ldws,ma 4(0,%r20),%r1 ; read from src 122 123 ; copy part 3 124 ; (r19 already has destination address of part 3) 125 ldo tmpdiskbuf_part3(%r6),%r20 126 addi,tr tmpdiskbuf_part3sz/4,%r0,%r2 ; loop count, skip next 127cpipl3: stws,ma %r1,4(0,%r19) ; write to dst 128 addib,uv,n -1,%r2,cpipl3 ; check loop condition 129 ldws,ma 4(0,%r20),%r1 ; read from src 130 131 ; flush data cache / invalidate instruction cache 132 ldo top-$global$+part1sz(%r27),%r1 ; part 2 address 133 ldi 16,%r20 ; 16: cache line size 134flipl: fdc 0(0,%r1) ; flush data cache line at r1 135 comb,< %r1,%r19,flipl 136 fic,m %r20(0,%r1) ; flush instruction cache line at r1, r1 += 16 137 sync ; I/O operation is guaranteed to finish 138 ; in eight instructions after sync 139 ; 140 ; Now, whole the IPL is loaded 141 ; 142 143 ; clear BSS 144 .import _edata,data 145 addil L%_edata-$global$,%r27;%r1 146 ldo R%_edata-$global$(%r1),%r1 147clrbss: comb,< %r1,%r6,clrbss 148 stws,ma %r0,4(0,%r1) 149 150 ; we have read disklabel -- save it for later use 151 .import labelsector,data 152 addil L%labelsector-$global$,%r27;%r1 153 ldo R%labelsector-$global$(%r1),%r20 154 ldo tmpdiskbuf_labelsec(%r6),%r21 155 addi,tr tmpdiskbuf_labelsecsz/4,%r0,%r2 ; loop count, skip next 156cplbl: stws,ma %r1,4(0,%r20) ; write to dst 157 addib,uv,n -1,%r2,cplbl ; check loop condition 158 ldws,ma 4(0,%r21),%r1 ; read from src 159 160 ; set stack 161 ; (r6 points at free space, 64byte aligned) 162 ; 32bit environment (and this code) requires stack is 64byte aligned. 163 ldo 64(%r6),%sp ; 64 > 48: frame marker (32) + args(up to 4) 164 165 ; stack usage 166 ; 12bytes arguments 167 ; 32 frame marker 168 169 ; parameters for main 170 copy %r3,%arg0 171 copy %r4,%arg2 172 173 .import ipl_main,entry 174 bl ipl_main,%rp 175 copy %sp,%arg1 176 177 ; main returned --- perform reset 178 bl print,%rp 179 ldo str_reset-$global$(%r27),%arg0 180 ; FALLTHROUGH 181 182IOMOD_CMD: .equ 0xFFFC0000 + (4*12) 183IOMOD_CMD_STOP: .equ 0 184IOMOD_CMD_RESET: .equ 5 185 186; void reboot(void) 187; void halt(void) 188 .export reboot,entry 189 .export halt,entry 190reboot: 191 addi,tr IOMOD_CMD_RESET,%r0,%r1 ; %r1 = IOMOD_CMD_RESET, skip next 192halt: ldi IOMOD_CMD_STOP,%r1 193iomcmd: ldil L%IOMOD_CMD,%r2 194 ldo R%IOMOD_CMD(%r2),%r2 195 stwas %r1,0(%r2) 196 b,n . 197 198str_startup: 199 .string "\r\n\n" 200 .stringz "NetBSD/hppa FFS/LFS Primary Bootstrap\r\n\n" 201str_reset: 202 .stringz "\r\nresetting..." 203 .align 4 204 205; void dispatch(unsigned interactive, unsigned top, unsigned end, int part, 206; unsigned entry) 207 .export dispatch,entry 208dispatch: 209 ; flush data cache / invalidate instruction cache 210 ldi 16,%r20 ; 16: cache line size 211flush: fdc 0(0,%arg1) ; flush data cache line at arg1 212 comb,< %arg1,%arg2,flush 213 fic,m %r20(0,%arg1) ; flush instruction cache line at arg1, arg1+=16 214 sync 215 copy %r0,%r1 ; I/O operation is guaranteed to finish 216 copy %r0,%r3 ; in eight instructions after sync 217 copy %r0,%r4 218 copy %r0,%r5 ; while waiting, clear unused registers 219 copy %r0,%r6 ; for future compatibility 220 copy %r0,%r7 221 copy %r0,%r8 222 copy %r0,%r9 223 copy %r0,%r10 224 copy %r0,%r11 225 copy %r0,%r12 226 copy %r0,%r13 227 copy %r0,%r14 228 copy %r0,%r15 229 copy %r0,%r16 230 copy %r0,%r17 231 copy %r0,%r18 232 copy %r0,%r19 233 copy %r0,%r20 234 copy %r0,%r21 235 copy %r0,%r22 236 copy %r0,%r28 ; r23-r26: arg3-arg0, r27: dp 237 copy %r0,%r29 ; r30: sp 238 copy %r0,%r31 239 ldw -52(%sp),%arg1 ; arg4: exec address 240 ldo reboot-$global$(%r27),%rp ; reboot if returns 241 bv %r0(%arg1) ; execute 242 ldi BOOT_IF_VERSION,%arg1 243 244; 245; IODC subroutines 246; 247PZ_MEM_CONSOLE: .equ 0x3a0 248PZ_MEM_BOOT: .equ 0x3d0 249PZ_MEM_KEYBOARD: .equ 0x400 250 251DEV_PATH: .equ 0x00 252DEV_LAYERS: .equ 0x08 253DEV_HPA: .equ 0x20 ; hard physical address space 254DEV_SPA: .equ 0x24 ; soft physical address space 255DEV_IODC_ENTRY: .equ 0x28 256DEV_CLASS: .equ 0x2c 257DEV_CL_DUPLEX: .equ 0x7 ; full-duplex console class 258 259IODC_ENTRY_IO_BOOTIN: .equ 0 260IODC_ENTRY_IO_CONSOLEIN: .equ 2 261IODC_ENTRY_IO_CONSOLEOUT: .equ 3 262 263; call_iodc 264; inputs: 265; %ret0 IODC base in page zero 266; %rp return address 267; %r29 arg 8 268; %r19 arg 7 269; %r20 arg 6 270; %r21 arg 5 271; %r25 arg 1 272; outputs 273; all scratch regs undefined, unless defined by the IODC call 274call_iodc: 275 ; set common arguments in registers 276 addil L%retbuf-$global$,%r27;%r1 277 ldo R%retbuf-$global$(%r1),%r22 ; arg4: return buffer 278 ldo DEV_LAYERS(%ret0),%arg3 ; arg3: layer 279 ldw DEV_SPA(%ret0),%arg2 ; arg2: spa 280 ldw DEV_HPA(%ret0),%arg0 ; arg0: hpa 281 ; check if narrow or wide mode 282 ssm 0,%r1 ; get PSW 283 bb,< %r1,4,call_iodc_64 ; if W, call in 64bit mode 284 ldw DEV_IODC_ENTRY(%ret0),%r1 ; ENTRY_IO address 285 286 ; narrow mode 287 stw %r29,-68(%sp) ; arg8: maxsize / lang 288 stw %r19,-64(%sp) ; arg7: size 289 stw %r20,-60(%sp) ; arg6: buf 290 stw %r21,-56(%sp) ; arg5: devaddr / unused 291 bv %r0(%r1) ; call ENTRY_IO 292 stw %r22,-52(%sp) ; arg4: return buffer 293 294call_iodc_64: 295 .allow 2.0 296 ; On PA64 convention, arg0 - arg7 are passed in registers. 297 ; Parameters are placed in INCREASING order. 298 ; The argument pointer points at the first stack parameter. 299 ; stack usage: 300 ; 64bytes allocated for register arguments arg0-arg7 301 ; 8 arg8 (argument pointer points here) 302 ; 16 frame marker 303 std %r29,-16-8(%sp) ; arg8: maxsize / lang 304; std %sp,-8(%sp) ; psp in frame marker 305 bv %r0(%r1) ; call ENTRY_IO 306 ldo -16-8(%sp),%r29 ; argument pointer 307 .allow 308 309; 310; console output 311; 312; void putch(int) 313; void print(const char *string) 314 .align 4 315 .export putch,entry 316 .export print,entry 317putch: 318 stwm %arg0,128(%sp) ; fake up a string on the stack 319 stb %r0,-124(%sp) ; (see stack usage below) 320 addi,tr -125,%sp,%arg0 ; string address, skip next 321print: 322 .proc 323 .callinfo frame=128,save_rp,no_unwind 324 .entry 325 ldo 128(%sp),%sp 326 stw %rp,-128-20(%sp) 327 328 ; stack usage: 329 ; 36byte IODC buffer (assume %sp was 64byte aligned) 330 ; 4 saved reg 331 ; 88 arguments, frame marker 332 ; 32bit: 36 (arguments) + 32 (frame marker) 333 ; 64bit: 72 (arguments) + 16 (frame marker) 334prbufsiz: .equ 36 335 336 ; save callee-saves 337 stw %r3,-92(%sp) 338 339 copy %arg0,%r3 340 341prloop: 342 copy %r0,%r19 343 ldi prbufsiz,%r20 344 ldo -128(%sp),%r1 345 346strloop: 347 ldb 0(%r3),%r2 348 comb,= %r2,%r0,endstr 349 stbs,ma %r2,1(0,%r1) 350 ldo 1(%r19),%r19 351 comb,<> %r19,%r20,strloop 352 ldo 1(%r3),%r3 353 354endstr: 355 comb,=,n %r19,%r0,endpr 356 357 ; see IODC 3-51 358 ; arg0 hpa 359 ; arg1 option (ENTRY_IO_CONSOLEOUT (3)) 360 ; arg2 spa 361 ; arg3 ID_addr (pointer to LAYER) 362 ; arg4 R_addr (pointer to return buffer (64word?)) 363 ; arg5 unused (0) 364 ; arg6 memaddr (64byte-aligned) string buffer 365 ; arg7 reqsize 366 ; arg8 lang (0) 367 ldi PZ_MEM_CONSOLE,%ret0 ; IODC base in page zero 368 copy %r0,%r29 ; arg8: lang 369; copy %r19,%r19 ; arg7: size 370 ldo -128(%sp),%r20 ; arg6: buf 371; copy %r0,%r21 ; arg5: unused 372 bl call_iodc,%rp 373 ldi IODC_ENTRY_IO_CONSOLEOUT,%arg1 ; arg1: option 374 b,n prloop 375 376endpr: 377 ; restore callee-saves 378 ldw -92(%sp),%r3 379 380 ; return subroutine 381 ldw -128-20(%sp),%rp 382 bv %r0(%rp) 383 .exit 384 ldo -128(%sp),%sp 385 .procend 386 387; 388; console input 389; 390; int getch(void) 391 .align 4 392 .export getch,entry 393getch: 394 .proc 395 .callinfo frame=192,save_rp,no_unwind 396 .entry 397 stw %rp,-20(%sp) 398 ldo 192(%sp),%sp 399 400 ; stack usage: 401 ; 64byte IODC buffer (assume %sp was 64byte aligned) 402 ; 40 unused 403 ; 88 arguments, frame marker 404 ; 32bit: 36 (arguments) + 32 (frame marker) 405 ; 64bit: 72 (arguments) + 16 (frame marker) 406 407 ; check if console is full or half duplex 408 ldw PZ_MEM_CONSOLE+DEV_CLASS(%r0),%r1 ; device class 409 extru %r1,31,4,%r1 ; right 4bits are valid 410 ldi PZ_MEM_CONSOLE,%ret0 411 comib,=,n DEV_CL_DUPLEX,%r1,getch_console ; use CONSOLE if full 412 ldi PZ_MEM_KEYBOARD,%ret0 ; otherwise KEYBOARD 413getch_console: 414 415 ; see IODC 3-50 416 ; arg0 hpa 417 ; arg1 option (ENTRY_IO_CONSOLEIN (2)) 418 ; arg2 spa 419 ; arg3 ID_addr (pointer to LAYER) 420 ; arg4 R_addr (pointer to return buffer (64word?)) 421 ; arg5 unused (0) 422 ; arg6 memaddr (64byte-aligned, must have 64byte) data buffer 423 ; arg7 reqsize 424 ; arg8 lang (0) 425; copy %rp,%rp ; IODC base in page zero 426 copy %r0,%r29 ; arg8: lang 427 ldi 1,%r19 ; arg7: size (1) 428 ldo -192(%sp),%r20 ; arg6: buf 429; copy %r0,%r21 ; arg5: unused 430 bl call_iodc,%rp 431 ldi IODC_ENTRY_IO_CONSOLEIN,%arg1 ; arg1: option 432 433 ; make return value 434 comb,<> %ret0,%r0,getch_ret ; return -1 on error 435 ldi -1,%ret0 436 ldi 1,%r19 437 438 ; check if narrow or wide mode 439 ssm 0,%r1 ; get PSW 440 bb,< %r1,4,getch_64 441 addil L%retbuf-$global$,%r27;%r1 442 ldw R%retbuf-$global$(%r1),%r2 ; ret[0] 443 comclr,<> %r19,%r2,%ret0 ; return 0 if no char available 444getch_retc: 445 ldb -192(%sp),%ret0 ; otherwise return the char 446 447getch_ret: 448 ; return subroutine 449 ldw -192-20(%sp),%rp 450 bv %r0(%rp) 451 .exit 452 ldo -192(%sp),%sp 453 454getch_64: 455 .allow 2.0 456 ldd R%retbuf-$global$(%r1),%r2 ; ret[0] (64bit) 457 b getch_retc 458 cmpclr,*<> %r19,%r2,%ret0 ; return 0 if no char available 459 .allow 460 .procend 461 462; 463; read boot device 464; 465; void boot_input(void *buf, unsigned len, unsigned pos) 466 .align 4 467 .export boot_input,entry 468boot_input: 469 .proc 470 .callinfo frame=128,save_rp,no_unwind 471 .entry 472 stw %rp,-20(%sp) 473 ldo 128(%sp),%sp 474 475 ; stack usage: 476 ; 40byte unused (alignment) 477 ; 88 arguments, frame marker 478 ; 32bit: 36 (arguments) + 32 (frame marker) 479 ; 64bit: 72 (arguments) + 16 (frame marker) 480 481 ; see IODC 3-46 482 ; arg0 hpa 483 ; arg1 option (ENTRY_IO_BOOTIN (0)) 484 ; arg2 spa 485 ; arg3 ID_addr (pointer to LAYER) 486 ; arg4 R_addr (pointer to return buffer (64word?)) 487 ; arg5 devaddr 488 ; arg6 memaddr (64byte-aligned) string buffer 489 ; arg7 reqsize 490 ; arg8 maxsize 491 ldi PZ_MEM_BOOT,%ret0 ; IODC base in page zero 492 copy %arg1,%r29 ; arg8: maxsize 493 copy %arg1,%r19 ; arg7: size 494 copy %arg0,%r20 ; arg6: buf 495 copy %arg2,%r21 ; arg5: devaddr 496 bl call_iodc,%rp 497 ldi IODC_ENTRY_IO_BOOTIN,%arg1 ; arg1: option 498 499 ; return subroutine 500 ldw -128-20(%sp),%rp 501 bv %r0(%rp) 502 .exit 503 ldo -128(%sp),%sp 504 .procend 505 506; 507; utilities 508; optimized for size 509; 510 511; int strcmp(const char *str1, const char *str2) 512 .align 4 513 .export strcmp,entry 514strcmp: 515 .proc 516 .callinfo frame=0,no_calls 517 .entry 518 ldbs,ma 1(0,%arg0),%r1 519strcmp_loop: 520 comb,= %r1,%r0,strcmp_eos 521 ldbs,ma 1(0,%arg1),%r19 522 comb,=,n %r1,%r19,strcmp_loop 523 ldbs,ma 1(0,%arg0),%r1 524strcmp_eos: 525 bv %r0(%rp) 526 .exit 527 sub %r1,%r19,%ret0 528 .procend 529 530; void memcpy(void *dst, const void *src, unsigned len) 531 .align 4 532 .export memcpy,entry 533 .export memmove,entry 534memcpy: 535memmove: 536 .proc 537 .callinfo no_unwind ; multiple exit points 538 .entry 539; copy %arg0,%ret0 ; uncomment this to conform ANSI 540 comb,<<,n %arg0,%arg1,memcpy0 ; copy forward or backward? 541 add %arg0,%arg2,%arg0 ; dst end address 542 add,tr %arg1,%arg2,%arg1 ; src end address, skip next 543memcpy_bwd: 544 stbs,mb %r1,-1(0,%arg0) ; write to dst 545 addib,uv,n -1,%arg2,memcpy_bwd ; check loop condition 546 ldbs,mb -1(0,%arg1),%r1 ; read from src 547 bv,n %r0(%rp) ; return subroutine 548memcpy_fwd: 549 stbs,ma %r1,1(0,%arg0) ; write to dst 550memcpy0: 551 addib,uv,n -1,%arg2,memcpy_fwd ; check loop condition 552 ldbs,ma 1(0,%arg1),%r1 ; read from src 553 .exit 554 bv,n %r0(%rp) ; return subroutine 555 .procend 556 557; 558; string table 559; placed here to save space 560; 561 .export str_seekseq, data 562 .export str_startup, data 563 .export str_bit_firmware, data 564 .export str_crlf, data 565 .export str_space, data 566 .export str_rubout, data 567str_seekseq: 568 .stringz "repositioning media...\r\n" 569str_bit_firmware: 570 .stringz "bit firmware\r\n" 571str_rubout: 572 .byte 0x08, 0x20, 0x08, 0x00 ; "\b \b" 573 574 .export str_bootpart, data 575str_bootpart: 576 .string "boot partition (a-p, ! to reboot) [a]:" 577str_space: 578 .stringz " " 579 .export str_booting_part, data 580str_booting_part: 581 .string "\r\nbooting from partition _" 582str_crlf: 583 .stringz "\r\n" 584 .export str_warn_2GB, data 585str_warn_2GB: 586 .stringz "boot partition exceeds 2GB boundary\r\n" 587 .export str_warn_unused, data 588str_warn_unused: 589 .stringz "unused partition\r\n" 590 .export str_nolabel, data 591str_nolabel: 592 .stringz "no disklabel\r\n" 593 594 .export str_filesystem, data 595str_filesystem: 596 .stringz "filesystem: _FS\r\n" 597 .export str_nofs, data 598str_nofs: 599 .stringz "no filesystem found\r\n" 600 .export str_lookup, data 601 .export str_loading, data 602 .export str_at, data 603 .export str_dddot, data 604 .export str_done, data 605str_lookup: 606 .stringz "looking up " 607str_loading: 608 .stringz "loading " 609str_at: 610 .stringz " at 0x" 611str_dddot: 612 .stringz "..." 613str_done: 614 .stringz "done\r\n" 615 616 .export str_boot1, data 617 .export str_boot2, data 618 .export str_boot3, data 619str_boot1: 620 .stringz "boot.hp700" 621str_boot2: 622 .stringz "boot" 623str_boot3: 624 .stringz "usr/mdec/boot" 625 626 .export str_noboot, data 627str_noboot: 628 .stringz "no secondary boot found\r\n" 629 630 .export str_ukfmt, data 631str_ukfmt: 632 .stringz ": unknown format -- exec from top\r\n" 633 634 .bss 635 .align 64 636retbuf: .block 32*8 ; *4 for narrow mode / *8 for wide mode 637 638 .export diskbuf,data 639 .align 64 640diskbuf: 641 .block 2048 642