1 ; $NetBSD: start.S,v 1.1.2.1 2004/11/14 08:15:06 skrll Exp $
3 ; Copyright (c) 2003 ITOH Yasufumi.
6 ; Redistribution and use in source and binary forms, with or without
7 ; modification, are permitted provided that the following conditions
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.
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.
30 ; LIF (Logical Interchange Format) header
32 lifhdr: .byte 0x80,0x00 ; LIF magic
33 .string "NetBSD" ; volume label (6 chars, fill with space)
37 .word top-lifhdr ; start at 4KB (must be 2KB aligned)
39 .word 0x00001000 ; size 4KB (must be 2KB aligned)
41 .word $START$-top ; entry offset
43 ; ipl part 1 starts here
49 ; arg0 = interact flag (1: interactive, 0: otherwise)
50 ; arg1 = address of first doubleword past the end of ipl part 1
54 b,n start ; 0: entry address
56 ; version of interface of primary to secondary boot
57 BOOT_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
62 cksum: .word 0 ; 4: checksum will be stored here
63 version: .word BOOT_IF_VERSION ; 8: version of interface
64 rsvd1: .word 0 ; 12: future use
65 rsvd2: .word 0 ; 16: future use
66 rsvd3: .word 0 ; 20: future use
69 ; set data pointer for relocatable data access
76 ; save parameters for main
79 tmpdiskbufsz: .equ 0x1000 ; 4KB
80 tmpdiskbuf_labelsec: .equ 0x0200 ; dbtob(LABELSECTOR)
81 tmpdiskbuf_labelsecsz: .equ 512
82 tmpdiskbuf_part2: .equ 0x0400
83 tmpdiskbuf_part2sz: .equ 0x0400
84 tmpdiskbuf_part3: .equ 0x0A00
85 tmpdiskbuf_part3sz: .equ 0x0600
89 ; get next free address
91 addil L%_end-$global$,%r27;%r1
92 ldo R%_end-$global$(%r1),%r1
94 ; 32bit environment (and this code) requires stack is 64byte aligned.
97 andcm %r1,%r2,%r6 ; r6 = tmp disk buffer
98 ldo tmpdiskbufsz+64(%r6),%sp ; tmp stack
101 ldo str_startup-$global$(%r27),%arg0
104 ; read part 2 and 3 of ipl (see README.ipl)
107 ; read disk blocks which contains ipl part 2 and part 3
109 ldi 0,%arg2 ; offset = 0
111 ldi tmpdiskbufsz,%arg1 ; read size
114 ldo top-$global$+part1sz(%r27),%r19
117 ldo tmpdiskbuf_part2(%r6),%r20
118 addi,tr tmpdiskbuf_part2sz/4,%r0,%r2 ; loop count, skip next
119 cpipl2: 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
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
127 cpipl3: 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
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
134 flipl: 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
140 ; Now, whole the IPL is loaded
145 addil L%_edata-$global$,%r27;%r1
146 ldo R%_edata-$global$(%r1),%r1
147 clrbss: comb,< %r1,%r6,clrbss
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
156 cplbl: 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
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)
169 ; parameters for main
173 .import ipl_main,entry
177 ; main returned --- perform reset
179 ldo str_reset-$global$(%r27),%arg0
182 IOMOD_CMD: .equ 0xFFFC0000 + (4*12)
183 IOMOD_CMD_STOP: .equ 0
184 IOMOD_CMD_RESET: .equ 5
191 addi,tr IOMOD_CMD_RESET,%r0,%r1 ; %r1 = IOMOD_CMD_RESET, skip next
192 halt: ldi IOMOD_CMD_STOP,%r1
193 iomcmd: ldil L%IOMOD_CMD,%r2
194 ldo R%IOMOD_CMD(%r2),%r2
200 .stringz "NetBSD/hp700 FFS/LFS Primary Bootstrap\r\n\n"
202 .stringz "\r\nresetting..."
205 ; void dispatch(unsigned interactive, unsigned top, unsigned end, int part,
207 .export dispatch,entry
209 ; flush data cache / invalidate instruction cache
210 ldi 16,%r20 ; 16: cache line size
211 flush: 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
215 copy %r0,%r1 ; I/O operation is guaranteed to finish
216 copy %r0,%r3 ; in eight instructions after sync
218 copy %r0,%r5 ; while waiting, clear unused registers
219 copy %r0,%r6 ; for future compatibility
236 copy %r0,%r28 ; r23-r26: arg3-arg0, r27: dp
237 copy %r0,%r29 ; r30: sp
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
247 PZ_MEM_CONSOLE: .equ 0x3a0
248 PZ_MEM_BOOT: .equ 0x3d0
249 PZ_MEM_KEYBOARD: .equ 0x400
252 DEV_LAYERS: .equ 0x08
253 DEV_HPA: .equ 0x20 ; hard physical adderss space
254 DEV_SPA: .equ 0x24 ; soft physical address space
255 DEV_IODC_ENTRY: .equ 0x28
257 DEV_CL_DUPLEX: .equ 0x7 ; full-duplex console class
259 IODC_ENTRY_IO_BOOTIN: .equ 0
260 IODC_ENTRY_IO_CONSOLEIN: .equ 2
261 IODC_ENTRY_IO_CONSOLEOUT: .equ 3
265 ; %ret0 IODC base in page zero
273 ; all scratch regs undefined, unless defined by the IODC call
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
283 bb,< %r1,4,call_iodc_64 ; if W, call in 64bit mode
284 ldw DEV_IODC_ENTRY(%ret0),%r1 ; ENTRY_IO address
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
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.
300 ; 64bytes allocated for register arguments arg0-arg7
301 ; 8 arg8 (argument pointer points here)
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
313 ; void print(const char *string)
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
323 .callinfo frame=128,save_rp,no_unwind
329 ; 36byte IODC buffer (assume %sp was 64byte aligned)
331 ; 88 arguments, frame marker
332 ; 32bit: 36 (arguments) + 32 (frame marker)
333 ; 64bit: 72 (arguments) + 16 (frame marker)
348 comb,= %r2,%r0,endstr
351 comb,<> %r19,%r20,strloop
355 comb,=,n %r19,%r0,endpr
359 ; arg1 option (ENTRY_IO_CONSOLEOUT (3))
361 ; arg3 ID_addr (pointer to LAYER)
362 ; arg4 R_addr (pointer to return buffer (64word?))
364 ; arg6 memaddr (64byte-aligned) string buffer
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
373 ldi IODC_ENTRY_IO_CONSOLEOUT,%arg1 ; arg1: option
377 ; restore callee-saves
395 .callinfo frame=192,save_rp,no_unwind
401 ; 64byte IODC buffer (assume %sp was 64byte aligned)
403 ; 88 arguments, frame marker
404 ; 32bit: 36 (arguments) + 32 (frame marker)
405 ; 64bit: 72 (arguments) + 16 (frame marker)
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
417 ; arg1 option (ENTRY_IO_CONSOLEIN (2))
419 ; arg3 ID_addr (pointer to LAYER)
420 ; arg4 R_addr (pointer to return buffer (64word?))
422 ; arg6 memaddr (64byte-aligned, must have 64byte) data buffer
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
431 ldi IODC_ENTRY_IO_CONSOLEIN,%arg1 ; arg1: option
434 comb,<> %ret0,%r0,getch_ret ; return -1 on error
438 ; check if narrow or wide mode
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
445 ldb -192(%sp),%ret0 ; otherwise return the char
456 ldd R%retbuf-$global$(%r1),%r2 ; ret[0] (64bit)
458 cmpclr,*<> %r19,%r2,%ret0 ; return 0 if no char available
465 ; void boot_input(void *buf, unsigned len, unsigned pos)
467 .export boot_input,entry
470 .callinfo frame=128,save_rp,no_unwind
476 ; 40byte unused (alignment)
477 ; 88 arguments, frame marker
478 ; 32bit: 36 (arguments) + 32 (frame marker)
479 ; 64bit: 72 (arguments) + 16 (frame marker)
483 ; arg1 option (ENTRY_IO_BOOTIN (0))
485 ; arg3 ID_addr (pointer to LAYER)
486 ; arg4 R_addr (pointer to return buffer (64word?))
488 ; arg6 memaddr (64byte-aligned) string buffer
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
497 ldi IODC_ENTRY_IO_BOOTIN,%arg1 ; arg1: option
511 ; int strcmp(const char *str1, const char *str2)
516 .callinfo frame=0,no_calls
518 ldbs,ma 1(0,%arg0),%r1
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
530 ; void memcpy(void *dst, const void *src, unsigned len)
533 .export memmove,entry
537 .callinfo no_unwind ; multiple exit points
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
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
549 stbs,ma %r1,1(0,%arg0) ; write to dst
551 addib,uv,n -1,%arg2,memcpy_fwd ; check loop condition
552 ldbs,ma 1(0,%arg1),%r1 ; read from src
554 bv,n %r0(%rp) ; return subroutine
559 ; placed here to save space
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
568 .stringz "repositioning media...\r\n"
570 .stringz "bit firmware\r\n"
572 .byte 0x08, 0x20, 0x08, 0x00 ; "\b \b"
574 .export str_bootpart, data
576 .string "boot partition (a-p, ! to reboot) [a]:"
579 .export str_booting_part, data
581 .string "\r\nbooting from partition _"
584 .export str_warn_2GB, data
586 .stringz "boot partition exceeds 2GB boundary\r\n"
587 .export str_warn_unused, data
589 .stringz "unused partition\r\n"
590 .export str_nolabel, data
592 .stringz "no disklabel\r\n"
594 .export str_filesystem, data
596 .stringz "filesystem: _FS\r\n"
597 .export str_nofs, data
599 .stringz "no filesystem found\r\n"
600 .export str_lookup, data
601 .export str_loading, data
603 .export str_dddot, data
604 .export str_done, data
606 .stringz "looking up "
616 .export str_boot1, data
617 .export str_boot2, data
618 .export str_boot3, data
620 .stringz "boot.hp700"
624 .stringz "usr/mdec/boot"
626 .export str_noboot, data
628 .stringz "no secondary boot found\r\n"
630 .export str_ukfmt, data
632 .stringz ": unknown format -- exec from top\r\n"
636 retbuf: .block 32*8 ; *4 for narrow mode / *8 for wide mode