diff options
Diffstat (limited to 'arch/arm/kernel/head.S')
-rw-r--r-- | arch/arm/kernel/head.S | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 03a588b6e15c..1db8ead2e331 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -98,6 +98,9 @@ ENTRY(stext) | |||
98 | #ifdef CONFIG_SMP_ON_UP | 98 | #ifdef CONFIG_SMP_ON_UP |
99 | bl __fixup_smp | 99 | bl __fixup_smp |
100 | #endif | 100 | #endif |
101 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | ||
102 | bl __fixup_pv_table | ||
103 | #endif | ||
101 | bl __create_page_tables | 104 | bl __create_page_tables |
102 | 105 | ||
103 | /* | 106 | /* |
@@ -438,4 +441,69 @@ smp_on_up: | |||
438 | 441 | ||
439 | #endif | 442 | #endif |
440 | 443 | ||
444 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | ||
445 | |||
446 | /* __fixup_pv_table - patch the stub instructions with the delta between | ||
447 | * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and | ||
448 | * can be expressed by an immediate shifter operand. The stub instruction | ||
449 | * has a form of '(add|sub) rd, rn, #imm'. | ||
450 | */ | ||
451 | __HEAD | ||
452 | __fixup_pv_table: | ||
453 | adr r0, 1f | ||
454 | ldmia r0, {r3-r5, r7} | ||
455 | sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET | ||
456 | add r4, r4, r3 @ adjust table start address | ||
457 | add r5, r5, r3 @ adjust table end address | ||
458 | str r8, [r7, r3]! @ save computed PHYS_OFFSET to __pv_phys_offset | ||
459 | mov r6, r3, lsr #24 @ constant for add/sub instructions | ||
460 | teq r3, r6, lsl #24 @ must be 16MiB aligned | ||
461 | bne __error | ||
462 | str r6, [r7, #4] @ save to __pv_offset | ||
463 | b __fixup_a_pv_table | ||
464 | ENDPROC(__fixup_pv_table) | ||
465 | |||
466 | .align | ||
467 | 1: .long . | ||
468 | .long __pv_table_begin | ||
469 | .long __pv_table_end | ||
470 | 2: .long __pv_phys_offset | ||
471 | |||
472 | .text | ||
473 | __fixup_a_pv_table: | ||
474 | b 3f | ||
475 | 2: ldr ip, [r7, r3] | ||
476 | bic ip, ip, #0x000000ff | ||
477 | orr ip, ip, r6 | ||
478 | str ip, [r7, r3] | ||
479 | 3: cmp r4, r5 | ||
480 | ldrcc r7, [r4], #4 @ use branch for delay slot | ||
481 | bcc 2b | ||
482 | mov pc, lr | ||
483 | ENDPROC(__fixup_a_pv_table) | ||
484 | |||
485 | ENTRY(fixup_pv_table) | ||
486 | stmfd sp!, {r4 - r7, lr} | ||
487 | ldr r2, 2f @ get address of __pv_phys_offset | ||
488 | mov r3, #0 @ no offset | ||
489 | mov r4, r0 @ r0 = table start | ||
490 | add r5, r0, r1 @ r1 = table size | ||
491 | ldr r6, [r2, #4] @ get __pv_offset | ||
492 | bl __fixup_a_pv_table | ||
493 | ldmfd sp!, {r4 - r7, pc} | ||
494 | ENDPROC(fixup_pv_table) | ||
495 | |||
496 | .align | ||
497 | 2: .long __pv_phys_offset | ||
498 | |||
499 | .data | ||
500 | .globl __pv_phys_offset | ||
501 | .type __pv_phys_offset, %object | ||
502 | __pv_phys_offset: | ||
503 | .long 0 | ||
504 | .size __pv_phys_offset, . - __pv_phys_offset | ||
505 | __pv_offset: | ||
506 | .long 0 | ||
507 | #endif | ||
508 | |||
441 | #include "head-common.S" | 509 | #include "head-common.S" |