/* $NetBSD: bbstart.s,v 1.15 2022/04/29 07:12:41 rin Exp $ */

/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Ignatios Souvatzis.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <machine/asm.h>
#include "elf2bb.h"

#define LVOAllocMem     -0x0c6
#define LVODoIO         -0x1c8
#define LVOCacheClearU  -0x27c

#define IOcmd   28
#define IOerr   31
#define IOlen   36
#define IObuf   40
#define IOoff   44

#define Cmd_Rd  2

       .text
#if defined(_PRIMARY_BOOT) || defined(AUTOLOAD)
Lzero:  .asciz "DOS"                    | "DOS type"
#else
Lzero:  .ascii  "BOOT"                  | Secondary Boot
#endif
       /*
        * We put the relocator version here, for elf2bb, which replaces
        * it with the bootblock checksum.
        */
Chksum: .long RELVER_RELATIVE_BYTES_FORWARD
Filesz: .long 8192                      | dummy

/*
* Entry point from Kickstart.
* A1 points to an IOrequest, A6 points to ExecBase, we have a stack.
* _must_ be at offset 12.
*/
ENTRY_NOPROFILE(start)
#ifdef AUTOLOAD
       jra     Lautoload
#else
       jra     Lrelocate
#endif

Lreltab:
       .word 0                 | elf2bb puts the reloc table address here

       .globl _C_LABEL(default_command)
_C_LABEL(default_command):
       .asciz  "netbsd -ASn2"
       .org    (_C_LABEL(default_command)+32)

#ifdef AUTOLOAD
/*
* autoload
*/
Lautoload:
       movl    %a6,%sp@-                       |SysBase
       movl    %a1,%sp@-                       |IORequest

       movl    #AUTOLOAD,%d0           |Howmuch
       movl    %d0,%a1@(IOlen)         | for the actual read...
       movl    #0x10001,%d1            |MEMF_CLEAR|MEMF_PUBLIC
       jsr     %a6@(LVOAllocMem)
       movl    %sp@+,%a1                       |IORequest
       movl    %sp@+,%a6                       |SysBase
       orl     %d0,%d0
       jne     Lgotmem
       movql   #1,%d0
       rts

Lgotmem:
       movl    %d0,%sp@-                       |Address
       movl    %a1@(IOoff),%sp@-               |Old offset
       movl    %a1,%sp@-
       movl    %a6,%sp@-

/* we've set IOlen above */
       movl    %d0,%a1@(IObuf)
       movw    #Cmd_Rd,%a1@(IOcmd)
       jsr     %a6@(LVODoIO)

       movl    %sp@+,%a6
       movl    %sp@+,%a1
       movl    %sp@+,%a1@(IOoff)

       tstb    %a1@(IOerr)
       jne     Lioerr
       addl    #Lrelocate-Lzero,%sp@

       movl    %a6,%sp@-
       jsr     %a6@(LVOCacheClearU)
       movl    %sp@+,%a6
       rts
Lioerr:
       movql   #1,%d0
       addql   #4,%sp
       rts
#endif

/*
* Relocate ourselves, at the same time clearing the relocation table
* (in case it overlaps with BSS).
*
* Register usage:
* A2: points into the reloc table, located at our end.
* A0: pointer to the longword to relocate.
* D0: word offset of longword to relocate
* D1: points to our start.
*
* Table has relative byte offsets, if a byte offset is zero, it is
* followed by an absolute word offset. If this is zero, too, table
* end is reached.
*/

Lrelocate:
       lea     %pc@(Lzero),%a0
       movl    %a0,%d1

       /*
        * Here, we cannot use
        *      movw    %pc@(Lreltab),%a2
        * "movw" against An is synonym for "movea.w", which carries out
        * sign extension. This breaks things when reltab >= 0x8000.
        */
       movq    #0,%d0
       movw    %pc@(Lreltab),%d0
       movl    %d0,%a2

       addl    %d1,%a2
       jra     Loopend

Loopw:
       clrw    %a2@+
Loopb:
       addl    %d0,%a0
       addl    %d1,%a0@
Loopend:
       movq    #0,%d0
       movb    %a2@,%d0
       clrb    %a2@+   | bfclr %a2@+{0:8} is still two shorts
       tstb    %d0     | we could save one short by using casb %d0,d0,%a2@+
       jne     Loopb

       movw    %a2@,%d0
       jne     Loopw

Lendtab:
       movl    %a6,%sp@-
       jsr     %a6@(LVOCacheClearU)
       movl    %sp@+,%a6

/* We are relocated. Now it is safe to initialize _SysBase: */

       movl    %a6,_C_LABEL(SysBase)

#ifndef _PRIMARY_BOOT
       movl    %a5,%sp@-               | Console info
#endif
       movl    %a1,%sp@-
       bsr     _C_LABEL(pain)
#ifdef _PRIMARY_BOOT
       addql   #4,%sp
#else
       addql   #8,%sp
#endif

Lerr:
       movq    #1,%d0
       rts

       .comm _C_LABEL(SysBase),4