mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 20:51:44 +00:00
28baebae73
Make the FRV arch use virtual interrupt disablement because accesses to the processor status register (PSR) are relatively slow and because we will soon have the need to deal with multiple interrupt controls at the same time (separate h/w and inter-core interrupts). The way this is done is to dedicate one of the four integer condition code registers (ICC2) to maintaining a virtual interrupt disablement state whilst inside the kernel. This uses the ICC2.Z flag (Zero) to indicate whether the interrupts are virtually disabled and the ICC2.C flag (Carry) to indicate whether the interrupts are physically disabled. ICC2.Z is set to indicate interrupts are virtually disabled. ICC2.C is set to indicate interrupts are physically enabled. Under normal running conditions Z==0 and C==1. Disabling interrupts with local_irq_disable() doesn't then actually physically disable interrupts - it merely sets ICC2.Z to 1. Should an interrupt then happen, the exception prologue will note ICC2.Z is set and branch out of line using one instruction (an unlikely BEQ). Here it will physically disable interrupts and clear ICC2.C. When it comes time to enable interrupts (local_irq_enable()), this simply clears the ICC2.Z flag and invokes a trap #2 if both Z and C flags are clear (the HI integer condition). This can be done with the TIHI conditional trap instruction. The trap then physically reenables interrupts and sets ICC2.C again. Upon returning the interrupt will be taken as interrupts will then be enabled. Note that whilst processing the trap, the whole exceptions system is disabled, and so an interrupt can't happen till it returns. If no pending interrupt had happened, ICC2.C would still be set, the HI condition would not be fulfilled, and no trap will happen. Saving interrupts (local_irq_save) is simply a matter of pulling the ICC2.Z flag out of the CCR register, shifting it down and masking it off. This gives a result of 0 if interrupts were enabled and 1 if they weren't. Restoring interrupts (local_irq_restore) is then a matter of taking the saved value mentioned previously and XOR'ing it against 1. If it was one, the result will be zero, and if it was zero the result will be non-zero. This result is then used to affect the ICC2.Z flag directly (it is a condition code flag after all). An XOR instruction does not affect the Carry flag, and so that bit of state is unchanged. The two flags can then be sampled to see if they're both zero using the trap (TIHI) as for the unconditional reenablement (local_irq_enable). This patch also: (1) Modifies the debugging stub (break.S) to handle single-stepping crossing into the trap #2 handler and into virtually disabled interrupts. (2) Removes superseded fixup pointers from the second instructions in the trap tables (there's no a separate fixup table for this). (3) Declares the trap #3 vector for use in .org directives in the trap table. (4) Moves irq_enter() and irq_exit() in do_IRQ() to avoid problems with virtual interrupt handling, and removes the duplicate code that has now been folded into irq_exit() (softirq and preemption handling). (5) Tells the compiler in the arch Makefile that ICC2 is now reserved. (6) Documents the in-kernel ABI, including the virtual interrupts. (7) Renames the old irq management functions to different names. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
643 lines
16 KiB
ArmAsm
643 lines
16 KiB
ArmAsm
/* head.S: kernel entry point for FR-V kernel
|
|
*
|
|
* Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved.
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
*
|
|
* 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/threads.h>
|
|
#include <linux/linkage.h>
|
|
#include <asm/ptrace.h>
|
|
#include <asm/page.h>
|
|
#include <asm/spr-regs.h>
|
|
#include <asm/mb86943a.h>
|
|
#include <asm/cache.h>
|
|
#include "head.inc"
|
|
|
|
###############################################################################
|
|
#
|
|
# void _boot(unsigned long magic, char *command_line) __attribute__((noreturn))
|
|
#
|
|
# - if magic is 0xdead1eaf, then command_line is assumed to point to the kernel
|
|
# command line string
|
|
#
|
|
###############################################################################
|
|
.section .text.head,"ax"
|
|
.balign 4
|
|
|
|
.globl _boot, __head_reference
|
|
.type _boot,@function
|
|
_boot:
|
|
__head_reference:
|
|
sethi.p %hi(LED_ADDR),gr30
|
|
setlo %lo(LED_ADDR),gr30
|
|
|
|
LEDS 0x0000
|
|
|
|
# calculate reference address for PC-relative stuff
|
|
call 0f
|
|
0: movsg lr,gr26
|
|
addi gr26,#__head_reference-0b,gr26
|
|
|
|
# invalidate and disable both of the caches and turn off the memory access checking
|
|
dcef @(gr0,gr0),1
|
|
bar
|
|
|
|
sethi.p %hi(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
|
|
setlo %lo(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
|
|
movsg hsr0,gr5
|
|
and gr4,gr5,gr5
|
|
movgs gr5,hsr0
|
|
movsg hsr0,gr5
|
|
|
|
LEDS 0x0001
|
|
|
|
icei @(gr0,gr0),1
|
|
dcei @(gr0,gr0),1
|
|
bar
|
|
|
|
# turn the instruction cache back on
|
|
sethi.p %hi(HSR0_ICE),gr4
|
|
setlo %lo(HSR0_ICE),gr4
|
|
movsg hsr0,gr5
|
|
or gr4,gr5,gr5
|
|
movgs gr5,hsr0
|
|
movsg hsr0,gr5
|
|
|
|
bar
|
|
|
|
LEDS 0x0002
|
|
|
|
# retrieve the parameters (including command line) before we overwrite them
|
|
sethi.p %hi(0xdead1eaf),gr7
|
|
setlo %lo(0xdead1eaf),gr7
|
|
subcc gr7,gr8,gr0,icc0
|
|
bne icc0,#0,__head_no_parameters
|
|
|
|
sethi.p %hi(redboot_command_line-1),gr6
|
|
setlo %lo(redboot_command_line-1),gr6
|
|
sethi.p %hi(__head_reference),gr4
|
|
setlo %lo(__head_reference),gr4
|
|
sub gr6,gr4,gr6
|
|
add.p gr6,gr26,gr6
|
|
subi gr9,#1,gr9
|
|
setlos.p #511,gr4
|
|
setlos #1,gr5
|
|
|
|
__head_copy_cmdline:
|
|
ldubu.p @(gr9,gr5),gr16
|
|
subicc gr4,#1,gr4,icc0
|
|
stbu.p gr16,@(gr6,gr5)
|
|
subicc gr16,#0,gr0,icc1
|
|
bls icc0,#0,__head_end_cmdline
|
|
bne icc1,#1,__head_copy_cmdline
|
|
__head_end_cmdline:
|
|
stbu gr0,@(gr6,gr5)
|
|
__head_no_parameters:
|
|
|
|
###############################################################################
|
|
#
|
|
# we need to relocate the SDRAM to 0x00000000 (linux) or 0xC0000000 (uClinux)
|
|
# - note that we're going to have to run entirely out of the icache whilst
|
|
# fiddling with the SDRAM controller registers
|
|
#
|
|
###############################################################################
|
|
#ifdef CONFIG_MMU
|
|
call __head_fr451_describe_sdram
|
|
|
|
#else
|
|
movsg psr,gr5
|
|
srli gr5,#28,gr5
|
|
subicc gr5,#3,gr0,icc0
|
|
beq icc0,#0,__head_fr551_sdram
|
|
|
|
call __head_fr401_describe_sdram
|
|
bra __head_do_sdram
|
|
|
|
__head_fr551_sdram:
|
|
call __head_fr555_describe_sdram
|
|
LEDS 0x000d
|
|
|
|
__head_do_sdram:
|
|
#endif
|
|
|
|
# preload the registers with invalid values in case any DBR/DARS are marked not present
|
|
sethi.p %hi(0xfe000000),gr17 ; unused SDRAM DBR value
|
|
setlo %lo(0xfe000000),gr17
|
|
or.p gr17,gr0,gr20
|
|
or gr17,gr0,gr21
|
|
or.p gr17,gr0,gr22
|
|
or gr17,gr0,gr23
|
|
|
|
# consult the SDRAM controller CS address registers
|
|
cld @(gr14,gr0 ),gr20, cc0,#1 ; DBR0 / DARS0
|
|
cld @(gr14,gr11),gr21, cc1,#1 ; DBR1 / DARS1
|
|
cld @(gr14,gr12),gr22, cc2,#1 ; DBR2 / DARS2
|
|
cld.p @(gr14,gr13),gr23, cc3,#1 ; DBR3 / DARS3
|
|
|
|
sll gr20,gr15,gr20 ; shift values up for FR551
|
|
sll gr21,gr15,gr21
|
|
sll gr22,gr15,gr22
|
|
sll gr23,gr15,gr23
|
|
|
|
LEDS 0x0003
|
|
|
|
# assume the lowest valid CS line to be the SDRAM base and get its address
|
|
subcc gr20,gr17,gr0,icc0
|
|
subcc.p gr21,gr17,gr0,icc1
|
|
subcc gr22,gr17,gr0,icc2
|
|
subcc.p gr23,gr17,gr0,icc3
|
|
ckne icc0,cc4 ; T if DBR0 != 0xfe000000
|
|
ckne icc1,cc5
|
|
ckne icc2,cc6
|
|
ckne icc3,cc7
|
|
cor gr23,gr0,gr24, cc7,#1 ; GR24 = SDRAM base
|
|
cor gr22,gr0,gr24, cc6,#1
|
|
cor gr21,gr0,gr24, cc5,#1
|
|
cor gr20,gr0,gr24, cc4,#1
|
|
|
|
# calculate the displacement required to get the SDRAM into the right place in memory
|
|
sethi.p %hi(__sdram_base),gr16
|
|
setlo %lo(__sdram_base),gr16
|
|
sub gr16,gr24,gr16 ; delta = __sdram_base - DBRx
|
|
|
|
# calculate the new values to go in the controller regs
|
|
cadd.p gr20,gr16,gr20, cc4,#1 ; DCS#0 (new) = DCS#0 (old) + delta
|
|
cadd gr21,gr16,gr21, cc5,#1
|
|
cadd.p gr22,gr16,gr22, cc6,#1
|
|
cadd gr23,gr16,gr23, cc7,#1
|
|
|
|
srl gr20,gr15,gr20 ; shift values down for FR551
|
|
srl gr21,gr15,gr21
|
|
srl gr22,gr15,gr22
|
|
srl gr23,gr15,gr23
|
|
|
|
# work out the address at which the reg updater resides and lock it into icache
|
|
# also work out the address the updater will jump to when finished
|
|
sethi.p %hi(__head_move_sdram-__head_reference),gr18
|
|
setlo %lo(__head_move_sdram-__head_reference),gr18
|
|
sethi.p %hi(__head_sdram_moved-__head_reference),gr19
|
|
setlo %lo(__head_sdram_moved-__head_reference),gr19
|
|
add.p gr18,gr26,gr18
|
|
add gr19,gr26,gr19
|
|
add.p gr19,gr16,gr19 ; moved = addr + (__sdram_base - DBRx)
|
|
add gr18,gr5,gr4 ; two cachelines probably required
|
|
|
|
icpl gr18,gr0,#1 ; load and lock the cachelines
|
|
icpl gr4,gr0,#1
|
|
LEDS 0x0004
|
|
membar
|
|
bar
|
|
jmpl @(gr18,gr0)
|
|
|
|
.balign L1_CACHE_BYTES
|
|
__head_move_sdram:
|
|
cst gr20,@(gr14,gr0 ), cc4,#1
|
|
cst gr21,@(gr14,gr11), cc5,#1
|
|
cst gr22,@(gr14,gr12), cc6,#1
|
|
cst gr23,@(gr14,gr13), cc7,#1
|
|
cld @(gr14,gr0 ),gr20, cc4,#1
|
|
cld @(gr14,gr11),gr21, cc5,#1
|
|
cld @(gr14,gr12),gr22, cc4,#1
|
|
cld @(gr14,gr13),gr23, cc7,#1
|
|
bar
|
|
membar
|
|
jmpl @(gr19,gr0)
|
|
|
|
.balign L1_CACHE_BYTES
|
|
__head_sdram_moved:
|
|
icul gr18
|
|
add gr18,gr5,gr4
|
|
icul gr4
|
|
icei @(gr0,gr0),1
|
|
dcei @(gr0,gr0),1
|
|
|
|
LEDS 0x0005
|
|
|
|
# recalculate reference address
|
|
call 0f
|
|
0: movsg lr,gr26
|
|
addi gr26,#__head_reference-0b,gr26
|
|
|
|
|
|
###############################################################################
|
|
#
|
|
# move the kernel image down to the bottom of the SDRAM
|
|
#
|
|
###############################################################################
|
|
sethi.p %hi(__kernel_image_size_no_bss+15),gr4
|
|
setlo %lo(__kernel_image_size_no_bss+15),gr4
|
|
srli.p gr4,#4,gr4 ; count
|
|
or gr26,gr26,gr16 ; source
|
|
|
|
sethi.p %hi(__sdram_base),gr17 ; destination
|
|
setlo %lo(__sdram_base),gr17
|
|
|
|
setlos #8,gr5
|
|
sub.p gr16,gr5,gr16 ; adjust src for LDDU
|
|
sub gr17,gr5,gr17 ; adjust dst for LDDU
|
|
|
|
sethi.p %hi(__head_move_kernel-__head_reference),gr18
|
|
setlo %lo(__head_move_kernel-__head_reference),gr18
|
|
sethi.p %hi(__head_kernel_moved-__head_reference+__sdram_base),gr19
|
|
setlo %lo(__head_kernel_moved-__head_reference+__sdram_base),gr19
|
|
add gr18,gr26,gr18
|
|
icpl gr18,gr0,#1
|
|
jmpl @(gr18,gr0)
|
|
|
|
.balign 32
|
|
__head_move_kernel:
|
|
lddu @(gr16,gr5),gr10
|
|
lddu @(gr16,gr5),gr12
|
|
stdu.p gr10,@(gr17,gr5)
|
|
subicc gr4,#1,gr4,icc0
|
|
stdu.p gr12,@(gr17,gr5)
|
|
bhi icc0,#0,__head_move_kernel
|
|
jmpl @(gr19,gr0)
|
|
|
|
.balign 32
|
|
__head_kernel_moved:
|
|
icul gr18
|
|
icei @(gr0,gr0),1
|
|
dcei @(gr0,gr0),1
|
|
|
|
LEDS 0x0006
|
|
|
|
# recalculate reference address
|
|
call 0f
|
|
0: movsg lr,gr26
|
|
addi gr26,#__head_reference-0b,gr26
|
|
|
|
|
|
###############################################################################
|
|
#
|
|
# rearrange the iomem map and set the protection registers
|
|
#
|
|
###############################################################################
|
|
|
|
#ifdef CONFIG_MMU
|
|
LEDS 0x3301
|
|
call __head_fr451_set_busctl
|
|
LEDS 0x3303
|
|
call __head_fr451_survey_sdram
|
|
LEDS 0x3305
|
|
call __head_fr451_set_protection
|
|
|
|
#else
|
|
movsg psr,gr5
|
|
srli gr5,#PSR_IMPLE_SHIFT,gr5
|
|
subicc gr5,#PSR_IMPLE_FR551,gr0,icc0
|
|
beq icc0,#0,__head_fr555_memmap
|
|
subicc gr5,#PSR_IMPLE_FR451,gr0,icc0
|
|
beq icc0,#0,__head_fr451_memmap
|
|
|
|
LEDS 0x3101
|
|
call __head_fr401_set_busctl
|
|
LEDS 0x3103
|
|
call __head_fr401_survey_sdram
|
|
LEDS 0x3105
|
|
call __head_fr401_set_protection
|
|
bra __head_done_memmap
|
|
|
|
__head_fr451_memmap:
|
|
LEDS 0x3301
|
|
call __head_fr401_set_busctl
|
|
LEDS 0x3303
|
|
call __head_fr401_survey_sdram
|
|
LEDS 0x3305
|
|
call __head_fr451_set_protection
|
|
bra __head_done_memmap
|
|
|
|
__head_fr555_memmap:
|
|
LEDS 0x3501
|
|
call __head_fr555_set_busctl
|
|
LEDS 0x3503
|
|
call __head_fr555_survey_sdram
|
|
LEDS 0x3505
|
|
call __head_fr555_set_protection
|
|
|
|
__head_done_memmap:
|
|
#endif
|
|
LEDS 0x0007
|
|
|
|
###############################################################################
|
|
#
|
|
# turn the data cache and MMU on
|
|
# - for the FR451 this'll mean that the window through which the kernel is
|
|
# viewed will change
|
|
#
|
|
###############################################################################
|
|
|
|
#ifdef CONFIG_MMU
|
|
#define MMUMODE HSR0_EIMMU|HSR0_EDMMU|HSR0_EXMMU|HSR0_EDAT|HSR0_XEDAT
|
|
#else
|
|
#define MMUMODE HSR0_EIMMU|HSR0_EDMMU
|
|
#endif
|
|
|
|
movsg hsr0,gr5
|
|
|
|
sethi.p %hi(MMUMODE),gr4
|
|
setlo %lo(MMUMODE),gr4
|
|
or gr4,gr5,gr5
|
|
|
|
#if defined(CONFIG_FRV_DEFL_CACHE_WTHRU)
|
|
sethi.p %hi(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
|
|
setlo %lo(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
|
|
#elif defined(CONFIG_FRV_DEFL_CACHE_WBACK)
|
|
sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
|
|
setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
|
|
#elif defined(CONFIG_FRV_DEFL_CACHE_WBEHIND)
|
|
sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
|
|
setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
|
|
|
|
movsg psr,gr6
|
|
srli gr6,#24,gr6
|
|
cmpi gr6,#0x50,icc0 // FR451
|
|
beq icc0,#0,0f
|
|
cmpi gr6,#0x40,icc0 // FR405
|
|
bne icc0,#0,1f
|
|
0:
|
|
# turn off write-allocate
|
|
sethi.p %hi(HSR0_NWA),gr6
|
|
setlo %lo(HSR0_NWA),gr6
|
|
or gr4,gr6,gr4
|
|
1:
|
|
|
|
#else
|
|
#error No default cache configuration set
|
|
#endif
|
|
|
|
or gr4,gr5,gr5
|
|
movgs gr5,hsr0
|
|
bar
|
|
|
|
LEDS 0x0008
|
|
|
|
sethi.p %hi(__head_mmu_enabled),gr19
|
|
setlo %lo(__head_mmu_enabled),gr19
|
|
jmpl @(gr19,gr0)
|
|
|
|
__head_mmu_enabled:
|
|
icei @(gr0,gr0),#1
|
|
dcei @(gr0,gr0),#1
|
|
|
|
LEDS 0x0009
|
|
|
|
#ifdef CONFIG_MMU
|
|
call __head_fr451_finalise_protection
|
|
#endif
|
|
|
|
LEDS 0x000a
|
|
|
|
###############################################################################
|
|
#
|
|
# set up the runtime environment
|
|
#
|
|
###############################################################################
|
|
|
|
# clear the BSS area
|
|
sethi.p %hi(__bss_start),gr4
|
|
setlo %lo(__bss_start),gr4
|
|
sethi.p %hi(_end),gr5
|
|
setlo %lo(_end),gr5
|
|
or.p gr0,gr0,gr18
|
|
or gr0,gr0,gr19
|
|
|
|
0:
|
|
stdi gr18,@(gr4,#0)
|
|
stdi gr18,@(gr4,#8)
|
|
stdi gr18,@(gr4,#16)
|
|
stdi.p gr18,@(gr4,#24)
|
|
addi gr4,#24,gr4
|
|
subcc gr5,gr4,gr0,icc0
|
|
bhi icc0,#2,0b
|
|
|
|
LEDS 0x000b
|
|
|
|
# save the SDRAM details
|
|
sethi.p %hi(__sdram_old_base),gr4
|
|
setlo %lo(__sdram_old_base),gr4
|
|
st gr24,@(gr4,gr0)
|
|
|
|
sethi.p %hi(__sdram_base),gr5
|
|
setlo %lo(__sdram_base),gr5
|
|
sethi.p %hi(memory_start),gr4
|
|
setlo %lo(memory_start),gr4
|
|
st gr5,@(gr4,gr0)
|
|
|
|
add gr25,gr5,gr25
|
|
sethi.p %hi(memory_end),gr4
|
|
setlo %lo(memory_end),gr4
|
|
st gr25,@(gr4,gr0)
|
|
|
|
# point the TBR at the kernel trap table
|
|
sethi.p %hi(__entry_kerneltrap_table),gr4
|
|
setlo %lo(__entry_kerneltrap_table),gr4
|
|
movgs gr4,tbr
|
|
|
|
# set up the exception frame for init
|
|
sethi.p %hi(__kernel_frame0_ptr),gr28
|
|
setlo %lo(__kernel_frame0_ptr),gr28
|
|
sethi.p %hi(_gp),gr16
|
|
setlo %lo(_gp),gr16
|
|
sethi.p %hi(__entry_usertrap_table),gr4
|
|
setlo %lo(__entry_usertrap_table),gr4
|
|
|
|
lddi @(gr28,#0),gr28 ; load __frame & current
|
|
ldi.p @(gr29,#4),gr15 ; set current_thread
|
|
|
|
or gr0,gr0,fp
|
|
or gr28,gr0,sp
|
|
|
|
sti.p gr4,@(gr28,REG_TBR)
|
|
setlos #ISR_EDE|ISR_DTT_DIVBYZERO|ISR_EMAM_EXCEPTION,gr5
|
|
movgs gr5,isr
|
|
|
|
# turn on and off various CPU services
|
|
movsg psr,gr22
|
|
sethi.p %hi(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
|
|
setlo %lo(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
|
|
or gr22,gr4,gr22
|
|
movgs gr22,psr
|
|
|
|
andi gr22,#~(PSR_PIL|PSR_PS|PSR_S),gr22
|
|
ori gr22,#PSR_ET,gr22
|
|
sti gr22,@(gr28,REG_PSR)
|
|
|
|
|
|
###############################################################################
|
|
#
|
|
# set up the registers and jump into the kernel
|
|
#
|
|
###############################################################################
|
|
|
|
LEDS 0x000c
|
|
|
|
# initialise the processor and the peripherals
|
|
#call SYMBOL_NAME(processor_init)
|
|
#call SYMBOL_NAME(unit_init)
|
|
#LEDS 0x0aff
|
|
|
|
sethi.p #0xe5e5,gr3
|
|
setlo #0xe5e5,gr3
|
|
or.p gr3,gr0,gr4
|
|
or gr3,gr0,gr5
|
|
or.p gr3,gr0,gr6
|
|
or gr3,gr0,gr7
|
|
or.p gr3,gr0,gr8
|
|
or gr3,gr0,gr9
|
|
or.p gr3,gr0,gr10
|
|
or gr3,gr0,gr11
|
|
or.p gr3,gr0,gr12
|
|
or gr3,gr0,gr13
|
|
or.p gr3,gr0,gr14
|
|
or gr3,gr0,gr17
|
|
or.p gr3,gr0,gr18
|
|
or gr3,gr0,gr19
|
|
or.p gr3,gr0,gr20
|
|
or gr3,gr0,gr21
|
|
or.p gr3,gr0,gr23
|
|
or gr3,gr0,gr24
|
|
or.p gr3,gr0,gr25
|
|
or gr3,gr0,gr26
|
|
or.p gr3,gr0,gr27
|
|
# or gr3,gr0,gr30
|
|
or gr3,gr0,gr31
|
|
movgs gr0,lr
|
|
movgs gr0,lcr
|
|
movgs gr0,ccr
|
|
movgs gr0,cccr
|
|
|
|
# initialise the virtual interrupt handling
|
|
subcc gr0,gr0,gr0,icc2 /* set Z, clear C */
|
|
|
|
#ifdef CONFIG_MMU
|
|
movgs gr3,scr2
|
|
movgs gr3,scr3
|
|
#endif
|
|
|
|
LEDS 0x0fff
|
|
|
|
# invoke the debugging stub if present
|
|
# - arch/frv/kernel/debug-stub.c will shift control directly to init/main.c
|
|
# (it will not return here)
|
|
break
|
|
.globl __debug_stub_init_break
|
|
__debug_stub_init_break:
|
|
|
|
# however, if you need to use an ICE, and don't care about using any userspace
|
|
# debugging tools (such as the ptrace syscall), you can just step over the break
|
|
# above and get to the kernel this way
|
|
# look at arch/frv/kernel/debug-stub.c: debug_stub_init() to see what you've missed
|
|
call start_kernel
|
|
|
|
.globl __head_end
|
|
__head_end:
|
|
.size _boot, .-_boot
|
|
|
|
# provide a point for GDB to place a break
|
|
.section .text.start,"ax"
|
|
.globl _start
|
|
.balign 4
|
|
_start:
|
|
call _boot
|
|
|
|
.previous
|
|
###############################################################################
|
|
#
|
|
# split a tile off of the region defined by GR8-GR9
|
|
#
|
|
# ENTRY: EXIT:
|
|
# GR4 - IAMPR value representing tile
|
|
# GR5 - DAMPR value representing tile
|
|
# GR6 - IAMLR value representing tile
|
|
# GR7 - DAMLR value representing tile
|
|
# GR8 region base pointer [saved]
|
|
# GR9 region top pointer updated to exclude new tile
|
|
# GR11 xAMLR mask [saved]
|
|
# GR25 SDRAM size [saved]
|
|
# GR30 LED address [saved]
|
|
#
|
|
# - GR8 and GR9 should be rounded up/down to the nearest megabyte before calling
|
|
#
|
|
###############################################################################
|
|
.globl __head_split_region
|
|
.type __head_split_region,@function
|
|
__head_split_region:
|
|
subcc.p gr9,gr8,gr4,icc0
|
|
setlos #31,gr5
|
|
scan.p gr4,gr0,gr6
|
|
beq icc0,#0,__head_region_empty
|
|
sub.p gr5,gr6,gr6 ; bit number of highest set bit (1MB=>20)
|
|
setlos #1,gr4
|
|
sll.p gr4,gr6,gr4 ; size of region (1 << bitno)
|
|
subi gr6,#17,gr6 ; 1MB => 0x03
|
|
slli.p gr6,#4,gr6 ; 1MB => 0x30
|
|
sub gr9,gr4,gr9 ; move uncovered top down
|
|
|
|
or gr9,gr6,gr4
|
|
ori gr4,#xAMPRx_S_USER|xAMPRx_C_CACHED|xAMPRx_V,gr4
|
|
or.p gr4,gr0,gr5
|
|
|
|
and gr4,gr11,gr6
|
|
and.p gr5,gr11,gr7
|
|
bralr
|
|
|
|
__head_region_empty:
|
|
or.p gr0,gr0,gr4
|
|
or gr0,gr0,gr5
|
|
or.p gr0,gr0,gr6
|
|
or gr0,gr0,gr7
|
|
bralr
|
|
.size __head_split_region, .-__head_split_region
|
|
|
|
###############################################################################
|
|
#
|
|
# write the 32-bit hex number in GR8 to ttyS0
|
|
#
|
|
###############################################################################
|
|
#if 0
|
|
.globl __head_write_to_ttyS0
|
|
.type __head_write_to_ttyS0,@function
|
|
__head_write_to_ttyS0:
|
|
sethi.p %hi(0xfeff9c00),gr31
|
|
setlo %lo(0xfeff9c00),gr31
|
|
setlos #8,gr20
|
|
|
|
0: ldubi @(gr31,#5*8),gr21
|
|
andi gr21,#0x60,gr21
|
|
subicc gr21,#0x60,gr21,icc0
|
|
bne icc0,#0,0b
|
|
|
|
1: srli gr8,#28,gr21
|
|
slli gr8,#4,gr8
|
|
|
|
addi gr21,#'0',gr21
|
|
subicc gr21,#'9',gr0,icc0
|
|
bls icc0,#2,2f
|
|
addi gr21,#'A'-'0'-10,gr21
|
|
2:
|
|
stbi gr21,@(gr31,#0*8)
|
|
subicc gr20,#1,gr20,icc0
|
|
bhi icc0,#2,1b
|
|
|
|
setlos #'\r',gr21
|
|
stbi gr21,@(gr31,#0*8)
|
|
|
|
setlos #'\n',gr21
|
|
stbi gr21,@(gr31,#0*8)
|
|
|
|
3: ldubi @(gr31,#5*8),gr21
|
|
andi gr21,#0x60,gr21
|
|
subicc gr21,#0x60,gr21,icc0
|
|
bne icc0,#0,3b
|
|
bralr
|
|
|
|
.size __head_write_to_ttyS0, .-__head_write_to_ttyS0
|
|
#endif
|