text: /* 
   *	<start.S>
   *	
   *     BIOS start code for Open Hack'Ware.
   *   
   *   Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr)
   *   
   *   This program is free software; you can redistribute it and/or
   *   modify it under the terms of the GNU General Public License V2
   *   as published by the Free Software Foundation
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  #define ASSEMBLY_CODE
  #include "bios.h"
  
  .section .start, "ax"
  .align 2
  
  .globl _start
  _start:
          /* Save our stack pointer */
          lis    r11, saved_params@h                           ;
          ori    r11, r11, saved_params@l                      ;
          stw    r1, 0(r11)                                    ;
          /* Fill space from _bss_start to _ram_start with zeroes */
          lis    r11, _bss_start@h                             ;
          ori    r11, r11, _bss_start@l                        ;
          lis    r12, _ram_start@h                             ;
          ori    r12, r12, _ram_start@l                        ;
          subf   r12, r11, r12                                 ;
          srawi  r12, r12, 2                                   ;
          cmpi   0, r12, 0                                     ;
          beq    _bss_done                                     ;
          mtctr  r12                                           ;
          subi   r11, r11, 4                                   ;
          li     r12, 0                                        ;
  _bss_loop:
          stwu   r12, 4(r11)                                   ;
          bdnz   _bss_loop                                     ;
  _bss_done:
          /* Now, we have a real C environment: call main */
          bl     main                                          ;
          /* If we return, stop */
  .globl bug
  bug:
          li     r0, 0x80                                      ;
          mtlr   r0                                            ;
          blr                                                  ;
  _return_loop:
          b      _return_loop                                  ;
  
  .section .data
  .align 2
  saved_params:
          .long 0x00000000 /* OF stack     */
          .long 0x00000000 /* client stack */
          .long 0x00000000 /* client link  */
          
  .section .text
  .align 2
  
  .globl transfer_handler
  transfer_handler:
          /* Build a new stack room and launch loaded image
           * void transfer_handler (void *residual, void *load_addr,
           *                        void *OF_entry, void *bootinfos,
           *                        void *cmdline, void *unused,
           *                        void *nip, void *stack_base);
           */
          mfmsr  r0                                            ;
          mtspr  SRR1, r0                                      ;
          mtspr  SRR0, r9                                      ;
          li     r0, 0                                         ;
          mr     r1, r10                                       ;
          stw    r1, -16(r1)                                   ;
          stwu   r0, -4(r1)                                    ;
          stwu   r0, -4(r1)                                    ;
          stwu   r0, -4(r1)                                    ;
          stwu   r0, -4(r1)                                    ;
          /* Skip frame pointer */        
          stwu   r0, -8(r1)                                    ;
          stwu   r0, -4(r1)                                    ;
          stwu   r0, -4(r1)                                    ;
          rfi                                                  ;
          /* Should never return, but who knows... */
          bl     bug                                           ;
  
  .globl  OF_entry
  OF_entry:
          /* Save the stack pointer and get our own one */
          lis    r11, saved_params@h                           ;
          ori    r11, r11, saved_params@l                      ;
          mflr   r12                                           ;
          stw    r12, 8(r11)                                   ;
          stw    r1, 4(r11)                                    ;
          lwz    r1, 0(r11)                                    ;
          bl     OF_client_entry                               ;
          lis    r11, saved_params@h                           ;
          ori    r11, r11, saved_params@l                      ;
          lwz    r12, 8(r11)                                   ;
          mtlr   r12                                           ;
          lwz    r1, 4(r11)                                    ;
          blr                                                  ;
          
          /* PPC helpers */
  .globl mfmsr
  mfmsr:
          /* uint32_t mfmsr (void); */
          mfmsr  r3                                            ;
          blr                                                  ;
  .globl mtmsr
  mtmsr:
          /* void mtmsr (uint32_t msr); */
          lis    r0, _mtmsr_rfi@h                              ;
          ori    r0, r0, _mtmsr_rfi@l                          ;
          mtspr  26, r0                                        ;
          mtspr  27, r3                                        ;
          rfi                                                  ;
  _mtmsr_rfi:
          blr                                                  ;
  .globl MMU_on
  MMU_on:
          /* void MMU_on (void); */
          stwu   r1, -16(r1)                                   ;
          mflr   r0                                            ;
          stw    r0, 20(r1)                                    ;
          mfmsr  r3                                            ;
          ori    r3, r3, 0x30                                  ;
          bl     mtmsr                                         ;
          lwz    r0, 20(r1)                                    ;
          mtlr   r0                                            ;
          addi   r1, r1, 16                                    ;
          blr                                                  ;
          
  .globl MMU_off
  MMU_off:
          /* void MMU_off (void); */
          stwu   r1, -16(r1)                                   ;
          mflr   r0                                            ;
          stw    r0, 20(r1)                                    ;
          mfmsr  r3                                            ;
          andi.  r3, r3, 0xFFCF                                ;
          bl     mtmsr                                         ;
          lwz    r0, 20(r1)                                    ;
          mtlr   r0                                            ;
          addi   r1, r1, 16                                    ;
          blr                                                  ;
          
  .globl mfpvr
  mfpvr:
          /* uint32_t mfpvr (void); */
          mfpvr  r3                                            ;
          blr                                                  ;
  
  .globl mftb
  mftb:
          /* void mftb (uint32_t *tb); */
          stwu   r1, -16(r1)                                   ;
          stw    r11, 12(r1)                                   ;
          stw    r12,  8(r1)                                   ;
          /* No need to save lr */
  _tb_loop:
          mftbu  r11                                           ;
          mftb   r12                                           ;
          mftbu  r0                                            ;
          cmpw   r0, r11                                       ;
          bne    _tb_loop                                      ;
          stw    r11,  0(r3)                                   ;
          stw    r12,  4(r3)                                   ;
          lwz    r12,  8(r1)                                   ;
          lwz    r11, 12(r1)                                   ;
          addi   r1, r1, 16                                    ;
          blr                                                  ;      
  
          /* IO helpers */
  .globl inb
  inb:
          /* uint32_t inb (uint16_t port); */
          stwu   r1, -16(r1)                                   ;
          stw    r11, 12(r1)                                   ;
          lis    r11, isa_io_base@h                            ;
          ori    r11, r11, isa_io_base@l                       ;
          lwz    r11, 0(r11)                                   ;
          add    r3, r3, r11                                   ;
          lbz    r3, 0(r3)                                     ;
          eieio                                                ;
          lwz    r11, 12(r1)                                   ;
          addi   r1, r1, 16                                    ;
          blr                                                  ;
  
  .globl outb
  outb:
          /* void outb (uint16_t port, uint32_t val); */
          stwu   r1, -16(r1)                                   ;
          stw    r11, 12(r1)                                   ;
          lis    r11, isa_io_base@h                            ;
          ori    r11, r11, isa_io_base@l                       ;
          lwz    r11, 0(r11)                                   ;
          add    r3, r3, r11                                   ;
          eieio                                                ;
          stb    r4, 0(r3)                                     ;
          lwz    r11, 12(r1)                                   ;
          addi   r1, r1, 16                                    ;
          blr                                                  ;
  
  .globl inw
  inw:
          /* uint32_t inw (uint16_t port); */
          stwu   r1, -16(r1)                                   ;
          stw    r11, 12(r1)                                   ;
          lis    r11, isa_io_base@h                            ;
          ori    r11, r11, isa_io_base@l                       ;
          lwz    r11, 0(r11)                                   ;
          add    r3, r3, r11                                   ;
          lhbrx  r3, 0, r3                                     ;
          eieio                                                ;
          lwz    r11, 12(r1)                                   ;
          addi   r1, r1, 16                                    ;
          blr                                                  ;
  
  .globl outw
  outw:
          /* void outw (uint16_t port, uint32_t val); */
          stwu   r1, -16(r1)                                   ;
          stw    r11, 12(r1)                                   ;
          lis    r11, isa_io_base@h                            ;
          ori    r11, r11, isa_io_base@l                       ;
          lwz    r11, 0(r11)                                   ;
          add    r3, r3, r11                                   ;
          eieio                                                ;
          sthbrx r4, 0, r3                                     ;
          lwz    r11, 12(r1)                                   ;
          addi   r1, r1, 16                                    ;
          blr                                                  ;
  
  .globl inl
  inl:
          /* uint32_t inl (uint16_t port); */
          stwu   r1, -16(r1)                                   ;
          stw    r11, 12(r1)                                   ;
          lis    r11, isa_io_base@h                            ;
          ori    r11, r11, isa_io_base@l                       ;
          lwz    r11, 0(r11)                                   ;
          add    r3, r3, r11                                   ;
          lwbrx  r3, 0, r3                                     ;
          eieio                                                ;
          lwz    r11, 12(r1)                                   ;
          addi   r1, r1, 16                                    ;
          blr                                                  ;
  
  .globl outl
  outl:
          /* void outl (uint16_t port, uint32_t val); */
          stwu   r1, -16(r1)                                   ;
          stw    r11, 12(r1)                                   ;
          lis    r11, isa_io_base@h                            ;
          ori    r11, r11, isa_io_base@l                       ;
          lwz    r11, 0(r11)                                   ;
          add    r3, r3, r11                                   ;
          eieio                                                ;
          stwbrx r4, 0, r3                                     ;
          lwz    r11, 12(r1)                                   ;
          addi   r1, r1, 16                                    ;
          blr                                                  ;
  
  .globl eieio
  eieio:
          eieio                                                ;
          blr                                                  ;
          
          /* Misc helpers */
  .globl ldswap16
  ldswap16:
          /* uint16_t ldswap16 (uint16_t *addr); */
          lhbrx  r3, 0, r3                                     ;
          blr                                                  ;
  
  .globl stswap16
  stswap16:
          /* void stswap16 (void *addr, uint16_t val); */
          sthbrx r4, 0, r3                                     ;
          blr                                                  ;
  
  .globl ldswap32
  ldswap32:
          /* uint32_t ldswap32 (uint32_t *addr); */
          lwbrx  r3, 0, r3                                     ;
          blr                                                  ;
  
  .globl stswap32
  stswap32:
          /* void stswap32 (void *addr, uint32_t val); */
          stwbrx r4, 0, r3                                     ;
          blr                                                  ;
  
  .globl mul64
  mul64:
          /* void mul64 (uint32_t *ret, uint32_t a, uint32_t b); */
          mulhwu r0, r4, r5                                    ;
          stw    r0, 0(r3)                                     ;
          mullw  r0, r4, r5                                    ;
          stw    r0, 4(r3)                                     ;
          blr                                                  ;
  
  .globl add64
  add64:
          /* void add64 (uint32_t *ret, uint32_t *a, uint32_t *b); */
          stwu   r1, -16(r1)                                   ;
          stw    r11, 12(r1)                                   ;
          stw    r12,  8(r1)                                   ;
          lwz    r11,  4(r4)                                   ;
          lwz    r12,  4(r5)                                   ;
          addc   r0, r11, r12                                  ;
          stw    r0,   4(r3)                                   ;
          lwz    r11,  0(r4)                                   ;
          lwz    r12,  0(r5)                                   ;
          adde   r0, r11, r12                                  ;
          stw    r0,   0(r3)                                   ;
          lwz    r12,  8(r1)                                   ;
          lwz    r11,  4(r1)                                   ;
          addi   r1, r1, 16                                    ;
          blr                                                  ;
  
  .globl setjmp
  setjmp:
          /* int setjmp (jmp_buf env); */
          /* save gprs */
          stmw   r0, 0(r3)                                     ;
          /* save lr, ctr, xer and ccr */
          mflr   r0                                            ;
          stw    r0, 0x80(r3)                                  ;
          mfctr  r0                                            ;
          stw    r0, 0x84(r3)                                  ;
          mfxer  r0                                            ;
          stw    r0, 0x88(r3)                                  ;
          mfcr   r0                                            ;
          stw    r0, 0x8C(r3)                                  ;
          /* return 0 */
          li     r3, 0                                         ;
          blr                                                  ;
  
  .globl longjmp
  longjmp:
          /* void longjmp (jmp_buf env, int val); */
          /* Let's pretend env is our stack */
          mr     r1, r3                                        ;
          /* Be sure we won't return 0 */
          cmpi   0, r4, 0                                      ;
          bne    _longjmp_cont                                 ;
          addi   r4, r4, 1                                     ;
  _longjmp_cont:
          /* Store return value in jmp_buf */
          stw    r4, 0x0C(r1)                                  ;
          /* restore lr, ctr, xer and ccr */
          lwz    r0, 0x80(r1)                                  ;
          mtlr   r0                                            ;
          lwz    r0, 0x84(r1)                                  ;
          mtctr  r0                                            ;
          lwz    r0, 0x88(r1)                                  ;
          mtxer  r0                                            ;
          lwz    r0, 0x8C(r1)                                  ;
          mtcr   r0                                            ;
          /* Restore r2 to r31 */
          lmw    r2, 0x08(r1)                                  ;
          /* Restore r0 (could forget it...) */
          lwz    r0, 0x00(r1)                                  ;
          /* Restore stack */
          lwz    r1, 0x04(r1)                                  ;
          /* Return */
          blr                                                  ;
  