Files
openbios/arch/sparc64/entry.S

315 lines
7.7 KiB
ArmAsm
Raw Normal View History

/**
** Standalone startup code for Linux PROM emulator.
** Copyright 1999 Pete A. Zaitcev
** This code is licensed under GNU General Public License.
**/
/*
* $Id: head.S,v 1.12 2002/07/23 05:47:09 zaitcev Exp $
*/
#define __ASSEMBLY__
#include "asi.h"
#include "pstate.h"
#include "lsu.h"
#define NO_QEMU_PROTOS
#include "openbios/fw_cfg.h"
#define PROM_ADDR 0x1fff0000000
#define CFG_ADDR 0x1fe02000510
.globl entry, _entry
.section ".text", "ax"
.align 8
.register %g2, #scratch
.register %g3, #scratch
.register %g6, #scratch
.register %g7, #scratch
/*
* Entry point
* We start execution from here.
*/
_entry:
entry:
! Set up CPU state
wrpr %g0, PSTATE_PRIV, %pstate
wr %g0, 0, %fprs
wrpr %g0, 0x0, %tl
! Extract NWINDOWS from %ver
rdpr %ver, %g1
and %g1, 0xf, %g1
dec %g1
wrpr %g1, 0, %cleanwin
wrpr %g1, 0, %cansave
wrpr %g0, 0, %canrestore
wrpr %g0, 0, %otherwin
wrpr %g0, 0, %wstate
! 100 Hz timer
set 10 * 1000 * 1000, %g1
wr %g1, 0, %tick_cmpr
! Disable I/D MMUs and caches
stxa %g0, [%g0] ASI_LSU_CONTROL
! Check signature "QEMU"
setx CFG_ADDR, %g2, %g5
mov FW_CFG_SIGNATURE, %g2
stha %g2, [%g5] ASI_PHYS_BYPASS_EC_E
inc %g5
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g2
cmp %g2, 'Q'
bne bad_conf
nop
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g2
cmp %g2, 'E'
bne bad_conf
nop
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g2
cmp %g2, 'M'
bne bad_conf
nop
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g2
cmp %g2, 'U'
bne bad_conf
nop
! Get memory size from configuration device
! NB: little endian format
mov FW_CFG_RAM_SIZE, %g2
dec %g5
stha %g2, [%g5] ASI_PHYS_BYPASS_EC_E
inc %g5
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g4
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3
sllx %g3, 8, %g3
or %g3, %g4, %g4
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3
sllx %g3, 16, %g3
or %g3, %g4, %g4
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3
sllx %g3, 24, %g3
or %g3, %g4, %g4
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3
sllx %g3, 32, %g3
or %g3, %g4, %g4
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3
sllx %g3, 40, %g3
or %g3, %g4, %g4
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3
sllx %g3, 48, %g3
or %g3, %g4, %g4
lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3
sllx %g3, 56, %g3
or %g3, %g4, %g1
! %g1 contains end of memory
setx _end, %g7, %g3
set 0xffff, %g2
add %g3, %g2, %g3
andn %g3, %g2, %g3
setx _data, %g7, %g2
sub %g3, %g2, %g2
sub %g1, %g2, %g2 ! %g2 = start of private memory
mov %g2, %l0
! setup .data & .bss
setx _data, %g7, %g4
sub %g3, %g4, %g5
srlx %g5, 16, %g6 ! %g6 = # of 64k .bss pages
set 0xa0000000, %g3
sllx %g3, 32, %g3
or %g3, 0x76, %g3
! valid, 64k, locked, cacheable(I/E/C), priv, writable
set 48, %g7
1: stxa %g4, [%g7] ASI_DMMU ! vaddr = _data + N * 0x10000, ctx=0
or %g2, %g3, %g5
! paddr = start_mem + N * 0x10000
stxa %g5, [%g0] ASI_DTLB_DATA_IN
set 0x10000, %g5
add %g2, %g5, %g2
add %g4, %g5, %g4
deccc %g6
bne 1b
nop
! setup .rodata, also make .text readable
setx _data, %g7, %g5
setx _start, %g7, %g4
sub %g5, %g4, %g5
srlx %g5, 16, %g6 ! %g6 = # of 64k .rodata pages
set 48, %g7
set 0x10000, %g5
setx PROM_ADDR, %l1, %l2
1: stxa %g4, [%g7] ASI_DMMU ! vaddr = _rodata, ctx=0
set 0xa0000000, %g3
sllx %g3, 32, %g3
or %g3, 0x74, %g3
or %l2, %g3, %g3
! valid, 64k, locked, cacheable(I/E/C), priv
! paddr = _rodata + N * 0x10000
stxa %g3, [%g0] ASI_DTLB_DATA_IN
add %g4, %g5, %g4
deccc %g6
bne 1b
add %l2, %g5, %l2
! setup VGA buffer
setx 0x1ff004a0000, %g7, %g4
mov 2, %g6
set 48, %g7
set 0x10000, %g5
1: stxa %g4, [%g7] ASI_DMMU ! vaddr = 0x1ff004a0000, ctx=0
set 0xa0000000, %g3
sllx %g3, 32, %g3
or %g3, 0x76, %g3
or %g4, %g3, %g3
! valid, 64k, locked, cacheable(I/E/C), priv, writable
! paddr = 0x1ff004a0000
stxa %g3, [%g0] ASI_DTLB_DATA_IN
add %g4, %g5, %g4
deccc %g6
bne 1b
nop
#if 1
! setup 0-16M
mov %g0, %g4
mov 4, %g6
set 48, %g7
set 0x400000, %g5
1: stxa %g4, [%g7] ASI_DMMU ! vaddr = 0, ctx=0
set 0xe0000000, %g3
sllx %g3, 32, %g3
or %g3, 0x36, %g3
or %g4, %g3, %g3
! valid, 4M, cacheable(I/E/C), priv, writable
! paddr = 0
stxa %g3, [%g0] ASI_DTLB_DATA_IN
add %g4, %g5, %g4
deccc %g6
bne 1b
nop
#endif
membar #Sync
setx _start, %g7, %g4
setx _rodata, %g7, %g5
sub %g5, %g4, %g5
srlx %g5, 16, %g6 ! %g6 = # of 64k .text pages
set 0x10000, %g5
set 48, %g7
setx PROM_ADDR, %l1, %l2
1: stxa %g4, [%g7] ASI_IMMU ! vaddr = _start, ctx=0
set 0xa0000000, %g3
sllx %g3, 32, %g3
or %g3, 0x74, %g3
or %l2, %g3, %g3
! valid, 64k, locked, cacheable(I/E/C), priv
! paddr = _start + N * 0x10000
stxa %g3, [%g0] ASI_ITLB_DATA_IN
add %g4, %g5, %g4
deccc %g6
bne 1b
add %l2, %g5, %l2
#if 1
! setup 0-16M
mov %g0, %g4
mov 4, %g6
set 0x400000, %g5
1: stxa %g4, [%g7] ASI_IMMU ! vaddr = 0, ctx=0
set 0xe0000000, %g3
sllx %g3, 32, %g3
or %g3, 0x34, %g3
or %g4, %g3, %g3
! valid, 4M, cacheable(I/E/C), priv
! paddr = 0
stxa %g3, [%g0] ASI_ITLB_DATA_IN
add %g4, %g5, %g4
deccc %g6
bne 1b
nop
#endif
flush %g4
mov %g1, %g3
set 8, %g2
sta %g0, [%g2] ASI_DMMU ! set primary ctx=0
! Enable I/D MMUs and caches
setx lowmem, %g2, %g1
set LSU_CONTROL_DM|LSU_CONTROL_IM|LSU_CONTROL_DC|LSU_CONTROL_IC, %g2
jmp %g1
stxa %g2, [%g0] ASI_LSU_CONTROL
lowmem:
/* Copy the DATA section from ROM. */
setx _data - 8, %o7, %o0 ! First address of DATA
setx _bss, %o7, %o1 ! Last address of DATA
setx _start, %o7, %o2
sub %o0, %o2, %o2 ! _data - _start
setx PROM_ADDR, %o7, %o3
add %o3, %o2, %o2 ! PROM_ADDR + (_data - _start)
ba 2f
nop
1:
ldxa [%o2] ASI_PHYS_BYPASS_EC_E, %g1
stx %g1, [%o0]
2:
add %o2, 0x8, %o2
subcc %o0, %o1, %g0
bl 1b
add %o0, 0x8, %o0
/* Zero out our BSS section. */
setx _bss - 8, %o7, %o0 ! First address of BSS
setx _end - 8, %o7, %o1 ! Last address of BSS
ba 2f
nop
1:
stx %g0, [%o0]
2:
subcc %o0, %o1, %g0
bl 1b
add %o0, 0x8, %o0
setx trap_table, %g2, %g1
wrpr %g1, %tba
setx qemu_mem_size, %g7, %g1
stx %g3, [%g1]
setx _data, %g7, %g1 ! Store va->pa conversion factor
sub %g1, %l0, %g2
setx va_shift, %g7, %g1
stx %g2, [%g1]
/* Finally, turn on traps so that we can call c-code. */
wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
/* Switch to our main context.
* Main context is statically defined in C.
*/
call __switch_context_nosave
nop
/* We get here when the main context switches back to
* the boot context.
*/
bad_conf:
b bad_conf
nop