Skip to content
misc_32.S 19.9 KiB
Newer Older
/*
 * This file contains miscellaneous low-level functions.
 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
 *
 * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
 * and Paul Mackerras.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 *
 */

#include <linux/config.h>
#include <linux/sys.h>
#include <asm/unistd.h>
#include <asm/errno.h>
#include <asm/reg.h>
#include <asm/page.h>
#include <asm/cache.h>
#include <asm/cputable.h>
#include <asm/mmu.h>
#include <asm/ppc_asm.h>
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>

	.text

	.align	5
_GLOBAL(__delay)
	cmpwi	0,r3,0
	mtctr	r3
	beqlr
1:	bdnz	1b
	blr

/*
 * Returns (address we're running at) - (address we were linked at)
 * for use before the text and data are mapped to KERNELBASE.
 */
_GLOBAL(reloc_offset)
	mflr	r0
	bl	1f
1:	mflr	r3
	LOADADDR(r4,1b)
	subf	r3,r4,r3
	mtlr	r0
	blr

/*
 * add_reloc_offset(x) returns x + reloc_offset().
 */
_GLOBAL(add_reloc_offset)
	mflr	r0
	bl	1f
1:	mflr	r5
	LOADADDR(r4,1b)
	subf	r5,r4,r5
	add	r3,r3,r5
	mtlr	r0
	blr

/*
 * sub_reloc_offset(x) returns x - reloc_offset().
 */
_GLOBAL(sub_reloc_offset)
	mflr	r0
	bl	1f
1:	mflr	r5
	lis	r4,1b@ha
	addi	r4,r4,1b@l
	subf	r5,r4,r5
	subf	r3,r5,r3
	mtlr	r0
	blr

/*
 * reloc_got2 runs through the .got2 section adding an offset
 * to each entry.
 */
_GLOBAL(reloc_got2)
	mflr	r11
	lis	r7,__got2_start@ha
	addi	r7,r7,__got2_start@l
	lis	r8,__got2_end@ha
	addi	r8,r8,__got2_end@l
	subf	r8,r7,r8
	srwi.	r8,r8,2
	beqlr
	mtctr	r8
	bl	1f
1:	mflr	r0
	lis	r4,1b@ha
	addi	r4,r4,1b@l
	subf	r0,r4,r0
	add	r7,r0,r7
2:	lwz	r0,0(r7)
	add	r0,r0,r3
	stw	r0,0(r7)
	addi	r7,r7,4
	bdnz	2b
	mtlr	r11
	blr

/*
 * identify_cpu,
 * called with r3 = data offset and r4 = CPU number
 * doesn't change r3
 */
_GLOBAL(identify_cpu)
	addis	r8,r3,cpu_specs@ha
	addi	r8,r8,cpu_specs@l
	mfpvr	r7
1:
	lwz	r5,CPU_SPEC_PVR_MASK(r8)
	and	r5,r5,r7
	lwz	r6,CPU_SPEC_PVR_VALUE(r8)
	cmplw	0,r6,r5
	beq	1f
	addi	r8,r8,CPU_SPEC_ENTRY_SIZE
	b	1b
1:
	addis	r6,r3,cur_cpu_spec@ha
	addi	r6,r6,cur_cpu_spec@l
	sub	r8,r8,r3
	stw	r8,0(r6)
	blr

/*
 * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
 * and writes nop's over sections of code that don't apply for this cpu.
 * r3 = data offset (not changed)
 */
_GLOBAL(do_cpu_ftr_fixups)
	/* Get CPU 0 features */
	addis	r6,r3,cur_cpu_spec@ha
	addi	r6,r6,cur_cpu_spec@l
	lwz	r4,0(r6)
	add	r4,r4,r3
	lwz	r4,CPU_SPEC_FEATURES(r4)

	/* Get the fixup table */
	addis	r6,r3,__start___ftr_fixup@ha
	addi	r6,r6,__start___ftr_fixup@l
	addis	r7,r3,__stop___ftr_fixup@ha
	addi	r7,r7,__stop___ftr_fixup@l

	/* Do the fixup */
1:	cmplw	0,r6,r7
	bgelr
	addi	r6,r6,16
	lwz	r8,-16(r6)	/* mask */
	and	r8,r8,r4
	lwz	r9,-12(r6)	/* value */
	cmplw	0,r8,r9
	beq	1b
	lwz	r8,-8(r6)	/* section begin */
	lwz	r9,-4(r6)	/* section end */
	subf.	r9,r8,r9
	beq	1b
	/* write nops over the section of code */
	/* todo: if large section, add a branch at the start of it */
	srwi	r9,r9,2
	mtctr	r9
	add	r8,r8,r3
	lis	r0,0x60000000@h	/* nop */
3:	stw	r0,0(r8)
	andi.	r10,r4,CPU_FTR_SPLIT_ID_CACHE@l
	beq	2f
	dcbst	0,r8		/* suboptimal, but simpler */
	sync
	icbi	0,r8
2:	addi	r8,r8,4
	bdnz	3b
	sync			/* additional sync needed on g4 */
	isync
	b	1b

/*
 * call_setup_cpu - call the setup_cpu function for this cpu
 * r3 = data offset, r24 = cpu number
 *
 * Setup function is called with:
 *   r3 = data offset
 *   r4 = ptr to CPU spec (relocated)
 */
_GLOBAL(call_setup_cpu)
	addis	r4,r3,cur_cpu_spec@ha
	addi	r4,r4,cur_cpu_spec@l
	lwz	r4,0(r4)
	add	r4,r4,r3
	lwz	r5,CPU_SPEC_SETUP(r4)
	cmpi	0,r5,0
	add	r5,r5,r3
	beqlr
	mtctr	r5
	bctr

#if defined(CONFIG_CPU_FREQ_PMAC) && defined(CONFIG_6xx)
Loading
Loading full blame...