diff options
Diffstat (limited to 'arch/arm64/kernel/head.S')
-rw-r--r-- | arch/arm64/kernel/head.S | 121 |
1 files changed, 76 insertions, 45 deletions
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index a2c1195abb7f..144f10567f82 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/linkage.h> | 23 | #include <linux/linkage.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/irqchip/arm-gic-v3.h> | ||
25 | 26 | ||
26 | #include <asm/assembler.h> | 27 | #include <asm/assembler.h> |
27 | #include <asm/ptrace.h> | 28 | #include <asm/ptrace.h> |
@@ -35,37 +36,31 @@ | |||
35 | #include <asm/page.h> | 36 | #include <asm/page.h> |
36 | #include <asm/virt.h> | 37 | #include <asm/virt.h> |
37 | 38 | ||
38 | /* | ||
39 | * swapper_pg_dir is the virtual address of the initial page table. We place | ||
40 | * the page tables 3 * PAGE_SIZE below KERNEL_RAM_VADDR. The idmap_pg_dir has | ||
41 | * 2 pages and is placed below swapper_pg_dir. | ||
42 | */ | ||
43 | #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) | 39 | #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) |
44 | 40 | ||
45 | #if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000 | 41 | #if (TEXT_OFFSET & 0xf) != 0 |
46 | #error KERNEL_RAM_VADDR must start at 0xXXX80000 | 42 | #error TEXT_OFFSET must be at least 16B aligned |
43 | #elif (PAGE_OFFSET & 0xfffff) != 0 | ||
44 | #error PAGE_OFFSET must be at least 2MB aligned | ||
45 | #elif TEXT_OFFSET > 0xfffff | ||
46 | #error TEXT_OFFSET must be less than 2MB | ||
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | #define SWAPPER_DIR_SIZE (3 * PAGE_SIZE) | 49 | .macro pgtbl, ttb0, ttb1, virt_to_phys |
50 | #define IDMAP_DIR_SIZE (2 * PAGE_SIZE) | 50 | ldr \ttb1, =swapper_pg_dir |
51 | 51 | ldr \ttb0, =idmap_pg_dir | |
52 | .globl swapper_pg_dir | 52 | add \ttb1, \ttb1, \virt_to_phys |
53 | .equ swapper_pg_dir, KERNEL_RAM_VADDR - SWAPPER_DIR_SIZE | 53 | add \ttb0, \ttb0, \virt_to_phys |
54 | |||
55 | .globl idmap_pg_dir | ||
56 | .equ idmap_pg_dir, swapper_pg_dir - IDMAP_DIR_SIZE | ||
57 | |||
58 | .macro pgtbl, ttb0, ttb1, phys | ||
59 | add \ttb1, \phys, #TEXT_OFFSET - SWAPPER_DIR_SIZE | ||
60 | sub \ttb0, \ttb1, #IDMAP_DIR_SIZE | ||
61 | .endm | 54 | .endm |
62 | 55 | ||
63 | #ifdef CONFIG_ARM64_64K_PAGES | 56 | #ifdef CONFIG_ARM64_64K_PAGES |
64 | #define BLOCK_SHIFT PAGE_SHIFT | 57 | #define BLOCK_SHIFT PAGE_SHIFT |
65 | #define BLOCK_SIZE PAGE_SIZE | 58 | #define BLOCK_SIZE PAGE_SIZE |
59 | #define TABLE_SHIFT PMD_SHIFT | ||
66 | #else | 60 | #else |
67 | #define BLOCK_SHIFT SECTION_SHIFT | 61 | #define BLOCK_SHIFT SECTION_SHIFT |
68 | #define BLOCK_SIZE SECTION_SIZE | 62 | #define BLOCK_SIZE SECTION_SIZE |
63 | #define TABLE_SHIFT PUD_SHIFT | ||
69 | #endif | 64 | #endif |
70 | 65 | ||
71 | #define KERNEL_START KERNEL_RAM_VADDR | 66 | #define KERNEL_START KERNEL_RAM_VADDR |
@@ -120,9 +115,9 @@ efi_head: | |||
120 | b stext // branch to kernel start, magic | 115 | b stext // branch to kernel start, magic |
121 | .long 0 // reserved | 116 | .long 0 // reserved |
122 | #endif | 117 | #endif |
123 | .quad TEXT_OFFSET // Image load offset from start of RAM | 118 | .quad _kernel_offset_le // Image load offset from start of RAM, little-endian |
124 | .quad 0 // reserved | 119 | .quad _kernel_size_le // Effective size of kernel image, little-endian |
125 | .quad 0 // reserved | 120 | .quad _kernel_flags_le // Informative flags, little-endian |
126 | .quad 0 // reserved | 121 | .quad 0 // reserved |
127 | .quad 0 // reserved | 122 | .quad 0 // reserved |
128 | .quad 0 // reserved | 123 | .quad 0 // reserved |
@@ -295,6 +290,23 @@ CPU_LE( bic x0, x0, #(3 << 24) ) // Clear the EE and E0E bits for EL1 | |||
295 | msr cnthctl_el2, x0 | 290 | msr cnthctl_el2, x0 |
296 | msr cntvoff_el2, xzr // Clear virtual offset | 291 | msr cntvoff_el2, xzr // Clear virtual offset |
297 | 292 | ||
293 | #ifdef CONFIG_ARM_GIC_V3 | ||
294 | /* GICv3 system register access */ | ||
295 | mrs x0, id_aa64pfr0_el1 | ||
296 | ubfx x0, x0, #24, #4 | ||
297 | cmp x0, #1 | ||
298 | b.ne 3f | ||
299 | |||
300 | mrs_s x0, ICC_SRE_EL2 | ||
301 | orr x0, x0, #ICC_SRE_EL2_SRE // Set ICC_SRE_EL2.SRE==1 | ||
302 | orr x0, x0, #ICC_SRE_EL2_ENABLE // Set ICC_SRE_EL2.Enable==1 | ||
303 | msr_s ICC_SRE_EL2, x0 | ||
304 | isb // Make sure SRE is now set | ||
305 | msr_s ICH_HCR_EL2, xzr // Reset ICC_HCR_EL2 to defaults | ||
306 | |||
307 | 3: | ||
308 | #endif | ||
309 | |||
298 | /* Populate ID registers. */ | 310 | /* Populate ID registers. */ |
299 | mrs x0, midr_el1 | 311 | mrs x0, midr_el1 |
300 | mrs x1, mpidr_el1 | 312 | mrs x1, mpidr_el1 |
@@ -413,7 +425,7 @@ ENTRY(secondary_startup) | |||
413 | mov x23, x0 // x23=current cpu_table | 425 | mov x23, x0 // x23=current cpu_table |
414 | cbz x23, __error_p // invalid processor (x23=0)? | 426 | cbz x23, __error_p // invalid processor (x23=0)? |
415 | 427 | ||
416 | pgtbl x25, x26, x24 // x25=TTBR0, x26=TTBR1 | 428 | pgtbl x25, x26, x28 // x25=TTBR0, x26=TTBR1 |
417 | ldr x12, [x23, #CPU_INFO_SETUP] | 429 | ldr x12, [x23, #CPU_INFO_SETUP] |
418 | add x12, x12, x28 // __virt_to_phys | 430 | add x12, x12, x28 // __virt_to_phys |
419 | blr x12 // initialise processor | 431 | blr x12 // initialise processor |
@@ -455,8 +467,13 @@ ENDPROC(__enable_mmu) | |||
455 | * x27 = *virtual* address to jump to upon completion | 467 | * x27 = *virtual* address to jump to upon completion |
456 | * | 468 | * |
457 | * other registers depend on the function called upon completion | 469 | * other registers depend on the function called upon completion |
470 | * | ||
471 | * We align the entire function to the smallest power of two larger than it to | ||
472 | * ensure it fits within a single block map entry. Otherwise were PHYS_OFFSET | ||
473 | * close to the end of a 512MB or 1GB block we might require an additional | ||
474 | * table to map the entire function. | ||
458 | */ | 475 | */ |
459 | .align 6 | 476 | .align 4 |
460 | __turn_mmu_on: | 477 | __turn_mmu_on: |
461 | msr sctlr_el1, x0 | 478 | msr sctlr_el1, x0 |
462 | isb | 479 | isb |
@@ -479,17 +496,38 @@ ENDPROC(__calc_phys_offset) | |||
479 | .quad PAGE_OFFSET | 496 | .quad PAGE_OFFSET |
480 | 497 | ||
481 | /* | 498 | /* |
482 | * Macro to populate the PGD for the corresponding block entry in the next | 499 | * Macro to create a table entry to the next page. |
483 | * level (tbl) for the given virtual address. | 500 | * |
501 | * tbl: page table address | ||
502 | * virt: virtual address | ||
503 | * shift: #imm page table shift | ||
504 | * ptrs: #imm pointers per table page | ||
505 | * | ||
506 | * Preserves: virt | ||
507 | * Corrupts: tmp1, tmp2 | ||
508 | * Returns: tbl -> next level table page address | ||
509 | */ | ||
510 | .macro create_table_entry, tbl, virt, shift, ptrs, tmp1, tmp2 | ||
511 | lsr \tmp1, \virt, #\shift | ||
512 | and \tmp1, \tmp1, #\ptrs - 1 // table index | ||
513 | add \tmp2, \tbl, #PAGE_SIZE | ||
514 | orr \tmp2, \tmp2, #PMD_TYPE_TABLE // address of next table and entry type | ||
515 | str \tmp2, [\tbl, \tmp1, lsl #3] | ||
516 | add \tbl, \tbl, #PAGE_SIZE // next level table page | ||
517 | .endm | ||
518 | |||
519 | /* | ||
520 | * Macro to populate the PGD (and possibily PUD) for the corresponding | ||
521 | * block entry in the next level (tbl) for the given virtual address. | ||
484 | * | 522 | * |
485 | * Preserves: pgd, tbl, virt | 523 | * Preserves: tbl, next, virt |
486 | * Corrupts: tmp1, tmp2 | 524 | * Corrupts: tmp1, tmp2 |
487 | */ | 525 | */ |
488 | .macro create_pgd_entry, pgd, tbl, virt, tmp1, tmp2 | 526 | .macro create_pgd_entry, tbl, virt, tmp1, tmp2 |
489 | lsr \tmp1, \virt, #PGDIR_SHIFT | 527 | create_table_entry \tbl, \virt, PGDIR_SHIFT, PTRS_PER_PGD, \tmp1, \tmp2 |
490 | and \tmp1, \tmp1, #PTRS_PER_PGD - 1 // PGD index | 528 | #if SWAPPER_PGTABLE_LEVELS == 3 |
491 | orr \tmp2, \tbl, #3 // PGD entry table type | 529 | create_table_entry \tbl, \virt, TABLE_SHIFT, PTRS_PER_PTE, \tmp1, \tmp2 |
492 | str \tmp2, [\pgd, \tmp1, lsl #3] | 530 | #endif |
493 | .endm | 531 | .endm |
494 | 532 | ||
495 | /* | 533 | /* |
@@ -522,7 +560,7 @@ ENDPROC(__calc_phys_offset) | |||
522 | * - pgd entry for fixed mappings (TTBR1) | 560 | * - pgd entry for fixed mappings (TTBR1) |
523 | */ | 561 | */ |
524 | __create_page_tables: | 562 | __create_page_tables: |
525 | pgtbl x25, x26, x24 // idmap_pg_dir and swapper_pg_dir addresses | 563 | pgtbl x25, x26, x28 // idmap_pg_dir and swapper_pg_dir addresses |
526 | mov x27, lr | 564 | mov x27, lr |
527 | 565 | ||
528 | /* | 566 | /* |
@@ -550,10 +588,10 @@ __create_page_tables: | |||
550 | /* | 588 | /* |
551 | * Create the identity mapping. | 589 | * Create the identity mapping. |
552 | */ | 590 | */ |
553 | add x0, x25, #PAGE_SIZE // section table address | 591 | mov x0, x25 // idmap_pg_dir |
554 | ldr x3, =KERNEL_START | 592 | ldr x3, =KERNEL_START |
555 | add x3, x3, x28 // __pa(KERNEL_START) | 593 | add x3, x3, x28 // __pa(KERNEL_START) |
556 | create_pgd_entry x25, x0, x3, x5, x6 | 594 | create_pgd_entry x0, x3, x5, x6 |
557 | ldr x6, =KERNEL_END | 595 | ldr x6, =KERNEL_END |
558 | mov x5, x3 // __pa(KERNEL_START) | 596 | mov x5, x3 // __pa(KERNEL_START) |
559 | add x6, x6, x28 // __pa(KERNEL_END) | 597 | add x6, x6, x28 // __pa(KERNEL_END) |
@@ -562,9 +600,9 @@ __create_page_tables: | |||
562 | /* | 600 | /* |
563 | * Map the kernel image (starting with PHYS_OFFSET). | 601 | * Map the kernel image (starting with PHYS_OFFSET). |
564 | */ | 602 | */ |
565 | add x0, x26, #PAGE_SIZE // section table address | 603 | mov x0, x26 // swapper_pg_dir |
566 | mov x5, #PAGE_OFFSET | 604 | mov x5, #PAGE_OFFSET |
567 | create_pgd_entry x26, x0, x5, x3, x6 | 605 | create_pgd_entry x0, x5, x3, x6 |
568 | ldr x6, =KERNEL_END | 606 | ldr x6, =KERNEL_END |
569 | mov x3, x24 // phys offset | 607 | mov x3, x24 // phys offset |
570 | create_block_map x0, x7, x3, x5, x6 | 608 | create_block_map x0, x7, x3, x5, x6 |
@@ -586,13 +624,6 @@ __create_page_tables: | |||
586 | create_block_map x0, x7, x3, x5, x6 | 624 | create_block_map x0, x7, x3, x5, x6 |
587 | 1: | 625 | 1: |
588 | /* | 626 | /* |
589 | * Create the pgd entry for the fixed mappings. | ||
590 | */ | ||
591 | ldr x5, =FIXADDR_TOP // Fixed mapping virtual address | ||
592 | add x0, x26, #2 * PAGE_SIZE // section table address | ||
593 | create_pgd_entry x26, x0, x5, x6, x7 | ||
594 | |||
595 | /* | ||
596 | * Since the page tables have been populated with non-cacheable | 627 | * Since the page tables have been populated with non-cacheable |
597 | * accesses (MMU disabled), invalidate the idmap and swapper page | 628 | * accesses (MMU disabled), invalidate the idmap and swapper page |
598 | * tables again to remove any speculatively loaded cache lines. | 629 | * tables again to remove any speculatively loaded cache lines. |
@@ -611,7 +642,7 @@ ENDPROC(__create_page_tables) | |||
611 | __switch_data: | 642 | __switch_data: |
612 | .quad __mmap_switched | 643 | .quad __mmap_switched |
613 | .quad __bss_start // x6 | 644 | .quad __bss_start // x6 |
614 | .quad _end // x7 | 645 | .quad __bss_stop // x7 |
615 | .quad processor_id // x4 | 646 | .quad processor_id // x4 |
616 | .quad __fdt_pointer // x5 | 647 | .quad __fdt_pointer // x5 |
617 | .quad memstart_addr // x6 | 648 | .quad memstart_addr // x6 |