HelenOS sources

root/boot/arch/ppc32/src/asm.S

/* [<][>][^][v][top][bottom][index][help] */
#
# 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

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub