freebsd-skq/sys/powerpc/aim/locore64.S
Brandon Bergren 9411e24df3 [PowerPC] kernel ifunc support for powerpc*, fix ppc64 relocation oddities.
This is a general cleanup of the relocatable kernel support on powerpc,
needed to enable kernel ifuncs.

 * Fix some relocatable issues in the kernel linker, and change to using
   a RELOCATABLE_KERNEL #define instead of #ifdef __powerpc__ for parts that
   other platforms can use in the future if they wish to have ET_DYN kernels.

 * Get rid of the DB_STOFFS hack now that the kernel is relocated to the DMAP
   properly across the board on powerpc64.

 * Add powerpc64 and powerpc32 ifunc functionality.

 * Allow AIM64 virtual mode OF kernels to run from the DMAP like other AIM64
   by implementing a virtual mode restart. This fixes the runtime address on
   PowerMac G5.

 * Fix symbol relocation problems on post-relocation kernels by relocating
   the symbol table.

 * Add an undocumented method for supplying kernel symbols on powernv and
   other powerpc machines using linux-style kernel/initrd loading -- If
   you pass the kernel in as the initrd as well, the copy resident in initrd
   will be used as a source for symbols when initializing the debugger.
   This method is subject to removal once we have a better way of doing this.

Approved by:	jhibbits
Relnotes:	yes
Sponsored by:	Tag1 Consulting, Inc.
Differential Revision:	https://reviews.freebsd.org/D23156
2020-05-07 19:32:49 +00:00

271 lines
6.4 KiB
ArmAsm

/* $FreeBSD$ */
/*-
* Copyright (C) 2010-2016 Nathan Whitehorn
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* 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 TOOLS GMBH 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.
*
* $FreeBSD$
*/
#include "assym.inc"
#include <sys/syscall.h>
#include <machine/trap.h>
#include <machine/param.h>
#include <machine/spr.h>
#include <machine/asm.h>
#include <machine/vmparam.h>
#ifdef _CALL_ELF
.abiversion _CALL_ELF
#endif
/* Glue for linker script */
.globl kernbase
.set kernbase, KERNBASE
/*
* Globals
*/
.data
.align 3
GLOBAL(__startkernel)
.llong begin
GLOBAL(__endkernel)
.llong end
GLOBAL(can_wakeup)
.llong 0x0
.align 4
#define TMPSTKSZ 16384 /* 16K temporary stack */
GLOBAL(tmpstk)
.space TMPSTKSZ
TOC_ENTRY(tmpstk)
TOC_ENTRY(can_wakeup)
#ifdef KDB
#define TRAPSTKSZ 8192 /* 8k trap stack */
GLOBAL(trapstk)
.space TRAPSTKSZ
TOC_ENTRY(trapstk)
#endif
/*
* Entry point for bootloaders that do not fully implement ELF and start
* at the beginning of the image (kexec, notably). In its own section so
* that it ends up before any linker-generated call stubs and actually at
* the beginning of the image. kexec on some systems also enters at
* (start of image) + 0x60, so put a spin loop there.
*/
.section ".text.kboot", "x", @progbits
kbootentry:
b __start
. = kbootentry + 0x40 /* Magic address used in platform layer */
.global smp_spin_sem
ap_kexec_spin_sem:
.long -1
. = kbootentry + 0x60 /* Entry point for kexec APs */
ap_kexec_start: /* At 0x60 past start, copied to 0x60 by kexec */
/* r3 set to CPU ID by kexec */
/* Invalidate icache for low-memory copy and jump there */
li %r0,0x80
dcbst 0,%r0
sync
icbi 0,%r0
isync
ba 0x80 /* Absolute branch to next inst */
. = kbootentry + 0x80 /* Aligned to cache line */
1: or 31,31,31 /* yield */
sync
lwz %r1,0x40(0) /* Spin on ap_kexec_spin_sem */
cmpw %r1,%r3 /* Until it equals our CPU ID */
bne 1b
/* Released */
or 2,2,2 /* unyield */
/* Make sure that it will be software reset. Clear SRR1 */
li %r1,0
mtsrr1 %r1
ba EXC_RST
/*
* Now start the real text section
*/
.text
.globl btext
btext:
/*
* Main kernel entry point.
*
* Calling convention:
* r3: Flattened Device Tree pointer (or zero)
* r4: ignored
* r5: OF client interface pointer (or zero)
* r6: Loader metadata pointer (or zero)
* r7: Magic cookie (0xfb5d104d) to indicate that r6 has loader metadata
*/
.text
ASENTRY_NOPROF(__start)
/* Set 64-bit mode if not yet set before branching to C */
mfmsr %r20
li %r21,1
insrdi %r20,%r21,1,0
mtmsrd %r20
isync
nop /* Make this block a multiple of 8 bytes */
/* Set up the TOC pointer */
b 0f
.align 3
0: nop
bl 1f
.llong __tocbase + 0x8000 - .
1: mflr %r2
ld %r1,0(%r2)
add %r2,%r1,%r2
/* Get load offset */
ld %r31,-0x8000(%r2) /* First TOC entry is TOC base */
subf %r31,%r31,%r2 /* Subtract from real TOC base to get base */
/* Set up the stack pointer */
bl 1f
.llong tmpstk + TMPSTKSZ - 96 - .
1: mflr %r30
ld %r1,0(%r30)
add %r1,%r1,%r30
nop
/* Relocate kernel */
std %r3,48(%r1)
std %r4,56(%r1)
std %r5,64(%r1)
std %r6,72(%r1)
std %r7,80(%r1)
bl 1f
.llong _DYNAMIC-.
1: mflr %r3
ld %r4,0(%r3)
add %r3,%r4,%r3
mr %r4,%r31
bl elf_reloc_self
nop
ld %r3,48(%r1)
ld %r4,56(%r1)
ld %r5,64(%r1)
ld %r6,72(%r1)
ld %r7,80(%r1)
/* Begin CPU init */
mr %r4,%r2 /* Replace ignored r4 with tocbase for trap handlers */
bl powerpc_init
nop
/* Set stack pointer to new value and branch to mi_startup */
mr %r1, %r3
li %r3, 0
std %r3, 0(%r1)
bl mi_startup
nop
/* Unreachable */
b .
ASENTRY_NOPROF(__restartkernel_virtual)
/*
* When coming in via this entry point, we need to alter the SLB to
* shadow the segment register emulation entries in DMAP space.
* We need to do this dance because we are running with virtual-mode
* OpenFirmware and have not yet taken over the MMU.
*
* Assumptions:
* 1) The kernel is currently identity-mapped.
* 2) We are currently executing at an address compatible with
* real mode.
* 3) The first 16 SLB entries are emulating SRs.
* 4) The rest of the SLB is not in use.
* 5) OpenFirmware is not manipulating the SLB at runtime.
* 6) We are running on 64-bit AIM.
*
* Tested on a G5.
*/
mfmsr %r14
/* Switch to real mode because we are about to mess with the SLB. */
andi. %r14, %r14, ~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l
mtmsr %r14
isync
/* Prepare variables for later use. */
li %r14, 0
li %r18, 0
oris %r18, %r18, 0xc000
sldi %r18, %r18, 32 /* r18: 0xc000000000000000 */
1:
/*
* Loop over the first 16 SLB entries.
* Offset the SLBE into the DMAP, add 16 to the index, and write
* it back to the SLB.
*/
/* XXX add more safety checks */
slbmfev %r15, %r14
slbmfee %r16, %r14
or %r16, %r16, %r14 /* index is 0-15 */
ori %r16, %r16, 0x10 /* add 16 to index. */
or %r16, %r16, %r18 /* SLBE DMAP offset */
rldicr %r17, %r16, 0, 37 /* Invalidation SLBE */
isync
slbie %r17
/* isync */
slbmte %r15, %r16
isync
addi %r14, %r14, 1
cmpdi %r14, 16
blt 1b
ASENTRY_NOPROF(__restartkernel)
/*
* r3-r7: arguments to go to __start
* r8: offset from current kernel address to apply
* r9: MSR to set when (atomically) jumping to __start + r8
*/
mtsrr1 %r9
bl 1f
1: mflr %r25
add %r25,%r8,%r25
addi %r25,%r25,2f-1b
mtsrr0 %r25
rfid
2: bl __start
nop
#include <powerpc/aim/trap_subr64.S>