diff options
-rw-r--r-- | arch/mips/Makefile | 4 | ||||
-rw-r--r-- | arch/mips/kernel/head.S | 3 | ||||
-rw-r--r-- | arch/mips/kernel/module.c | 15 | ||||
-rw-r--r-- | arch/mips/mm/fault.c | 4 | ||||
-rw-r--r-- | arch/mips/mm/pgtable-64.c | 3 | ||||
-rw-r--r-- | arch/mips/mm/tlbex.c | 55 | ||||
-rw-r--r-- | include/asm-mips/pgtable-64.h | 13 |
7 files changed, 94 insertions, 3 deletions
diff --git a/arch/mips/Makefile b/arch/mips/Makefile index d580d46f967b..641aa30b3638 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile | |||
@@ -63,9 +63,7 @@ cflags-y += -mabi=64 | |||
63 | ifdef CONFIG_BUILD_ELF64 | 63 | ifdef CONFIG_BUILD_ELF64 |
64 | cflags-y += $(call cc-option,-mno-explicit-relocs) | 64 | cflags-y += $(call cc-option,-mno-explicit-relocs) |
65 | else | 65 | else |
66 | # -msym32 can not be used for modules since they are loaded into XKSEG | 66 | cflags-y += $(call cc-option,-msym32) |
67 | CFLAGS_MODULE += $(call cc-option,-mno-explicit-relocs) | ||
68 | CFLAGS_KERNEL += $(call cc-option,-msym32) | ||
69 | endif | 67 | endif |
70 | endif | 68 | endif |
71 | 69 | ||
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index ddc1b71c9378..a2e095adaa3f 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S | |||
@@ -250,6 +250,9 @@ NESTED(smp_bootstrap, 16, sp) | |||
250 | */ | 250 | */ |
251 | page swapper_pg_dir, _PGD_ORDER | 251 | page swapper_pg_dir, _PGD_ORDER |
252 | #ifdef CONFIG_64BIT | 252 | #ifdef CONFIG_64BIT |
253 | #if defined(CONFIG_MODULES) && !defined(CONFIG_BUILD_ELF64) | ||
254 | page module_pg_dir, _PGD_ORDER | ||
255 | #endif | ||
253 | page invalid_pmd_table, _PMD_ORDER | 256 | page invalid_pmd_table, _PMD_ORDER |
254 | #endif | 257 | #endif |
255 | page invalid_pte_table, _PTE_ORDER | 258 | page invalid_pte_table, _PTE_ORDER |
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index d7bf0215bc1d..cb0801437b66 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/spinlock.h> | 31 | #include <linux/spinlock.h> |
32 | #include <asm/pgtable.h> /* MODULE_START */ | ||
32 | 33 | ||
33 | struct mips_hi16 { | 34 | struct mips_hi16 { |
34 | struct mips_hi16 *next; | 35 | struct mips_hi16 *next; |
@@ -43,9 +44,23 @@ static DEFINE_SPINLOCK(dbe_lock); | |||
43 | 44 | ||
44 | void *module_alloc(unsigned long size) | 45 | void *module_alloc(unsigned long size) |
45 | { | 46 | { |
47 | #ifdef MODULE_START | ||
48 | struct vm_struct *area; | ||
49 | |||
50 | size = PAGE_ALIGN(size); | ||
51 | if (!size) | ||
52 | return NULL; | ||
53 | |||
54 | area = __get_vm_area(size, VM_ALLOC, MODULE_START, MODULE_END); | ||
55 | if (!area) | ||
56 | return NULL; | ||
57 | |||
58 | return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL); | ||
59 | #else | ||
46 | if (size == 0) | 60 | if (size == 0) |
47 | return NULL; | 61 | return NULL; |
48 | return vmalloc(size); | 62 | return vmalloc(size); |
63 | #endif | ||
49 | } | 64 | } |
50 | 65 | ||
51 | /* Free memory returned from module_alloc */ | 66 | /* Free memory returned from module_alloc */ |
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 8423d8590779..6f90e7ef66ac 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c | |||
@@ -60,6 +60,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, | |||
60 | */ | 60 | */ |
61 | if (unlikely(address >= VMALLOC_START && address <= VMALLOC_END)) | 61 | if (unlikely(address >= VMALLOC_START && address <= VMALLOC_END)) |
62 | goto vmalloc_fault; | 62 | goto vmalloc_fault; |
63 | #ifdef MODULE_START | ||
64 | if (unlikely(address >= MODULE_START && address < MODULE_END)) | ||
65 | goto vmalloc_fault; | ||
66 | #endif | ||
63 | 67 | ||
64 | /* | 68 | /* |
65 | * If we're in an interrupt or have no user | 69 | * If we're in an interrupt or have no user |
diff --git a/arch/mips/mm/pgtable-64.c b/arch/mips/mm/pgtable-64.c index 8d600d307d5d..c46eb651bf09 100644 --- a/arch/mips/mm/pgtable-64.c +++ b/arch/mips/mm/pgtable-64.c | |||
@@ -58,6 +58,9 @@ void __init pagetable_init(void) | |||
58 | 58 | ||
59 | /* Initialize the entire pgd. */ | 59 | /* Initialize the entire pgd. */ |
60 | pgd_init((unsigned long)swapper_pg_dir); | 60 | pgd_init((unsigned long)swapper_pg_dir); |
61 | #ifdef MODULE_START | ||
62 | pgd_init((unsigned long)module_pg_dir); | ||
63 | #endif | ||
61 | pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table); | 64 | pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table); |
62 | 65 | ||
63 | pgd_base = swapper_pg_dir; | 66 | pgd_base = swapper_pg_dir; |
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index fec318a1c8c5..492c518e7ba5 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
@@ -423,6 +423,9 @@ enum label_id { | |||
423 | label_invalid, | 423 | label_invalid, |
424 | label_second_part, | 424 | label_second_part, |
425 | label_leave, | 425 | label_leave, |
426 | #ifdef MODULE_START | ||
427 | label_module_alloc, | ||
428 | #endif | ||
426 | label_vmalloc, | 429 | label_vmalloc, |
427 | label_vmalloc_done, | 430 | label_vmalloc_done, |
428 | label_tlbw_hazard, | 431 | label_tlbw_hazard, |
@@ -455,6 +458,9 @@ static __init void build_label(struct label **lab, u32 *addr, | |||
455 | 458 | ||
456 | L_LA(_second_part) | 459 | L_LA(_second_part) |
457 | L_LA(_leave) | 460 | L_LA(_leave) |
461 | #ifdef MODULE_START | ||
462 | L_LA(_module_alloc) | ||
463 | #endif | ||
458 | L_LA(_vmalloc) | 464 | L_LA(_vmalloc) |
459 | L_LA(_vmalloc_done) | 465 | L_LA(_vmalloc_done) |
460 | L_LA(_tlbw_hazard) | 466 | L_LA(_tlbw_hazard) |
@@ -686,6 +692,13 @@ static void __init il_bgezl(u32 **p, struct reloc **r, unsigned int reg, | |||
686 | i_bgezl(p, reg, 0); | 692 | i_bgezl(p, reg, 0); |
687 | } | 693 | } |
688 | 694 | ||
695 | static void __init __attribute__((unused)) | ||
696 | il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l) | ||
697 | { | ||
698 | r_mips_pc16(r, *p, l); | ||
699 | i_bgez(p, reg, 0); | ||
700 | } | ||
701 | |||
689 | /* The only general purpose registers allowed in TLB handlers. */ | 702 | /* The only general purpose registers allowed in TLB handlers. */ |
690 | #define K0 26 | 703 | #define K0 26 |
691 | #define K1 27 | 704 | #define K1 27 |
@@ -970,7 +983,11 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r, | |||
970 | * The vmalloc handling is not in the hotpath. | 983 | * The vmalloc handling is not in the hotpath. |
971 | */ | 984 | */ |
972 | i_dmfc0(p, tmp, C0_BADVADDR); | 985 | i_dmfc0(p, tmp, C0_BADVADDR); |
986 | #ifdef MODULE_START | ||
987 | il_bltz(p, r, tmp, label_module_alloc); | ||
988 | #else | ||
973 | il_bltz(p, r, tmp, label_vmalloc); | 989 | il_bltz(p, r, tmp, label_vmalloc); |
990 | #endif | ||
974 | /* No i_nop needed here, since the next insn doesn't touch TMP. */ | 991 | /* No i_nop needed here, since the next insn doesn't touch TMP. */ |
975 | 992 | ||
976 | #ifdef CONFIG_SMP | 993 | #ifdef CONFIG_SMP |
@@ -1023,8 +1040,46 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r, | |||
1023 | { | 1040 | { |
1024 | long swpd = (long)swapper_pg_dir; | 1041 | long swpd = (long)swapper_pg_dir; |
1025 | 1042 | ||
1043 | #ifdef MODULE_START | ||
1044 | long modd = (long)module_pg_dir; | ||
1045 | |||
1046 | l_module_alloc(l, *p); | ||
1047 | /* | ||
1048 | * Assumption: | ||
1049 | * VMALLOC_START >= 0xc000000000000000UL | ||
1050 | * MODULE_START >= 0xe000000000000000UL | ||
1051 | */ | ||
1052 | i_SLL(p, ptr, bvaddr, 2); | ||
1053 | il_bgez(p, r, ptr, label_vmalloc); | ||
1054 | |||
1055 | if (in_compat_space_p(MODULE_START) && !rel_lo(MODULE_START)) { | ||
1056 | i_lui(p, ptr, rel_hi(MODULE_START)); /* delay slot */ | ||
1057 | } else { | ||
1058 | /* unlikely configuration */ | ||
1059 | i_nop(p); /* delay slot */ | ||
1060 | i_LA(p, ptr, MODULE_START); | ||
1061 | } | ||
1062 | i_dsubu(p, bvaddr, bvaddr, ptr); | ||
1063 | |||
1064 | if (in_compat_space_p(modd) && !rel_lo(modd)) { | ||
1065 | il_b(p, r, label_vmalloc_done); | ||
1066 | i_lui(p, ptr, rel_hi(modd)); | ||
1067 | } else { | ||
1068 | i_LA_mostly(p, ptr, modd); | ||
1069 | il_b(p, r, label_vmalloc_done); | ||
1070 | i_daddiu(p, ptr, ptr, rel_lo(modd)); | ||
1071 | } | ||
1072 | |||
1073 | l_vmalloc(l, *p); | ||
1074 | if (in_compat_space_p(MODULE_START) && !rel_lo(MODULE_START) && | ||
1075 | MODULE_START << 32 == VMALLOC_START) | ||
1076 | i_dsll32(p, ptr, ptr, 0); /* typical case */ | ||
1077 | else | ||
1078 | i_LA(p, ptr, VMALLOC_START); | ||
1079 | #else | ||
1026 | l_vmalloc(l, *p); | 1080 | l_vmalloc(l, *p); |
1027 | i_LA(p, ptr, VMALLOC_START); | 1081 | i_LA(p, ptr, VMALLOC_START); |
1082 | #endif | ||
1028 | i_dsubu(p, bvaddr, bvaddr, ptr); | 1083 | i_dsubu(p, bvaddr, bvaddr, ptr); |
1029 | 1084 | ||
1030 | if (in_compat_space_p(swpd) && !rel_lo(swpd)) { | 1085 | if (in_compat_space_p(swpd) && !rel_lo(swpd)) { |
diff --git a/include/asm-mips/pgtable-64.h b/include/asm-mips/pgtable-64.h index 7e7320300aa3..b9b1e86493ee 100644 --- a/include/asm-mips/pgtable-64.h +++ b/include/asm-mips/pgtable-64.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <asm/addrspace.h> | 14 | #include <asm/addrspace.h> |
15 | #include <asm/page.h> | 15 | #include <asm/page.h> |
16 | #include <asm/cachectl.h> | 16 | #include <asm/cachectl.h> |
17 | #include <asm/fixmap.h> | ||
17 | 18 | ||
18 | #include <asm-generic/pgtable-nopud.h> | 19 | #include <asm-generic/pgtable-nopud.h> |
19 | 20 | ||
@@ -103,6 +104,13 @@ | |||
103 | #define VMALLOC_START MAP_BASE | 104 | #define VMALLOC_START MAP_BASE |
104 | #define VMALLOC_END \ | 105 | #define VMALLOC_END \ |
105 | (VMALLOC_START + PTRS_PER_PGD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE) | 106 | (VMALLOC_START + PTRS_PER_PGD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE) |
107 | #if defined(CONFIG_MODULES) && !defined(CONFIG_BUILD_ELF64) && \ | ||
108 | VMALLOC_START != CKSSEG | ||
109 | /* Load modules into 32bit-compatible segment. */ | ||
110 | #define MODULE_START CKSSEG | ||
111 | #define MODULE_END (FIXADDR_START-2*PAGE_SIZE) | ||
112 | extern pgd_t module_pg_dir[PTRS_PER_PGD]; | ||
113 | #endif | ||
106 | 114 | ||
107 | #define pte_ERROR(e) \ | 115 | #define pte_ERROR(e) \ |
108 | printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e)) | 116 | printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e)) |
@@ -174,7 +182,12 @@ static inline void pud_clear(pud_t *pudp) | |||
174 | #define __pmd_offset(address) pmd_index(address) | 182 | #define __pmd_offset(address) pmd_index(address) |
175 | 183 | ||
176 | /* to find an entry in a kernel page-table-directory */ | 184 | /* to find an entry in a kernel page-table-directory */ |
185 | #ifdef MODULE_START | ||
186 | #define pgd_offset_k(address) \ | ||
187 | ((address) >= MODULE_START ? module_pg_dir : pgd_offset(&init_mm, 0UL)) | ||
188 | #else | ||
177 | #define pgd_offset_k(address) pgd_offset(&init_mm, 0UL) | 189 | #define pgd_offset_k(address) pgd_offset(&init_mm, 0UL) |
190 | #endif | ||
178 | 191 | ||
179 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) | 192 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) |
180 | #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) | 193 | #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) |