blob: d0062dbbada861081c99e53cbcff84819e5df228 [file] [log] [blame]
.level 1.1
;!
;! Execution begins here.
;!
;! We are called by the PDC as:
;!
;! $START$(interactive, endaddr)
;!
;! Where:
;!
;! interactive - 0 if not interactive, 1 if interactive.
;!
.section .init
.EXPORT $START$,entry
$START$:
b,n continue ; This branch instruction may be used
; by 'palo' to determine whether a boot
; loader file really is a boot loader, so
; if you change it palo may start failing.
.word 0 ; This word is available for inserting a
; checksum when necessary, as on an ISO
; image where we have to preserve the
; integrity of this ELF executable file.
continue:
ssm 0,%r0
;! nuke the W bit, saving original value
.level 2.0
#define PSW_W_SM 0x200
#define PSW_W_BIT 36
rsm PSW_W_SM, %r1
.level 1.1
extrw,u %r1, PSW_W_BIT-32, 1, %r1
;! find out where we were loaded
blr 0,%arg1
ldo ($START$-bbb)(%arg1), %arg1
bbb:
ldil L%($global$), %dp
ldo R%($global$)(%dp), %dp
/* find size of first memory module -- assume it is well aligned */
#define IMM_MAX_MEM 0x39c
ldil L%(IMM_MAX_MEM), %r3
ldo R%(IMM_MAX_MEM)(%r3), %r3
ldw 0(%r3), %r3
/* due to sign extension problems and PDC, limit RAM to 1G */
/* this isn't efficient assembly but it doesn't matter here either */
#define ARTIFICIAL_LIMIT (1*1024*1024*1024)
ldil L%(ARTIFICIAL_LIMIT), %r4
ldo R%(ARTIFICIAL_LIMIT)(%r4), %r4
cmpb,<< %r3, %r4, limit_ok
nop
copy %r4, %r3
limit_ok:
/* stack is at top of initial mem module */
#define STACK_SIZE (64 * 1024)
ldil L%(STACK_SIZE), %r4
ldo R%(STACK_SIZE)(%r4), %r4
sub %r3, %r4, %sp
copy %sp, %arg2
/* heap lives just below stack and grows down -- see iplmain() */
;! save %sp for calling iplmain()
copy %sp, %r10
;! push a stack frame
ldo 64(%sp), %sp
;! save arg0 from the firmware and original PSW-W bit value
stw %arg0, -64(%sp)
stw %r1, -60(%sp)
ldil L%$START$, %arg0
ldo R%$START$(%arg0), %arg0
/* arg2 = _end - $$START$$ */
.import _end
ldil L%_end, %r5
ldo R%_end(%r5), %r5
sub %r5, %arg0, %arg2
;! copy us to our correct destination
/* memmove($START$, where-loaded, #bytes) */
bl memmove, %r2
nop
/* restore saved arg0 from firmware and original PSW-W bit */
ldw -64(%sp), %arg0
ldw -60(%sp), %arg2
.import iplmain,code
;! call iplmain via a register so we can jump from PIC space
;! to non-PIC space
ldil L%iplmain, %r3
ldo R%iplmain(%r3), %r3
;! we will "return" to non-PIC space
ldil L%ret_iplmain, %r2
ldo R%ret_iplmain(%r2), %r2
;! second arg is initial SP
copy %r10, %arg1
call_iplmain:
;! kernel-entry = iplmain(interactive, free-ptr, started-wide)
bv 0(%r3)
nop
ret_iplmain:
ldil L%ret_kernel, %r2
ldo R%ret_kernel(%r2), %r2
;! kernel(any-big-number, command-line, rd-start, rd-end)
ldil L%commandline, %arg0
ldo R%commandline(%arg0), %arg0
copy %arg0, %arg1
ldil L%(rd_start), %arg2
ldw R%(rd_start)(%arg2), %arg2
ldil L%(rd_end), %arg3
ldw R%(rd_end)(%arg3), %arg3
bv 0(%ret0)
nop
/* shouldn't ever return */
ret_kernel:
nop
/* if it does, it won't go past here */
infinite_loop:
b .
nop
.section .init
.export memmove
/* void *memmove(void * dest,const void *src,size_t count)
*
* combines overkill cache flushing with copying because
* this loop is used to copy the bootloader to its final
* location where it will then be executed. You probably
* shouldn't use this for generic C memory copying.
*
* note that memmove() can handle overlapping copies, but
* that's not currently used because copying a running program
* on top of itself is unwise.
*/
memmove:
copy %arg0, %ret0 /* arg0 must be returned */
cmpb,<<,n %arg1, %arg0, mmreverse
ldo -1(%arg2), %arg2
cmpib,=,n -1, %arg2, mmret /* if count==0 exit */
mmloop1:
ldb,ma 1(%arg1), %r19
ldo -1(%arg2), %arg2
stb %r19, 0(%arg0)
fdc 0(%arg0)
fic 0(%arg0)
ldo 1(%arg0), %arg0
cmpib,<> -1, %arg2, mmloop1
nop
bv,n %r0(%rp)
mmreverse:
add,l %arg0, %arg2, %arg0
add,l %arg1, %arg2, %arg1
ldo -1(%arg2), %arg2
ldo -1(%arg0), %arg0
cmpib,=,n -1, %arg2, mmret
mmloop2:
ldb,mb -1( %arg1), %r19
ldo -1(%arg2), %arg2
stb %r19, 0(%arg0)
fdc 0(%arg0)
fic 0(%arg0)
ldo -1(%arg0), %arg0
cmpib,<> -1, %arg2, mmloop2
nop
mmret:
bv,n %r0(%rp)
nop
/************************ 64-bit real-mode calls ***********************/
/* Called in narrow mode; switches to wide mode for PDC or IODC call */
#define REG_SZ 8
.text
.export real64_call_asm
.level 2.0
/* unsigned int real64_call_asm(unsigned long long *sp,
* unsigned long long *arg0p,
* unsigned long long fn)
* sp is value of stack pointer to adopt before calling PDC
* arg0p points to where saved arg values may be found
* fn is the PDC/IODC function to call
*/
real64_call_asm:
stw %rp, -20(%sp) /* save RP */
stw %sp, -8(%arg0) /* save SP on real-mode stack */
copy %arg0, %sp /* adopt the real-mode SP */
/* switch to wide mode */
1: mfia %ret0 /* clear upper part of pcoq */
ldo 2f-1b(%ret0), %ret0
depdi 0, 31, 32, %ret0
bv (%ret0)
ssm 0x200, %r3 /* set W-bit */
2:
copy %arg2, %r31 /* save fn */
depd %arg3, 31, 32, %r31 /* merge in hi part */
ldo 64(%arg1), %r29 /* set up the new ap */
/* load up the arg registers from the saved arg area */
/* 64-bit calling convention passes first 8 args in registers */
ldw 0*REG_SZ+4(%arg1), %arg0 /* note overwriting arg0 */
ldw 2*REG_SZ+4(%arg1), %arg2
ldw 3*REG_SZ+4(%arg1), %arg3
ldw 4*REG_SZ+4(%arg1), %r22
ldw 5*REG_SZ+4(%arg1), %r21
ldw 6*REG_SZ+4(%arg1), %r20
ldw 7*REG_SZ+4(%arg1), %r19
ldw 1*REG_SZ+4(%arg1), %arg1 /* do this one last! */
ldil L%r64_ret, %rp
ldo R%r64_ret(%rp), %rp
bv 0(%r31)
nop
r64_ret:
mtsm %r3 /* return to narrow mode */
ldw -8(%sp), %sp /* restore SP */
ldw -20(%sp), %rp /* restore RP */
bv 0(%rp)
nop
.data
.align 4
.export $global$, data
$global$:
.word 4
.export commandline,data
.export rd_start,data
.export rd_end,data
commandline:
.blockz 256+4
rd_start:
.blockz 4
rd_end:
.blockz 4
.section .bss
.export real_stack
.align 64
real_stack:
.block 8192