#
# Copyright (c) 2006 Martin Decky
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# - 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.
# - The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <abi/asmtool.h>
#include <arch/arch.h>
#include <arch/regname.h>
.macro SMC_COHERENCY addr
dcbst 0, \addr
sync
icbi 0, \addr
sync
isync
.endm
.macro FLUSH_DCACHE addr
dcbst 0, \addr
sync
isync
.endm
.macro TLB_FLUSH reg
li \reg, 0
sync
.rept 64
tlbie \reg
addi \reg, \reg, 0x1000
.endr
eieio
tlbsync
sync
.endm
.macro BAT_COMPUTE base size mask lower upper
# less than 128 KB -> no BAT
lis \upper, 0x0002
cmpw \size, \upper
blt no_bat
# mask = total >> 18
li \upper, 18
srw \mask, \size, \upper
# create Block Length mask by replicating
# the leading logical one 14 times
li \upper, 14
mtctr \mask
li \upper, 1
0:
# mask = (mask >> 1) | mask
srw \lower, \mask, \upper
or \mask, \mask, \lower
bdnz 0b
# mask = mask & 0x07ff
# (BAT can map up to 256 MB)
andi. \mask, \mask, 0x07ff
# mask = (mask << 2) | 0x0002
# (priviledged access only)
li \upper, 2
slw \mask, \mask, \upper
ori \mask, \mask, 0x0002
lis \upper, (0x8000 + \base)
or \upper, \upper, \mask
lis \lower, \base
ori \lower, \lower, 0x0002
.endm
.section BOOTSTRAP, "ax"
SYMBOL(start)
lis r4, ofw_cif@ha
addi r4, r4, ofw_cif@l
stw r5, 0(r4)
bl ofw_init
b bootstrap
.text
FUNCTION_BEGIN(halt)
b halt
FUNCTION_END(halt)
FUNCTION_BEGIN(jump_to_kernel)
# arguments:
# r3 = bootinfo (physical address)
# r4 = translate table (physical address)
# r5 = pages to translate
# r6 = real mode meeting point (physical address)
# r7 = kernel entry point (virtual address in kernel's address space)
# disable interrupts
mfmsr r31
rlwinm r31, r31, 0, 17, 15
mtmsr r31
# set real mode meeting point physical address
mtspr srr0, r6
# jump to real_mode
mfmsr r31
lis r30, ~0@h
ori r30, r30, ~(msr_ir | msr_dr | msr_ee)@l
and r31, r31, r30
mtspr srr1, r31
sync
isync
rfi
FUNCTION_END(jump_to_kernel)
SYMBOL(real_mode)
# arguments:
# r3 = bootinfo (physical address)
# r4 = translate table (physical address)
# r5 = pages to translate
# r7 = kernel entry point (virtual address in kernel's address space)
# move the images of components to the proper
# location using the translate table
li r31, PAGE_SIZE >> 2
li r30, 0
page_copy:
cmpwi r5, 0
beq copy_end
mtctr r31
lwz r29, 0(r4)
copy_loop:
lwz r28, 0(r29)
stw r28, 0(r30)
SMC_COHERENCY r30
addi r29, r29, 4
addi r30, r30, 4
bdnz copy_loop
addi r4, r4, 4
subi r5, r5, 1
b page_copy
copy_end:
# initially fill segment registers
li r31, 0
li r29, 8
mtctr r29
li r30, 0 # ASID 0 (VSIDs 0 .. 7)
seg_fill_uspace:
mtsrin r30, r31
addi r30, r30, 1
addis r31, r31, 0x1000 # move to next SR
bdnz seg_fill_uspace
li r29, 8
mtctr r29
lis r30, 0x4000 # priviledged access only
ori r30, r30, 8 # ASID 0 (VSIDs 8 .. 15)
seg_fill_kernel:
mtsrin r30, r31
addi r30, r30, 1
addis r31, r31, 0x1000 # move to next SR
bdnz seg_fill_kernel
# invalidate block address translation registers
li r30, 0
mtspr ibat0u, r30
mtspr ibat0l, r30
mtspr ibat1u, r30
mtspr ibat1l, r30
mtspr ibat2u, r30
mtspr ibat2l, r30
mtspr ibat3u, r30
mtspr ibat3l, r30
mtspr dbat0u, r30
mtspr dbat0l, r30
mtspr dbat1u, r30
mtspr dbat1l, r30
mtspr dbat2u, r30
mtspr dbat2l, r30
mtspr dbat3u, r30
mtspr dbat3l, r30
# create empty Page Hash Table
# on top of memory, size 64 KB
lwz r31, 4(r3) # r31 = memory size
lis r30, 65536@h
ori r30, r30, 65536@l # r30 = 65536
subi r29, r30, 1 # r29 = 65535
sub r31, r31, r30
andc r31, r31, r29 # pht = ALIGN_DOWN(memory_size - 65536, 65536)
mtsdr1 r31
li r29, 2
srw r30, r30, r29 # r30 = 16384
li r29, 0
pht_clear:
# write zeroes
stw r29, 0(r31)
FLUSH_DCACHE r31
addi r31, r31, 4
subi r30, r30, 4
cmpwi r30, 0
beq clear_end
bdnz pht_clear
clear_end:
# create BAT identity mapping
lwz r31, 4(r3) # r31 = memory size
lis r30, 268435456@h
ori r30, r30, 268435456@l # r30 = 256 MB
# BAT0
# r29 = min(r31, r30)
cmpw r31, r30
blt bat0_r31
mr r29, r30
b bat0_r30
bat0_r31:
mr r29, r31
bat0_r30:
BAT_COMPUTE 0x0000 r29 r28 r27 r26
mtspr ibat0u, r26
mtspr ibat0l, r27
mtspr dbat0u, r26
mtspr dbat0l, r27
# BAT1
sub r31, r31, r29 # r31 = r31 - r29
# r29 = min(r31, r30)
cmpw r31, r30
blt bat1_r31
mr r29, r30
b bat1_r30
bat1_r31:
mr r29, r31
bat1_r30:
BAT_COMPUTE 0x1000 r29 r28 r27 r26
mtspr ibat1u, r26
mtspr ibat1l, r27
mtspr dbat1u, r26
mtspr dbat1l, r27
# BAT2
sub r31, r31, r29 # r31 = r31 - r29
# r29 = min(r31, r30)
cmpw r31, r30
blt bat2_r31
mr r29, r30
b bat2_r30
bat2_r31:
mr r29, r31
bat2_r30:
BAT_COMPUTE 0x2000 r29 r28 r27 r26
mtspr ibat2u, r26
mtspr ibat2l, r27
mtspr dbat2u, r26
mtspr dbat2l, r27
# BAT3
sub r31, r31, r29 # r31 = r31 - r29
# r29 = min(r31, r30)
cmpw r31, r30
blt bat3_r31
mr r29, r30
b bat3_r30
bat3_r31:
mr r29, r31
bat3_r30:
BAT_COMPUTE 0x3000 r29 r28 r27 r26
mtspr ibat3u, r26
mtspr ibat3l, r27
mtspr dbat3u, r26
mtspr dbat3l, r27
no_bat:
# flush TLB
TLB_FLUSH r31
# start the kernel
#
# pc = kernel's entry point (r7)
# r3 = bootinfo (physical address)
# sprg3 = physical memory size
# sp = 0 (enforces the usage of sprg0 as exception stack)
mtspr srr0, r7
# Clear sprg0. Kernel will set it.
li r31, 0
mtsprg0 r31
# bootinfo starts with a 64 bit integer containing
# the physical memory size, get the lower 4 bytes
// FIXME: unchecked magic offset
lwz r31, 4(r3)
mtsprg3 r31
li sp, 0
mfmsr r31
ori r31, r31, (msr_ir | msr_dr)@l
mtspr srr1, r31
sync
isync
rfi