linux/arch/arm/kernel/head-common.S
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/kernel/head-common.S
   3 *
   4 *  Copyright (C) 1994-2002 Russell King
   5 *  Copyright (c) 2003 ARM Limited
   6 *  All Rights Reserved
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 */
  13#include <asm/assembler.h>
  14
  15#define ATAG_CORE 0x54410001
  16#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
  17#define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2)
  18
  19#ifdef CONFIG_CPU_BIG_ENDIAN
  20#define OF_DT_MAGIC 0xd00dfeed
  21#else
  22#define OF_DT_MAGIC 0xedfe0dd0 /* 0xd00dfeed in big-endian */
  23#endif
  24
  25/*
  26 * Exception handling.  Something went wrong and we can't proceed.  We
  27 * ought to tell the user, but since we don't have any guarantee that
  28 * we're even running on the right architecture, we do virtually nothing.
  29 *
  30 * If CONFIG_DEBUG_LL is set we try to print out something about the error
  31 * and hope for the best (useful if bootloader fails to pass a proper
  32 * machine ID for example).
  33 */
  34        __HEAD
  35
  36/* Determine validity of the r2 atags pointer.  The heuristic requires
  37 * that the pointer be aligned, in the first 16k of physical RAM and
  38 * that the ATAG_CORE marker is first and present.  If CONFIG_OF_FLATTREE
  39 * is selected, then it will also accept a dtb pointer.  Future revisions
  40 * of this function may be more lenient with the physical address and
  41 * may also be able to move the ATAGS block if necessary.
  42 *
  43 * Returns:
  44 *  r2 either valid atags pointer, valid dtb pointer, or zero
  45 *  r5, r6 corrupted
  46 */
  47__vet_atags:
  48        tst     r2, #0x3                        @ aligned?
  49        bne     1f
  50
  51        ldr     r5, [r2, #0]
  52#ifdef CONFIG_OF_FLATTREE
  53        ldr     r6, =OF_DT_MAGIC                @ is it a DTB?
  54        cmp     r5, r6
  55        beq     2f
  56#endif
  57        cmp     r5, #ATAG_CORE_SIZE             @ is first tag ATAG_CORE?
  58        cmpne   r5, #ATAG_CORE_SIZE_EMPTY
  59        bne     1f
  60        ldr     r5, [r2, #4]
  61        ldr     r6, =ATAG_CORE
  62        cmp     r5, r6
  63        bne     1f
  64
  652:      ret     lr                              @ atag/dtb pointer is ok
  66
  671:      mov     r2, #0
  68        ret     lr
  69ENDPROC(__vet_atags)
  70
  71/*
  72 * The following fragment of code is executed with the MMU on in MMU mode,
  73 * and uses absolute addresses; this is not position independent.
  74 *
  75 *  r0  = cp#15 control register
  76 *  r1  = machine ID
  77 *  r2  = atags/dtb pointer
  78 *  r9  = processor ID
  79 */
  80        __INIT
  81__mmap_switched:
  82        adr     r3, __mmap_switched_data
  83
  84        ldmia   r3!, {r4, r5, r6, r7}
  85        cmp     r4, r5                          @ Copy data segment if needed
  861:      cmpne   r5, r6
  87        ldrne   fp, [r4], #4
  88        strne   fp, [r5], #4
  89        bne     1b
  90
  91        mov     fp, #0                          @ Clear BSS (and zero fp)
  921:      cmp     r6, r7
  93        strcc   fp, [r6],#4
  94        bcc     1b
  95
  96 ARM(   ldmia   r3, {r4, r5, r6, r7, sp})
  97 THUMB( ldmia   r3, {r4, r5, r6, r7}    )
  98 THUMB( ldr     sp, [r3, #16]           )
  99        str     r9, [r4]                        @ Save processor ID
 100        str     r1, [r5]                        @ Save machine type
 101        str     r2, [r6]                        @ Save atags pointer
 102        cmp     r7, #0
 103        strne   r0, [r7]                        @ Save control register values
 104        b       start_kernel
 105ENDPROC(__mmap_switched)
 106
 107        .align  2
 108        .type   __mmap_switched_data, %object
 109__mmap_switched_data:
 110        .long   __data_loc                      @ r4
 111        .long   _sdata                          @ r5
 112        .long   __bss_start                     @ r6
 113        .long   _end                            @ r7
 114        .long   processor_id                    @ r4
 115        .long   __machine_arch_type             @ r5
 116        .long   __atags_pointer                 @ r6
 117#ifdef CONFIG_CPU_CP15
 118        .long   cr_alignment                    @ r7
 119#else
 120        .long   0                               @ r7
 121#endif
 122        .long   init_thread_union + THREAD_START_SP @ sp
 123        .size   __mmap_switched_data, . - __mmap_switched_data
 124
 125/*
 126 * This provides a C-API version of __lookup_processor_type
 127 */
 128ENTRY(lookup_processor_type)
 129        stmfd   sp!, {r4 - r6, r9, lr}
 130        mov     r9, r0
 131        bl      __lookup_processor_type
 132        mov     r0, r5
 133        ldmfd   sp!, {r4 - r6, r9, pc}
 134ENDPROC(lookup_processor_type)
 135
 136        __FINIT
 137        .text
 138
 139/*
 140 * Read processor ID register (CP#15, CR0), and look up in the linker-built
 141 * supported processor list.  Note that we can't use the absolute addresses
 142 * for the __proc_info lists since we aren't running with the MMU on
 143 * (and therefore, we are not in the correct address space).  We have to
 144 * calculate the offset.
 145 *
 146 *      r9 = cpuid
 147 * Returns:
 148 *      r3, r4, r6 corrupted
 149 *      r5 = proc_info pointer in physical address space
 150 *      r9 = cpuid (preserved)
 151 */
 152__lookup_processor_type:
 153        adr     r3, __lookup_processor_type_data
 154        ldmia   r3, {r4 - r6}
 155        sub     r3, r3, r4                      @ get offset between virt&phys
 156        add     r5, r5, r3                      @ convert virt addresses to
 157        add     r6, r6, r3                      @ physical address space
 1581:      ldmia   r5, {r3, r4}                    @ value, mask
 159        and     r4, r4, r9                      @ mask wanted bits
 160        teq     r3, r4
 161        beq     2f
 162        add     r5, r5, #PROC_INFO_SZ           @ sizeof(proc_info_list)
 163        cmp     r5, r6
 164        blo     1b
 165        mov     r5, #0                          @ unknown processor
 1662:      ret     lr
 167ENDPROC(__lookup_processor_type)
 168
 169/*
 170 * Look in <asm/procinfo.h> for information about the __proc_info structure.
 171 */
 172        .align  2
 173        .type   __lookup_processor_type_data, %object
 174__lookup_processor_type_data:
 175        .long   .
 176        .long   __proc_info_begin
 177        .long   __proc_info_end
 178        .size   __lookup_processor_type_data, . - __lookup_processor_type_data
 179
 180__error_lpae:
 181#ifdef CONFIG_DEBUG_LL
 182        adr     r0, str_lpae
 183        bl      printascii
 184        b       __error
 185str_lpae: .asciz "\nError: Kernel with LPAE support, but CPU does not support LPAE.\n"
 186#else
 187        b       __error
 188#endif
 189        .align
 190ENDPROC(__error_lpae)
 191
 192__error_p:
 193#ifdef CONFIG_DEBUG_LL
 194        adr     r0, str_p1
 195        bl      printascii
 196        mov     r0, r9
 197        bl      printhex8
 198        adr     r0, str_p2
 199        bl      printascii
 200        b       __error
 201str_p1: .asciz  "\nError: unrecognized/unsupported processor variant (0x"
 202str_p2: .asciz  ").\n"
 203        .align
 204#endif
 205ENDPROC(__error_p)
 206
 207__error:
 208#ifdef CONFIG_ARCH_RPC
 209/*
 210 * Turn the screen red on a error - RiscPC only.
 211 */
 212        mov     r0, #0x02000000
 213        mov     r3, #0x11
 214        orr     r3, r3, r3, lsl #8
 215        orr     r3, r3, r3, lsl #16
 216        str     r3, [r0], #4
 217        str     r3, [r0], #4
 218        str     r3, [r0], #4
 219        str     r3, [r0], #4
 220#endif
 2211:      mov     r0, r0
 222        b       1b
 223ENDPROC(__error)
 224