301 lines
7.7 KiB
ArmAsm
301 lines
7.7 KiB
ArmAsm
/**
|
|
** 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 <asm/asi.h>
|
|
#include "pstate.h"
|
|
#include "lsu.h"
|
|
#include "cpustate.h"
|
|
#define NO_QEMU_PROTOS
|
|
#define NO_OPENBIOS_PROTOS
|
|
#include "arch/common/fw_cfg.h"
|
|
|
|
#define PROM_ADDR 0x1fff0000000
|
|
#define CFG_ADDR 0x1fe02000510
|
|
#define HZ 1 * 1000 * 1000
|
|
#define TICK_INT_DIS 0x8000000000000000
|
|
|
|
.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
|
|
! disable timer now
|
|
setx TICK_INT_DIS, %g2, %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_L
|
|
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
|
|
|
|
! Clear ITLB
|
|
mov 6 << 3, %g1
|
|
stxa %g0, [%g1] ASI_IMMU
|
|
stxa %g0, [%g1] ASI_DMMU
|
|
mov 63 << 3, %g1
|
|
1: stxa %g0, [%g1] ASI_ITLB_DATA_ACCESS
|
|
subcc %g1, 1 << 3, %g1
|
|
bpos 1b
|
|
nop
|
|
|
|
! Clear DTLB
|
|
mov 63 << 3, %g1
|
|
1: stxa %g0, [%g1] ASI_DTLB_DATA_ACCESS
|
|
subcc %g1, 1 << 3, %g1
|
|
bpos 1b
|
|
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_L
|
|
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 0x7ffff, %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, 19, %g6 ! %g6 = # of 512k .bss pages
|
|
set 0xc0000000, %g3
|
|
sllx %g3, 32, %g3
|
|
or %g3, 0x7e, %g3
|
|
! valid, 512k, locked, cacheable(I/E/C), priv, writable
|
|
set 48, %g7
|
|
1: stxa %g4, [%g7] ASI_DMMU ! vaddr = _data + N * 0x80000, ctx=0
|
|
or %g2, %g3, %g5
|
|
! paddr = start_mem + N * 0x80000
|
|
stxa %g5, [%g0] ASI_DTLB_DATA_IN
|
|
set 0x80000, %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, 19, %g6 ! %g6 = # of 512k .rodata pages
|
|
set 48, %g7
|
|
set 0x80000, %g5
|
|
setx PROM_ADDR, %l1, %l2
|
|
1: stxa %g4, [%g7] ASI_DMMU ! vaddr = _rodata, ctx=0
|
|
set 0xc0000000, %g3
|
|
sllx %g3, 32, %g3
|
|
or %g3, 0x7c, %g3
|
|
or %l2, %g3, %g3
|
|
! valid, 512k, 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
|
|
|
|
membar #Sync
|
|
|
|
setx _start, %g7, %g4
|
|
setx _rodata, %g7, %g5
|
|
sub %g5, %g4, %g5
|
|
set 0x7ffff, %g7
|
|
add %g5, %g7, %g5 ! round to 512k
|
|
srlx %g5, 19, %g6 ! %g6 = # of 512k .text pages
|
|
set 0x80000, %g5
|
|
set 48, %g7
|
|
setx PROM_ADDR, %l1, %l2
|
|
1: stxa %g4, [%g7] ASI_IMMU ! vaddr = _start, ctx=0
|
|
set 0xc0000000, %g3
|
|
sllx %g3, 32, %g3
|
|
or %g3, 0x7c, %g3
|
|
or %l2, %g3, %g3
|
|
! valid, 512k, locked, cacheable(I/E/C), priv
|
|
! paddr = _start + N * 0x80000
|
|
stxa %g3, [%g0] ASI_ITLB_DATA_IN
|
|
add %g4, %g5, %g4
|
|
deccc %g6
|
|
bne 1b
|
|
add %l2, %g5, %l2
|
|
|
|
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
|
|
|
|
/* Set up a default context */
|
|
setx __context, %g2, %g1
|
|
ldx [%g1], %g1
|
|
|
|
SAVE_CPU_STATE(entry)
|
|
|
|
/* Set up local stack pointer */
|
|
setx _estack - 2047, %o2, %sp
|
|
|
|
/* And for the main context */
|
|
add %sp, - 192 - 0x500, %g2
|
|
stx %g2, [%g1 + 0xa0]
|
|
|
|
! 100 Hz timer
|
|
setx TICK_INT_DIS, %g2, %g1
|
|
rd %tick, %g2
|
|
andn %g2, %g1, %g2
|
|
set HZ, %g1
|
|
add %g1, %g2, %g1
|
|
wr %g1, 0, %tick_cmpr
|
|
|
|
/* Switch to our main context.
|
|
* Main context is statically defined in C.
|
|
*/
|
|
|
|
call __switch_context
|
|
nop
|
|
|
|
/* We get here when the main context switches back to
|
|
* the boot context.
|
|
*/
|
|
bad_conf:
|
|
b bad_conf
|
|
nop
|