diff options
author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2006-10-25 11:08:31 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2006-11-29 20:14:44 -0500 |
commit | 656be92f9ae194ed62bc81310a4589a7cd765f13 (patch) | |
tree | 5fb14d0d7d9cd2cab2cd83a1eea38c3c964f3054 /arch | |
parent | 56ae58333031bb0564c141f955d1e42276cade55 (diff) |
[MIPS] Load modules to CKSEG0 if CONFIG_BUILD_ELF64=n
This is a patch to load 64-bit modules to CKSEG0 so that can be
compiled with -msym32 option. This makes each module ~10% smaller.
* introduce MODULE_START and MODULE_END
* custom module_alloc()
* PGD for modules
* change XTLB refill handler synthesizer
* enable -msym32 for modules again
(revert ca78b1a5c6a6e70e052d3ea253828e49b5d07c8a)
New XTLB refill handler looks like this:
80000080 dmfc0 k0,C0_BADVADDR
80000084 bltz k0,800000e4 # goto l_module_alloc
80000088 lui k1,0x8046 # %high(pgd_current)
8000008c ld k1,24600(k1) # %low(pgd_current)
80000090 dsrl k0,k0,0x1b # l_vmalloc_done:
80000094 andi k0,k0,0x1ff8
80000098 daddu k1,k1,k0
8000009c dmfc0 k0,C0_BADVADDR
800000a0 ld k1,0(k1)
800000a4 dsrl k0,k0,0x12
800000a8 andi k0,k0,0xff8
800000ac daddu k1,k1,k0
800000b0 dmfc0 k0,C0_XCONTEXT
800000b4 ld k1,0(k1)
800000b8 andi k0,k0,0xff0
800000bc daddu k1,k1,k0
800000c0 ld k0,0(k1)
800000c4 ld k1,8(k1)
800000c8 dsrl k0,k0,0x6
800000cc mtc0 k0,C0_ENTRYLO0
800000d0 dsrl k1,k1,0x6
800000d4 mtc0 k1,C0_ENTRYL01
800000d8 nop
800000dc tlbwr
800000e0 eret
800000e4 dsll k1,k0,0x2 # l_module_alloc:
800000e8 bgez k1,80000008 # goto l_vmalloc
800000ec lui k1,0xc000
800000f0 dsubu k0,k0,k1
800000f4 lui k1,0x8046 # %high(module_pg_dir)
800000f8 beq zero,zero,80000000
800000fc nop
80000000 beq zero,zero,80000090 # goto l_vmalloc_done
80000004 daddiu k1,k1,0x4000
80000008 dsll32 k1,k1,0x0 # l_vmalloc:
8000000c dsubu k0,k0,k1
80000010 beq zero,zero,80000090 # goto l_vmalloc_done
80000014 lui k1,0x8046 # %high(swapper_pg_dir)
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-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 |
6 files changed, 81 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)) { |