diff options
Diffstat (limited to 'arch/arm/kernel/head-common.S')
-rw-r--r-- | arch/arm/kernel/head-common.S | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S new file mode 100644 index 00000000000..a52da0ddb43 --- /dev/null +++ b/arch/arm/kernel/head-common.S @@ -0,0 +1,217 @@ +/* + * linux/arch/arm/kernel/head-common.S + * + * Copyright (C) 1994-2002 Russell King + * Copyright (c) 2003 ARM Limited + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + + .type __switch_data, %object +__switch_data: + .long __mmap_switched + .long __data_loc @ r4 + .long __data_start @ r5 + .long __bss_start @ r6 + .long _end @ r7 + .long processor_id @ r4 + .long __machine_arch_type @ r5 + .long cr_alignment @ r6 + .long init_thread_union + THREAD_START_SP @ sp + +/* + * The following fragment of code is executed with the MMU on in MMU mode, + * and uses absolute addresses; this is not position independent. + * + * r0 = cp#15 control register + * r1 = machine ID + * r9 = processor ID + */ + .type __mmap_switched, %function +__mmap_switched: + adr r3, __switch_data + 4 + + ldmia r3!, {r4, r5, r6, r7} + cmp r4, r5 @ Copy data segment if needed +1: cmpne r5, r6 + ldrne fp, [r4], #4 + strne fp, [r5], #4 + bne 1b + + mov fp, #0 @ Clear BSS (and zero fp) +1: cmp r6, r7 + strcc fp, [r6],#4 + bcc 1b + + ldmia r3, {r4, r5, r6, sp} + str r9, [r4] @ Save processor ID + str r1, [r5] @ Save machine type + bic r4, r0, #CR_A @ Clear 'A' bit + stmia r6, {r0, r4} @ Save control register values + b start_kernel + +/* + * Exception handling. Something went wrong and we can't proceed. We + * ought to tell the user, but since we don't have any guarantee that + * we're even running on the right architecture, we do virtually nothing. + * + * If CONFIG_DEBUG_LL is set we try to print out something about the error + * and hope for the best (useful if bootloader fails to pass a proper + * machine ID for example). + */ + + .type __error_p, %function +__error_p: +#ifdef CONFIG_DEBUG_LL + adr r0, str_p1 + bl printascii + b __error +str_p1: .asciz "\nError: unrecognized/unsupported processor variant.\n" + .align +#endif + + .type __error_a, %function +__error_a: +#ifdef CONFIG_DEBUG_LL + mov r4, r1 @ preserve machine ID + adr r0, str_a1 + bl printascii + mov r0, r4 + bl printhex8 + adr r0, str_a2 + bl printascii + adr r3, 3f + ldmia r3, {r4, r5, r6} @ get machine desc list + sub r4, r3, r4 @ get offset between virt&phys + add r5, r5, r4 @ convert virt addresses to + add r6, r6, r4 @ physical address space +1: ldr r0, [r5, #MACHINFO_TYPE] @ get machine type + bl printhex8 + mov r0, #'\t' + bl printch + ldr r0, [r5, #MACHINFO_NAME] @ get machine name + add r0, r0, r4 + bl printascii + mov r0, #'\n' + bl printch + add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc + cmp r5, r6 + blo 1b + adr r0, str_a3 + bl printascii + b __error +str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x" +str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n" +str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n" + .align +#endif + + .type __error, %function +__error: +#ifdef CONFIG_ARCH_RPC +/* + * Turn the screen red on a error - RiscPC only. + */ + mov r0, #0x02000000 + mov r3, #0x11 + orr r3, r3, r3, lsl #8 + orr r3, r3, r3, lsl #16 + str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 +#endif +1: mov r0, r0 + b 1b + + +/* + * Read processor ID register (CP#15, CR0), and look up in the linker-built + * supported processor list. Note that we can't use the absolute addresses + * for the __proc_info lists since we aren't running with the MMU on + * (and therefore, we are not in the correct address space). We have to + * calculate the offset. + * + * r9 = cpuid + * Returns: + * r3, r4, r6 corrupted + * r5 = proc_info pointer in physical address space + * r9 = cpuid (preserved) + */ + .type __lookup_processor_type, %function +__lookup_processor_type: + adr r3, 3f + ldmda r3, {r5 - r7} + sub r3, r3, r7 @ get offset between virt&phys + add r5, r5, r3 @ convert virt addresses to + add r6, r6, r3 @ physical address space +1: ldmia r5, {r3, r4} @ value, mask + and r4, r4, r9 @ mask wanted bits + teq r3, r4 + beq 2f + add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list) + cmp r5, r6 + blo 1b + mov r5, #0 @ unknown processor +2: mov pc, lr + +/* + * This provides a C-API version of the above function. + */ +ENTRY(lookup_processor_type) + stmfd sp!, {r4 - r7, r9, lr} + mov r9, r0 + bl __lookup_processor_type + mov r0, r5 + ldmfd sp!, {r4 - r7, r9, pc} + +/* + * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for + * more information about the __proc_info and __arch_info structures. + */ + .long __proc_info_begin + .long __proc_info_end +3: .long . + .long __arch_info_begin + .long __arch_info_end + +/* + * Lookup machine architecture in the linker-build list of architectures. + * Note that we can't use the absolute addresses for the __arch_info + * lists since we aren't running with the MMU on (and therefore, we are + * not in the correct address space). We have to calculate the offset. + * + * r1 = machine architecture number + * Returns: + * r3, r4, r6 corrupted + * r5 = mach_info pointer in physical address space + */ + .type __lookup_machine_type, %function +__lookup_machine_type: + adr r3, 3b + ldmia r3, {r4, r5, r6} + sub r3, r3, r4 @ get offset between virt&phys + add r5, r5, r3 @ convert virt addresses to + add r6, r6, r3 @ physical address space +1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type + teq r3, r1 @ matches loader number? + beq 2f @ found + add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc + cmp r5, r6 + blo 1b + mov r5, #0 @ unknown machine +2: mov pc, lr + +/* + * This provides a C-API version of the above function. + */ +ENTRY(lookup_machine_type) + stmfd sp!, {r4 - r6, lr} + mov r1, r0 + bl __lookup_machine_type + mov r0, r5 + ldmfd sp!, {r4 - r6, pc} |