diff options
Diffstat (limited to 'arch')
54 files changed, 965 insertions, 133 deletions
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 838eac128409..89bbe5b41145 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c | |||
@@ -200,7 +200,6 @@ show_regs(struct pt_regs *regs) | |||
200 | void | 200 | void |
201 | start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) | 201 | start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) |
202 | { | 202 | { |
203 | set_fs(USER_DS); | ||
204 | regs->pc = pc; | 203 | regs->pc = pc; |
205 | regs->ps = 8; | 204 | regs->ps = 8; |
206 | wrusp(sp); | 205 | wrusp(sp); |
diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c index 44fd3b5c33ec..e58f0f562426 100644 --- a/arch/arm/mach-ux500/board-u5500.c +++ b/arch/arm/mach-ux500/board-u5500.c | |||
@@ -10,16 +10,97 @@ | |||
10 | #include <linux/amba/bus.h> | 10 | #include <linux/amba/bus.h> |
11 | #include <linux/gpio.h> | 11 | #include <linux/gpio.h> |
12 | #include <linux/irq.h> | 12 | #include <linux/irq.h> |
13 | #include <linux/i2c.h> | ||
13 | 14 | ||
14 | #include <asm/mach/arch.h> | 15 | #include <asm/mach/arch.h> |
15 | #include <asm/mach-types.h> | 16 | #include <asm/mach-types.h> |
16 | 17 | ||
18 | #include <plat/pincfg.h> | ||
19 | #include <plat/i2c.h> | ||
20 | |||
17 | #include <mach/hardware.h> | 21 | #include <mach/hardware.h> |
18 | #include <mach/devices.h> | 22 | #include <mach/devices.h> |
19 | #include <mach/setup.h> | 23 | #include <mach/setup.h> |
20 | 24 | ||
25 | #include "pins-db5500.h" | ||
21 | #include "devices-db5500.h" | 26 | #include "devices-db5500.h" |
27 | #include <linux/led-lm3530.h> | ||
28 | |||
29 | /* | ||
30 | * GPIO | ||
31 | */ | ||
32 | |||
33 | static pin_cfg_t u5500_pins[] = { | ||
34 | /* I2C */ | ||
35 | GPIO218_I2C2_SCL | PIN_INPUT_PULLUP, | ||
36 | GPIO219_I2C2_SDA | PIN_INPUT_PULLUP, | ||
37 | |||
38 | /* DISPLAY_ENABLE */ | ||
39 | GPIO226_GPIO | PIN_OUTPUT_LOW, | ||
40 | |||
41 | /* Backlight Enbale */ | ||
42 | GPIO224_GPIO | PIN_OUTPUT_HIGH, | ||
43 | }; | ||
44 | /* | ||
45 | * I2C | ||
46 | */ | ||
47 | |||
48 | #define U5500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \ | ||
49 | static struct nmk_i2c_controller u5500_i2c##id##_data = { \ | ||
50 | /* \ | ||
51 | * slave data setup time, which is \ | ||
52 | * 250 ns,100ns,10ns which is 14,6,2 \ | ||
53 | * respectively for a 48 Mhz \ | ||
54 | * i2c clock \ | ||
55 | */ \ | ||
56 | .slsu = _slsu, \ | ||
57 | /* Tx FIFO threshold */ \ | ||
58 | .tft = _tft, \ | ||
59 | /* Rx FIFO threshold */ \ | ||
60 | .rft = _rft, \ | ||
61 | /* std. mode operation */ \ | ||
62 | .clk_freq = clk, \ | ||
63 | .sm = _sm, \ | ||
64 | } | ||
65 | /* | ||
66 | * The board uses TODO <3> i2c controllers, initialize all of | ||
67 | * them with slave data setup time of 250 ns, | ||
68 | * Tx & Rx FIFO threshold values as 1 and standard | ||
69 | * mode of operation | ||
70 | */ | ||
71 | |||
72 | U5500_I2C_CONTROLLER(2, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST); | ||
73 | |||
74 | static struct lm3530_platform_data u5500_als_platform_data = { | ||
75 | .mode = LM3530_BL_MODE_MANUAL, | ||
76 | .als_input_mode = LM3530_INPUT_ALS1, | ||
77 | .max_current = LM3530_FS_CURR_26mA, | ||
78 | .pwm_pol_hi = true, | ||
79 | .als_avrg_time = LM3530_ALS_AVRG_TIME_512ms, | ||
80 | .brt_ramp_law = 1, /* Linear */ | ||
81 | .brt_ramp_fall = LM3530_RAMP_TIME_8s, | ||
82 | .brt_ramp_rise = LM3530_RAMP_TIME_8s, | ||
83 | .als1_resistor_sel = LM3530_ALS_IMPD_13_53kOhm, | ||
84 | .als2_resistor_sel = LM3530_ALS_IMPD_Z, | ||
85 | .als_vmin = 730, /* mV */ | ||
86 | .als_vmax = 1020, /* mV */ | ||
87 | .brt_val = 0x7F, /* Max brightness */ | ||
88 | }; | ||
22 | 89 | ||
90 | |||
91 | static struct i2c_board_info __initdata u5500_i2c2_devices[] = { | ||
92 | { | ||
93 | /* Backlight */ | ||
94 | I2C_BOARD_INFO("lm3530-led", 0x36), | ||
95 | .platform_data = &u5500_als_platform_data, | ||
96 | }, | ||
97 | }; | ||
98 | |||
99 | static void __init u5500_i2c_init(void) | ||
100 | { | ||
101 | db5500_add_i2c2(&u5500_i2c2_data); | ||
102 | i2c_register_board_info(2, ARRAY_AND_SIZE(u5500_i2c2_devices)); | ||
103 | } | ||
23 | static void __init u5500_uart_init(void) | 104 | static void __init u5500_uart_init(void) |
24 | { | 105 | { |
25 | db5500_add_uart0(NULL); | 106 | db5500_add_uart0(NULL); |
@@ -30,7 +111,8 @@ static void __init u5500_uart_init(void) | |||
30 | static void __init u5500_init_machine(void) | 111 | static void __init u5500_init_machine(void) |
31 | { | 112 | { |
32 | u5500_init_devices(); | 113 | u5500_init_devices(); |
33 | 114 | nmk_config_pins(u5500_pins, ARRAY_SIZE(u5500_pins)); | |
115 | u5500_i2c_init(); | ||
34 | u5500_sdi_init(); | 116 | u5500_sdi_init(); |
35 | u5500_uart_init(); | 117 | u5500_uart_init(); |
36 | } | 118 | } |
diff --git a/arch/cris/arch-v32/mach-a3/pinmux.c b/arch/cris/arch-v32/mach-a3/pinmux.c index 18648ef2d874..591f77526746 100644 --- a/arch/cris/arch-v32/mach-a3/pinmux.c +++ b/arch/cris/arch-v32/mach-a3/pinmux.c | |||
@@ -85,6 +85,8 @@ crisv32_pinmux_alloc_fixed(enum fixed_function function) | |||
85 | int ret = -EINVAL; | 85 | int ret = -EINVAL; |
86 | char saved[sizeof pins]; | 86 | char saved[sizeof pins]; |
87 | unsigned long flags; | 87 | unsigned long flags; |
88 | reg_pinmux_rw_hwprot hwprot; | ||
89 | reg_clkgen_rw_clk_ctrl clk_ctrl; | ||
88 | 90 | ||
89 | spin_lock_irqsave(&pinmux_lock, flags); | 91 | spin_lock_irqsave(&pinmux_lock, flags); |
90 | 92 | ||
@@ -93,9 +95,8 @@ crisv32_pinmux_alloc_fixed(enum fixed_function function) | |||
93 | 95 | ||
94 | crisv32_pinmux_init(); /* must be done before we read rw_hwprot */ | 96 | crisv32_pinmux_init(); /* must be done before we read rw_hwprot */ |
95 | 97 | ||
96 | reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); | 98 | hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); |
97 | reg_clkgen_rw_clk_ctrl clk_ctrl = REG_RD(clkgen, regi_clkgen, | 99 | clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); |
98 | rw_clk_ctrl); | ||
99 | 100 | ||
100 | switch (function) { | 101 | switch (function) { |
101 | case pinmux_eth: | 102 | case pinmux_eth: |
@@ -262,6 +263,7 @@ crisv32_pinmux_dealloc_fixed(enum fixed_function function) | |||
262 | int ret = -EINVAL; | 263 | int ret = -EINVAL; |
263 | char saved[sizeof pins]; | 264 | char saved[sizeof pins]; |
264 | unsigned long flags; | 265 | unsigned long flags; |
266 | reg_pinmux_rw_hwprot hwprot; | ||
265 | 267 | ||
266 | spin_lock_irqsave(&pinmux_lock, flags); | 268 | spin_lock_irqsave(&pinmux_lock, flags); |
267 | 269 | ||
@@ -270,7 +272,7 @@ crisv32_pinmux_dealloc_fixed(enum fixed_function function) | |||
270 | 272 | ||
271 | crisv32_pinmux_init(); /* must be done before we read rw_hwprot */ | 273 | crisv32_pinmux_init(); /* must be done before we read rw_hwprot */ |
272 | 274 | ||
273 | reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); | 275 | hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); |
274 | 276 | ||
275 | switch (function) { | 277 | switch (function) { |
276 | case pinmux_eth: | 278 | case pinmux_eth: |
diff --git a/arch/cris/include/arch-v10/arch/processor.h b/arch/cris/include/arch-v10/arch/processor.h index cc692c7a0660..93feb2a487d8 100644 --- a/arch/cris/include/arch-v10/arch/processor.h +++ b/arch/cris/include/arch-v10/arch/processor.h | |||
@@ -53,7 +53,6 @@ struct thread_struct { | |||
53 | */ | 53 | */ |
54 | 54 | ||
55 | #define start_thread(regs, ip, usp) do { \ | 55 | #define start_thread(regs, ip, usp) do { \ |
56 | set_fs(USER_DS); \ | ||
57 | regs->irp = ip; \ | 56 | regs->irp = ip; \ |
58 | regs->dccr |= 1 << U_DCCR_BITNR; \ | 57 | regs->dccr |= 1 << U_DCCR_BITNR; \ |
59 | wrusp(usp); \ | 58 | wrusp(usp); \ |
diff --git a/arch/cris/include/arch-v32/arch/processor.h b/arch/cris/include/arch-v32/arch/processor.h index f80b47790ca6..9603c907fbc4 100644 --- a/arch/cris/include/arch-v32/arch/processor.h +++ b/arch/cris/include/arch-v32/arch/processor.h | |||
@@ -47,7 +47,6 @@ struct thread_struct { | |||
47 | */ | 47 | */ |
48 | #define start_thread(regs, ip, usp) \ | 48 | #define start_thread(regs, ip, usp) \ |
49 | do { \ | 49 | do { \ |
50 | set_fs(USER_DS); \ | ||
51 | regs->erp = ip; \ | 50 | regs->erp = ip; \ |
52 | regs->ccs |= 1 << (U_CCS_BITNR + CCS_SHIFT); \ | 51 | regs->ccs |= 1 << (U_CCS_BITNR + CCS_SHIFT); \ |
53 | wrusp(usp); \ | 52 | wrusp(usp); \ |
diff --git a/arch/h8300/include/asm/processor.h b/arch/h8300/include/asm/processor.h index 69e8a34eb6d5..e834b6018897 100644 --- a/arch/h8300/include/asm/processor.h +++ b/arch/h8300/include/asm/processor.h | |||
@@ -81,7 +81,6 @@ struct thread_struct { | |||
81 | #if defined(__H8300H__) | 81 | #if defined(__H8300H__) |
82 | #define start_thread(_regs, _pc, _usp) \ | 82 | #define start_thread(_regs, _pc, _usp) \ |
83 | do { \ | 83 | do { \ |
84 | set_fs(USER_DS); /* reads from user space */ \ | ||
85 | (_regs)->pc = (_pc); \ | 84 | (_regs)->pc = (_pc); \ |
86 | (_regs)->ccr = 0x00; /* clear all flags */ \ | 85 | (_regs)->ccr = 0x00; /* clear all flags */ \ |
87 | (_regs)->er5 = current->mm->start_data; /* GOT base */ \ | 86 | (_regs)->er5 = current->mm->start_data; /* GOT base */ \ |
@@ -91,7 +90,6 @@ do { \ | |||
91 | #if defined(__H8300S__) | 90 | #if defined(__H8300S__) |
92 | #define start_thread(_regs, _pc, _usp) \ | 91 | #define start_thread(_regs, _pc, _usp) \ |
93 | do { \ | 92 | do { \ |
94 | set_fs(USER_DS); /* reads from user space */ \ | ||
95 | (_regs)->pc = (_pc); \ | 93 | (_regs)->pc = (_pc); \ |
96 | (_regs)->ccr = 0x00; /* clear kernel flag */ \ | 94 | (_regs)->ccr = 0x00; /* clear kernel flag */ \ |
97 | (_regs)->exr = 0x78; /* enable all interrupts */ \ | 95 | (_regs)->exr = 0x78; /* enable all interrupts */ \ |
diff --git a/arch/m32r/include/asm/processor.h b/arch/m32r/include/asm/processor.h index 8397c249989b..e1f46d757460 100644 --- a/arch/m32r/include/asm/processor.h +++ b/arch/m32r/include/asm/processor.h | |||
@@ -106,7 +106,6 @@ struct thread_struct { | |||
106 | 106 | ||
107 | #define start_thread(regs, new_pc, new_spu) \ | 107 | #define start_thread(regs, new_pc, new_spu) \ |
108 | do { \ | 108 | do { \ |
109 | set_fs(USER_DS); \ | ||
110 | regs->psw = (regs->psw | USERPS_BPSW) & 0x0000FFFFUL; \ | 109 | regs->psw = (regs->psw | USERPS_BPSW) & 0x0000FFFFUL; \ |
111 | regs->bpc = new_pc; \ | 110 | regs->bpc = new_pc; \ |
112 | regs->spu = new_spu; \ | 111 | regs->spu = new_spu; \ |
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index f111b02b704f..d8ef53ac03f9 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h | |||
@@ -105,9 +105,6 @@ struct thread_struct { | |||
105 | static inline void start_thread(struct pt_regs * regs, unsigned long pc, | 105 | static inline void start_thread(struct pt_regs * regs, unsigned long pc, |
106 | unsigned long usp) | 106 | unsigned long usp) |
107 | { | 107 | { |
108 | /* reads from user space */ | ||
109 | set_fs(USER_DS); | ||
110 | |||
111 | regs->pc = pc; | 108 | regs->pc = pc; |
112 | regs->sr &= ~0x2000; | 109 | regs->sr &= ~0x2000; |
113 | wrusp(usp); | 110 | wrusp(usp); |
@@ -129,7 +126,6 @@ extern int handle_kernel_fault(struct pt_regs *regs); | |||
129 | 126 | ||
130 | #define start_thread(_regs, _pc, _usp) \ | 127 | #define start_thread(_regs, _pc, _usp) \ |
131 | do { \ | 128 | do { \ |
132 | set_fs(USER_DS); /* reads from user space */ \ | ||
133 | (_regs)->pc = (_pc); \ | 129 | (_regs)->pc = (_pc); \ |
134 | ((struct switch_stack *)(_regs))[-1].a6 = 0; \ | 130 | ((struct switch_stack *)(_regs))[-1].a6 = 0; \ |
135 | reformat(_regs); \ | 131 | reformat(_regs); \ |
diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c index c2a1fc23dd75..1bc223aa07ec 100644 --- a/arch/m68k/kernel/process_mm.c +++ b/arch/m68k/kernel/process_mm.c | |||
@@ -185,7 +185,7 @@ EXPORT_SYMBOL(kernel_thread); | |||
185 | void flush_thread(void) | 185 | void flush_thread(void) |
186 | { | 186 | { |
187 | unsigned long zero = 0; | 187 | unsigned long zero = 0; |
188 | set_fs(USER_DS); | 188 | |
189 | current->thread.fs = __USER_DS; | 189 | current->thread.fs = __USER_DS; |
190 | if (!FPU_IS_EMU) | 190 | if (!FPU_IS_EMU) |
191 | asm volatile (".chip 68k/68881\n\t" | 191 | asm volatile (".chip 68k/68881\n\t" |
diff --git a/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c index 9b86ad11c68e..69c1803fcf1b 100644 --- a/arch/m68k/kernel/process_no.c +++ b/arch/m68k/kernel/process_no.c | |||
@@ -158,7 +158,7 @@ void flush_thread(void) | |||
158 | #ifdef CONFIG_FPU | 158 | #ifdef CONFIG_FPU |
159 | unsigned long zero = 0; | 159 | unsigned long zero = 0; |
160 | #endif | 160 | #endif |
161 | set_fs(USER_DS); | 161 | |
162 | current->thread.fs = __USER_DS; | 162 | current->thread.fs = __USER_DS; |
163 | #ifdef CONFIG_FPU | 163 | #ifdef CONFIG_FPU |
164 | if (!FPU_IS_EMU) | 164 | if (!FPU_IS_EMU) |
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 271ff6318eda..0e0ea941156f 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/cpumask.h> | 24 | #include <linux/cpumask.h> |
25 | #include <linux/memblock.h> | 25 | #include <linux/memblock.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/reboot.h> | ||
27 | 28 | ||
28 | #include <asm/prom.h> | 29 | #include <asm/prom.h> |
29 | #include <asm/rtas.h> | 30 | #include <asm/rtas.h> |
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index bf5f5ce3a7bd..e037c7494fd8 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/proc_fs.h> | 19 | #include <linux/proc_fs.h> |
20 | #include <linux/reboot.h> | ||
20 | #include <asm/delay.h> | 21 | #include <asm/delay.h> |
21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
22 | #include <asm/rtas.h> | 23 | #include <asm/rtas.h> |
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 253986bd6bb6..1074dddcb104 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig | |||
@@ -41,6 +41,7 @@ config SPARC64 | |||
41 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST | 41 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST |
42 | select HAVE_KRETPROBES | 42 | select HAVE_KRETPROBES |
43 | select HAVE_KPROBES | 43 | select HAVE_KPROBES |
44 | select HAVE_RCU_TABLE_FREE if SMP | ||
44 | select HAVE_MEMBLOCK | 45 | select HAVE_MEMBLOCK |
45 | select HAVE_SYSCALL_WRAPPERS | 46 | select HAVE_SYSCALL_WRAPPERS |
46 | select HAVE_DYNAMIC_FTRACE | 47 | select HAVE_DYNAMIC_FTRACE |
@@ -81,10 +82,6 @@ config IOMMU_HELPER | |||
81 | bool | 82 | bool |
82 | default y if SPARC64 | 83 | default y if SPARC64 |
83 | 84 | ||
84 | config QUICKLIST | ||
85 | bool | ||
86 | default y if SPARC64 | ||
87 | |||
88 | config STACKTRACE_SUPPORT | 85 | config STACKTRACE_SUPPORT |
89 | bool | 86 | bool |
90 | default y if SPARC64 | 87 | default y if SPARC64 |
diff --git a/arch/sparc/include/asm/pgalloc_64.h b/arch/sparc/include/asm/pgalloc_64.h index 4e5e0878144f..40b2d7a7023d 100644 --- a/arch/sparc/include/asm/pgalloc_64.h +++ b/arch/sparc/include/asm/pgalloc_64.h | |||
@@ -5,7 +5,6 @@ | |||
5 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
6 | #include <linux/mm.h> | 6 | #include <linux/mm.h> |
7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
8 | #include <linux/quicklist.h> | ||
9 | 8 | ||
10 | #include <asm/spitfire.h> | 9 | #include <asm/spitfire.h> |
11 | #include <asm/cpudata.h> | 10 | #include <asm/cpudata.h> |
@@ -14,71 +13,114 @@ | |||
14 | 13 | ||
15 | /* Page table allocation/freeing. */ | 14 | /* Page table allocation/freeing. */ |
16 | 15 | ||
16 | extern struct kmem_cache *pgtable_cache; | ||
17 | |||
17 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | 18 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) |
18 | { | 19 | { |
19 | return quicklist_alloc(0, GFP_KERNEL, NULL); | 20 | return kmem_cache_alloc(pgtable_cache, GFP_KERNEL); |
20 | } | 21 | } |
21 | 22 | ||
22 | static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) | 23 | static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) |
23 | { | 24 | { |
24 | quicklist_free(0, NULL, pgd); | 25 | kmem_cache_free(pgtable_cache, pgd); |
25 | } | 26 | } |
26 | 27 | ||
27 | #define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD) | 28 | #define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD) |
28 | 29 | ||
29 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) | 30 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) |
30 | { | 31 | { |
31 | return quicklist_alloc(0, GFP_KERNEL, NULL); | 32 | return kmem_cache_alloc(pgtable_cache, |
33 | GFP_KERNEL|__GFP_REPEAT); | ||
32 | } | 34 | } |
33 | 35 | ||
34 | static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) | 36 | static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) |
35 | { | 37 | { |
36 | quicklist_free(0, NULL, pmd); | 38 | kmem_cache_free(pgtable_cache, pmd); |
37 | } | 39 | } |
38 | 40 | ||
39 | static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, | 41 | static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, |
40 | unsigned long address) | 42 | unsigned long address) |
41 | { | 43 | { |
42 | return quicklist_alloc(0, GFP_KERNEL, NULL); | 44 | return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO); |
43 | } | 45 | } |
44 | 46 | ||
45 | static inline pgtable_t pte_alloc_one(struct mm_struct *mm, | 47 | static inline pgtable_t pte_alloc_one(struct mm_struct *mm, |
46 | unsigned long address) | 48 | unsigned long address) |
47 | { | 49 | { |
48 | struct page *page; | 50 | struct page *page; |
49 | void *pg; | 51 | pte_t *pte; |
50 | 52 | ||
51 | pg = quicklist_alloc(0, GFP_KERNEL, NULL); | 53 | pte = pte_alloc_one_kernel(mm, address); |
52 | if (!pg) | 54 | if (!pte) |
53 | return NULL; | 55 | return NULL; |
54 | page = virt_to_page(pg); | 56 | page = virt_to_page(pte); |
55 | pgtable_page_ctor(page); | 57 | pgtable_page_ctor(page); |
56 | return page; | 58 | return page; |
57 | } | 59 | } |
58 | 60 | ||
59 | static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) | 61 | static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) |
60 | { | 62 | { |
61 | quicklist_free(0, NULL, pte); | 63 | free_page((unsigned long)pte); |
62 | } | 64 | } |
63 | 65 | ||
64 | static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage) | 66 | static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage) |
65 | { | 67 | { |
66 | pgtable_page_dtor(ptepage); | 68 | pgtable_page_dtor(ptepage); |
67 | quicklist_free_page(0, NULL, ptepage); | 69 | __free_page(ptepage); |
68 | } | 70 | } |
69 | 71 | ||
70 | |||
71 | #define pmd_populate_kernel(MM, PMD, PTE) pmd_set(PMD, PTE) | 72 | #define pmd_populate_kernel(MM, PMD, PTE) pmd_set(PMD, PTE) |
72 | #define pmd_populate(MM,PMD,PTE_PAGE) \ | 73 | #define pmd_populate(MM,PMD,PTE_PAGE) \ |
73 | pmd_populate_kernel(MM,PMD,page_address(PTE_PAGE)) | 74 | pmd_populate_kernel(MM,PMD,page_address(PTE_PAGE)) |
74 | #define pmd_pgtable(pmd) pmd_page(pmd) | 75 | #define pmd_pgtable(pmd) pmd_page(pmd) |
75 | 76 | ||
76 | static inline void check_pgt_cache(void) | 77 | #define check_pgt_cache() do { } while (0) |
78 | |||
79 | static inline void pgtable_free(void *table, bool is_page) | ||
80 | { | ||
81 | if (is_page) | ||
82 | free_page((unsigned long)table); | ||
83 | else | ||
84 | kmem_cache_free(pgtable_cache, table); | ||
85 | } | ||
86 | |||
87 | #ifdef CONFIG_SMP | ||
88 | |||
89 | struct mmu_gather; | ||
90 | extern void tlb_remove_table(struct mmu_gather *, void *); | ||
91 | |||
92 | static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, bool is_page) | ||
93 | { | ||
94 | unsigned long pgf = (unsigned long)table; | ||
95 | if (is_page) | ||
96 | pgf |= 0x1UL; | ||
97 | tlb_remove_table(tlb, (void *)pgf); | ||
98 | } | ||
99 | |||
100 | static inline void __tlb_remove_table(void *_table) | ||
101 | { | ||
102 | void *table = (void *)((unsigned long)_table & ~0x1UL); | ||
103 | bool is_page = false; | ||
104 | |||
105 | if ((unsigned long)_table & 0x1UL) | ||
106 | is_page = true; | ||
107 | pgtable_free(table, is_page); | ||
108 | } | ||
109 | #else /* CONFIG_SMP */ | ||
110 | static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, bool is_page) | ||
77 | { | 111 | { |
78 | quicklist_trim(0, NULL, 25, 16); | 112 | pgtable_free(table, is_page); |
113 | } | ||
114 | #endif /* !CONFIG_SMP */ | ||
115 | |||
116 | static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage, | ||
117 | unsigned long address) | ||
118 | { | ||
119 | pgtable_page_dtor(ptepage); | ||
120 | pgtable_free_tlb(tlb, page_address(ptepage), true); | ||
79 | } | 121 | } |
80 | 122 | ||
81 | #define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte) | 123 | #define __pmd_free_tlb(tlb, pmd, addr) \ |
82 | #define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd) | 124 | pgtable_free_tlb(tlb, pmd, false) |
83 | 125 | ||
84 | #endif /* _SPARC64_PGALLOC_H */ | 126 | #endif /* _SPARC64_PGALLOC_H */ |
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 1e03c5a6b4f7..adf89329af59 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h | |||
@@ -95,6 +95,10 @@ | |||
95 | /* PTE bits which are the same in SUN4U and SUN4V format. */ | 95 | /* PTE bits which are the same in SUN4U and SUN4V format. */ |
96 | #define _PAGE_VALID _AC(0x8000000000000000,UL) /* Valid TTE */ | 96 | #define _PAGE_VALID _AC(0x8000000000000000,UL) /* Valid TTE */ |
97 | #define _PAGE_R _AC(0x8000000000000000,UL) /* Keep ref bit uptodate*/ | 97 | #define _PAGE_R _AC(0x8000000000000000,UL) /* Keep ref bit uptodate*/ |
98 | #define _PAGE_SPECIAL _AC(0x0200000000000000,UL) /* Special page */ | ||
99 | |||
100 | /* Advertise support for _PAGE_SPECIAL */ | ||
101 | #define __HAVE_ARCH_PTE_SPECIAL | ||
98 | 102 | ||
99 | /* SUN4U pte bits... */ | 103 | /* SUN4U pte bits... */ |
100 | #define _PAGE_SZ4MB_4U _AC(0x6000000000000000,UL) /* 4MB Page */ | 104 | #define _PAGE_SZ4MB_4U _AC(0x6000000000000000,UL) /* 4MB Page */ |
@@ -104,6 +108,7 @@ | |||
104 | #define _PAGE_NFO_4U _AC(0x1000000000000000,UL) /* No Fault Only */ | 108 | #define _PAGE_NFO_4U _AC(0x1000000000000000,UL) /* No Fault Only */ |
105 | #define _PAGE_IE_4U _AC(0x0800000000000000,UL) /* Invert Endianness */ | 109 | #define _PAGE_IE_4U _AC(0x0800000000000000,UL) /* Invert Endianness */ |
106 | #define _PAGE_SOFT2_4U _AC(0x07FC000000000000,UL) /* Software bits, set 2 */ | 110 | #define _PAGE_SOFT2_4U _AC(0x07FC000000000000,UL) /* Software bits, set 2 */ |
111 | #define _PAGE_SPECIAL_4U _AC(0x0200000000000000,UL) /* Special page */ | ||
107 | #define _PAGE_RES1_4U _AC(0x0002000000000000,UL) /* Reserved */ | 112 | #define _PAGE_RES1_4U _AC(0x0002000000000000,UL) /* Reserved */ |
108 | #define _PAGE_SZ32MB_4U _AC(0x0001000000000000,UL) /* (Panther) 32MB page */ | 113 | #define _PAGE_SZ32MB_4U _AC(0x0001000000000000,UL) /* (Panther) 32MB page */ |
109 | #define _PAGE_SZ256MB_4U _AC(0x2001000000000000,UL) /* (Panther) 256MB page */ | 114 | #define _PAGE_SZ256MB_4U _AC(0x2001000000000000,UL) /* (Panther) 256MB page */ |
@@ -133,6 +138,7 @@ | |||
133 | #define _PAGE_ACCESSED_4V _AC(0x1000000000000000,UL) /* Accessed (ref'd) */ | 138 | #define _PAGE_ACCESSED_4V _AC(0x1000000000000000,UL) /* Accessed (ref'd) */ |
134 | #define _PAGE_READ_4V _AC(0x0800000000000000,UL) /* Readable SW Bit */ | 139 | #define _PAGE_READ_4V _AC(0x0800000000000000,UL) /* Readable SW Bit */ |
135 | #define _PAGE_WRITE_4V _AC(0x0400000000000000,UL) /* Writable SW Bit */ | 140 | #define _PAGE_WRITE_4V _AC(0x0400000000000000,UL) /* Writable SW Bit */ |
141 | #define _PAGE_SPECIAL_4V _AC(0x0200000000000000,UL) /* Special page */ | ||
136 | #define _PAGE_PADDR_4V _AC(0x00FFFFFFFFFFE000,UL) /* paddr[55:13] */ | 142 | #define _PAGE_PADDR_4V _AC(0x00FFFFFFFFFFE000,UL) /* paddr[55:13] */ |
137 | #define _PAGE_IE_4V _AC(0x0000000000001000,UL) /* Invert Endianness */ | 143 | #define _PAGE_IE_4V _AC(0x0000000000001000,UL) /* Invert Endianness */ |
138 | #define _PAGE_E_4V _AC(0x0000000000000800,UL) /* side-Effect */ | 144 | #define _PAGE_E_4V _AC(0x0000000000000800,UL) /* side-Effect */ |
@@ -302,10 +308,10 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t prot) | |||
302 | : "=r" (mask), "=r" (tmp) | 308 | : "=r" (mask), "=r" (tmp) |
303 | : "i" (_PAGE_PADDR_4U | _PAGE_MODIFIED_4U | _PAGE_ACCESSED_4U | | 309 | : "i" (_PAGE_PADDR_4U | _PAGE_MODIFIED_4U | _PAGE_ACCESSED_4U | |
304 | _PAGE_CP_4U | _PAGE_CV_4U | _PAGE_E_4U | _PAGE_PRESENT_4U | | 310 | _PAGE_CP_4U | _PAGE_CV_4U | _PAGE_E_4U | _PAGE_PRESENT_4U | |
305 | _PAGE_SZBITS_4U), | 311 | _PAGE_SZBITS_4U | _PAGE_SPECIAL), |
306 | "i" (_PAGE_PADDR_4V | _PAGE_MODIFIED_4V | _PAGE_ACCESSED_4V | | 312 | "i" (_PAGE_PADDR_4V | _PAGE_MODIFIED_4V | _PAGE_ACCESSED_4V | |
307 | _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_E_4V | _PAGE_PRESENT_4V | | 313 | _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_E_4V | _PAGE_PRESENT_4V | |
308 | _PAGE_SZBITS_4V)); | 314 | _PAGE_SZBITS_4V | _PAGE_SPECIAL)); |
309 | 315 | ||
310 | return __pte((pte_val(pte) & mask) | (pgprot_val(prot) & ~mask)); | 316 | return __pte((pte_val(pte) & mask) | (pgprot_val(prot) & ~mask)); |
311 | } | 317 | } |
@@ -502,6 +508,7 @@ static inline pte_t pte_mkyoung(pte_t pte) | |||
502 | 508 | ||
503 | static inline pte_t pte_mkspecial(pte_t pte) | 509 | static inline pte_t pte_mkspecial(pte_t pte) |
504 | { | 510 | { |
511 | pte_val(pte) |= _PAGE_SPECIAL; | ||
505 | return pte; | 512 | return pte; |
506 | } | 513 | } |
507 | 514 | ||
@@ -607,9 +614,9 @@ static inline unsigned long pte_present(pte_t pte) | |||
607 | return val; | 614 | return val; |
608 | } | 615 | } |
609 | 616 | ||
610 | static inline int pte_special(pte_t pte) | 617 | static inline unsigned long pte_special(pte_t pte) |
611 | { | 618 | { |
612 | return 0; | 619 | return pte_val(pte) & _PAGE_SPECIAL; |
613 | } | 620 | } |
614 | 621 | ||
615 | #define pmd_set(pmdp, ptep) \ | 622 | #define pmd_set(pmdp, ptep) \ |
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile index 79836a7dd00c..e3cda21b5ee9 100644 --- a/arch/sparc/mm/Makefile +++ b/arch/sparc/mm/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | asflags-y := -ansi | 4 | asflags-y := -ansi |
5 | ccflags-y := -Werror | 5 | ccflags-y := -Werror |
6 | 6 | ||
7 | obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o | 7 | obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o gup.o |
8 | obj-y += fault_$(BITS).o | 8 | obj-y += fault_$(BITS).o |
9 | obj-y += init_$(BITS).o | 9 | obj-y += init_$(BITS).o |
10 | obj-$(CONFIG_SPARC32) += loadmmu.o | 10 | obj-$(CONFIG_SPARC32) += loadmmu.o |
diff --git a/arch/sparc/mm/gup.c b/arch/sparc/mm/gup.c new file mode 100644 index 000000000000..a986b5d05712 --- /dev/null +++ b/arch/sparc/mm/gup.c | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * Lockless get_user_pages_fast for sparc, cribbed from powerpc | ||
3 | * | ||
4 | * Copyright (C) 2008 Nick Piggin | ||
5 | * Copyright (C) 2008 Novell Inc. | ||
6 | */ | ||
7 | |||
8 | #include <linux/sched.h> | ||
9 | #include <linux/mm.h> | ||
10 | #include <linux/vmstat.h> | ||
11 | #include <linux/pagemap.h> | ||
12 | #include <linux/rwsem.h> | ||
13 | #include <asm/pgtable.h> | ||
14 | |||
15 | /* | ||
16 | * The performance critical leaf functions are made noinline otherwise gcc | ||
17 | * inlines everything into a single function which results in too much | ||
18 | * register pressure. | ||
19 | */ | ||
20 | static noinline int gup_pte_range(pmd_t pmd, unsigned long addr, | ||
21 | unsigned long end, int write, struct page **pages, int *nr) | ||
22 | { | ||
23 | unsigned long mask, result; | ||
24 | pte_t *ptep; | ||
25 | |||
26 | if (tlb_type == hypervisor) { | ||
27 | result = _PAGE_PRESENT_4V|_PAGE_P_4V; | ||
28 | if (write) | ||
29 | result |= _PAGE_WRITE_4V; | ||
30 | } else { | ||
31 | result = _PAGE_PRESENT_4U|_PAGE_P_4U; | ||
32 | if (write) | ||
33 | result |= _PAGE_WRITE_4U; | ||
34 | } | ||
35 | mask = result | _PAGE_SPECIAL; | ||
36 | |||
37 | ptep = pte_offset_kernel(&pmd, addr); | ||
38 | do { | ||
39 | struct page *page, *head; | ||
40 | pte_t pte = *ptep; | ||
41 | |||
42 | if ((pte_val(pte) & mask) != result) | ||
43 | return 0; | ||
44 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); | ||
45 | |||
46 | /* The hugepage case is simplified on sparc64 because | ||
47 | * we encode the sub-page pfn offsets into the | ||
48 | * hugepage PTEs. We could optimize this in the future | ||
49 | * use page_cache_add_speculative() for the hugepage case. | ||
50 | */ | ||
51 | page = pte_page(pte); | ||
52 | head = compound_head(page); | ||
53 | if (!page_cache_get_speculative(head)) | ||
54 | return 0; | ||
55 | if (unlikely(pte_val(pte) != pte_val(*ptep))) { | ||
56 | put_page(head); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | pages[*nr] = page; | ||
61 | (*nr)++; | ||
62 | } while (ptep++, addr += PAGE_SIZE, addr != end); | ||
63 | |||
64 | return 1; | ||
65 | } | ||
66 | |||
67 | static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, | ||
68 | int write, struct page **pages, int *nr) | ||
69 | { | ||
70 | unsigned long next; | ||
71 | pmd_t *pmdp; | ||
72 | |||
73 | pmdp = pmd_offset(&pud, addr); | ||
74 | do { | ||
75 | pmd_t pmd = *pmdp; | ||
76 | |||
77 | next = pmd_addr_end(addr, end); | ||
78 | if (pmd_none(pmd)) | ||
79 | return 0; | ||
80 | if (!gup_pte_range(pmd, addr, next, write, pages, nr)) | ||
81 | return 0; | ||
82 | } while (pmdp++, addr = next, addr != end); | ||
83 | |||
84 | return 1; | ||
85 | } | ||
86 | |||
87 | static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end, | ||
88 | int write, struct page **pages, int *nr) | ||
89 | { | ||
90 | unsigned long next; | ||
91 | pud_t *pudp; | ||
92 | |||
93 | pudp = pud_offset(&pgd, addr); | ||
94 | do { | ||
95 | pud_t pud = *pudp; | ||
96 | |||
97 | next = pud_addr_end(addr, end); | ||
98 | if (pud_none(pud)) | ||
99 | return 0; | ||
100 | if (!gup_pmd_range(pud, addr, next, write, pages, nr)) | ||
101 | return 0; | ||
102 | } while (pudp++, addr = next, addr != end); | ||
103 | |||
104 | return 1; | ||
105 | } | ||
106 | |||
107 | int get_user_pages_fast(unsigned long start, int nr_pages, int write, | ||
108 | struct page **pages) | ||
109 | { | ||
110 | struct mm_struct *mm = current->mm; | ||
111 | unsigned long addr, len, end; | ||
112 | unsigned long next; | ||
113 | pgd_t *pgdp; | ||
114 | int nr = 0; | ||
115 | |||
116 | start &= PAGE_MASK; | ||
117 | addr = start; | ||
118 | len = (unsigned long) nr_pages << PAGE_SHIFT; | ||
119 | end = start + len; | ||
120 | |||
121 | /* | ||
122 | * XXX: batch / limit 'nr', to avoid large irq off latency | ||
123 | * needs some instrumenting to determine the common sizes used by | ||
124 | * important workloads (eg. DB2), and whether limiting the batch size | ||
125 | * will decrease performance. | ||
126 | * | ||
127 | * It seems like we're in the clear for the moment. Direct-IO is | ||
128 | * the main guy that batches up lots of get_user_pages, and even | ||
129 | * they are limited to 64-at-a-time which is not so many. | ||
130 | */ | ||
131 | /* | ||
132 | * This doesn't prevent pagetable teardown, but does prevent | ||
133 | * the pagetables from being freed on sparc. | ||
134 | * | ||
135 | * So long as we atomically load page table pointers versus teardown, | ||
136 | * we can follow the address down to the the page and take a ref on it. | ||
137 | */ | ||
138 | local_irq_disable(); | ||
139 | |||
140 | pgdp = pgd_offset(mm, addr); | ||
141 | do { | ||
142 | pgd_t pgd = *pgdp; | ||
143 | |||
144 | next = pgd_addr_end(addr, end); | ||
145 | if (pgd_none(pgd)) | ||
146 | goto slow; | ||
147 | if (!gup_pud_range(pgd, addr, next, write, pages, &nr)) | ||
148 | goto slow; | ||
149 | } while (pgdp++, addr = next, addr != end); | ||
150 | |||
151 | local_irq_enable(); | ||
152 | |||
153 | VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT); | ||
154 | return nr; | ||
155 | |||
156 | { | ||
157 | int ret; | ||
158 | |||
159 | slow: | ||
160 | local_irq_enable(); | ||
161 | |||
162 | /* Try to get the remaining pages with get_user_pages */ | ||
163 | start += nr << PAGE_SHIFT; | ||
164 | pages += nr; | ||
165 | |||
166 | down_read(&mm->mmap_sem); | ||
167 | ret = get_user_pages(current, mm, start, | ||
168 | (end - start) >> PAGE_SHIFT, write, 0, pages, NULL); | ||
169 | up_read(&mm->mmap_sem); | ||
170 | |||
171 | /* Have to be a bit careful with return values */ | ||
172 | if (nr > 0) { | ||
173 | if (ret < 0) | ||
174 | ret = nr; | ||
175 | else | ||
176 | ret += nr; | ||
177 | } | ||
178 | |||
179 | return ret; | ||
180 | } | ||
181 | } | ||
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index a5f51b22fcbe..536412d8f416 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c | |||
@@ -236,6 +236,8 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsign | |||
236 | } | 236 | } |
237 | } | 237 | } |
238 | 238 | ||
239 | struct kmem_cache *pgtable_cache __read_mostly; | ||
240 | |||
239 | static struct kmem_cache *tsb_caches[8] __read_mostly; | 241 | static struct kmem_cache *tsb_caches[8] __read_mostly; |
240 | 242 | ||
241 | static const char *tsb_cache_names[8] = { | 243 | static const char *tsb_cache_names[8] = { |
@@ -253,6 +255,15 @@ void __init pgtable_cache_init(void) | |||
253 | { | 255 | { |
254 | unsigned long i; | 256 | unsigned long i; |
255 | 257 | ||
258 | pgtable_cache = kmem_cache_create("pgtable_cache", | ||
259 | PAGE_SIZE, PAGE_SIZE, | ||
260 | 0, | ||
261 | _clear_page); | ||
262 | if (!pgtable_cache) { | ||
263 | prom_printf("pgtable_cache_init(): Could not create!\n"); | ||
264 | prom_halt(); | ||
265 | } | ||
266 | |||
256 | for (i = 0; i < 8; i++) { | 267 | for (i = 0; i < 8; i++) { |
257 | unsigned long size = 8192 << i; | 268 | unsigned long size = 8192 << i; |
258 | const char *name = tsb_cache_names[i]; | 269 | const char *name = tsb_cache_names[i]; |
diff --git a/arch/um/Kconfig.x86 b/arch/um/Kconfig.x86 index 8aae429a56e2..d31ecf346b4e 100644 --- a/arch/um/Kconfig.x86 +++ b/arch/um/Kconfig.x86 | |||
@@ -1,3 +1,5 @@ | |||
1 | mainmenu "User Mode Linux/$SUBARCH $KERNELVERSION Kernel Configuration" | ||
2 | |||
1 | source "arch/um/Kconfig.common" | 3 | source "arch/um/Kconfig.common" |
2 | 4 | ||
3 | menu "UML-specific options" | 5 | menu "UML-specific options" |
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 25e1965df7ce..d4191fe1cede 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c | |||
@@ -543,11 +543,10 @@ int parse_chan_pair(char *str, struct line *line, int device, | |||
543 | const struct chan_opts *opts, char **error_out) | 543 | const struct chan_opts *opts, char **error_out) |
544 | { | 544 | { |
545 | struct list_head *chans = &line->chan_list; | 545 | struct list_head *chans = &line->chan_list; |
546 | struct chan *new, *chan; | 546 | struct chan *new; |
547 | char *in, *out; | 547 | char *in, *out; |
548 | 548 | ||
549 | if (!list_empty(chans)) { | 549 | if (!list_empty(chans)) { |
550 | chan = list_entry(chans->next, struct chan, list); | ||
551 | free_chan(chans, 0); | 550 | free_chan(chans, 0); |
552 | INIT_LIST_HEAD(chans); | 551 | INIT_LIST_HEAD(chans); |
553 | } | 552 | } |
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c index 93f227a25ba4..9cbb426c0b91 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c | |||
@@ -186,7 +186,11 @@ static int absolutize(char *to, int size, char *from) | |||
186 | strcat(to, "/"); | 186 | strcat(to, "/"); |
187 | strcat(to, from); | 187 | strcat(to, from); |
188 | } | 188 | } |
189 | chdir(save_cwd); | 189 | if (chdir(save_cwd)) { |
190 | cow_printf("absolutize : Can't cd to '%s' - " | ||
191 | "errno = %d\n", save_cwd, errno); | ||
192 | return -1; | ||
193 | } | ||
190 | return 0; | 194 | return 0; |
191 | } | 195 | } |
192 | 196 | ||
diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c index b56f8e0196a9..84dce3fc590c 100644 --- a/arch/um/drivers/harddog_user.c +++ b/arch/um/drivers/harddog_user.c | |||
@@ -32,7 +32,7 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) | |||
32 | { | 32 | { |
33 | struct dog_data data; | 33 | struct dog_data data; |
34 | int in_fds[2], out_fds[2], pid, n, err; | 34 | int in_fds[2], out_fds[2], pid, n, err; |
35 | char pid_buf[sizeof("nnnnn\0")], c; | 35 | char pid_buf[sizeof("nnnnnnn\0")], c; |
36 | char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL }; | 36 | char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL }; |
37 | char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, | 37 | char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, |
38 | NULL }; | 38 | NULL }; |
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 35dd0b86401a..d51c404239a8 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
@@ -176,10 +176,9 @@ void line_flush_buffer(struct tty_struct *tty) | |||
176 | { | 176 | { |
177 | struct line *line = tty->driver_data; | 177 | struct line *line = tty->driver_data; |
178 | unsigned long flags; | 178 | unsigned long flags; |
179 | int err; | ||
180 | 179 | ||
181 | spin_lock_irqsave(&line->lock, flags); | 180 | spin_lock_irqsave(&line->lock, flags); |
182 | err = flush_buffer(line); | 181 | flush_buffer(line); |
183 | spin_unlock_irqrestore(&line->lock, flags); | 182 | spin_unlock_irqrestore(&line->lock, flags); |
184 | } | 183 | } |
185 | 184 | ||
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 47d0c37897d5..22745b47c829 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c | |||
@@ -262,6 +262,15 @@ static int uml_net_change_mtu(struct net_device *dev, int new_mtu) | |||
262 | return 0; | 262 | return 0; |
263 | } | 263 | } |
264 | 264 | ||
265 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
266 | static void uml_net_poll_controller(struct net_device *dev) | ||
267 | { | ||
268 | disable_irq(dev->irq); | ||
269 | uml_net_interrupt(dev->irq, dev); | ||
270 | enable_irq(dev->irq); | ||
271 | } | ||
272 | #endif | ||
273 | |||
265 | static void uml_net_get_drvinfo(struct net_device *dev, | 274 | static void uml_net_get_drvinfo(struct net_device *dev, |
266 | struct ethtool_drvinfo *info) | 275 | struct ethtool_drvinfo *info) |
267 | { | 276 | { |
@@ -364,6 +373,9 @@ static const struct net_device_ops uml_netdev_ops = { | |||
364 | .ndo_set_mac_address = eth_mac_addr, | 373 | .ndo_set_mac_address = eth_mac_addr, |
365 | .ndo_change_mtu = uml_net_change_mtu, | 374 | .ndo_change_mtu = uml_net_change_mtu, |
366 | .ndo_validate_addr = eth_validate_addr, | 375 | .ndo_validate_addr = eth_validate_addr, |
376 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
377 | .ndo_poll_controller = uml_net_poll_controller, | ||
378 | #endif | ||
367 | }; | 379 | }; |
368 | 380 | ||
369 | /* | 381 | /* |
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index 9415dd9e63ef..520118888f16 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c | |||
@@ -228,7 +228,10 @@ static void change(char *dev, char *what, unsigned char *addr, | |||
228 | "buffer\n"); | 228 | "buffer\n"); |
229 | 229 | ||
230 | pid = change_tramp(argv, output, output_len); | 230 | pid = change_tramp(argv, output, output_len); |
231 | if (pid < 0) return; | 231 | if (pid < 0) { |
232 | kfree(output); | ||
233 | return; | ||
234 | } | ||
232 | 235 | ||
233 | if (output != NULL) { | 236 | if (output != NULL) { |
234 | printk("%s", output); | 237 | printk("%s", output); |
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index a1c2d2c98a94..cbacfc4e63e6 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c | |||
@@ -102,7 +102,7 @@ static int slip_tramp(char **argv, int fd) | |||
102 | "buffer\n"); | 102 | "buffer\n"); |
103 | os_kill_process(pid, 1); | 103 | os_kill_process(pid, 1); |
104 | err = -ENOMEM; | 104 | err = -ENOMEM; |
105 | goto out_free; | 105 | goto out_close; |
106 | } | 106 | } |
107 | 107 | ||
108 | close(fds[1]); | 108 | close(fds[1]); |
@@ -112,7 +112,6 @@ static int slip_tramp(char **argv, int fd) | |||
112 | err = helper_wait(pid); | 112 | err = helper_wait(pid); |
113 | close(fds[0]); | 113 | close(fds[0]); |
114 | 114 | ||
115 | out_free: | ||
116 | kfree(output); | 115 | kfree(output); |
117 | return err; | 116 | return err; |
118 | 117 | ||
diff --git a/arch/um/include/asm/delay.h b/arch/um/include/asm/delay.h index c71e32b6741e..8a5576d8eda5 100644 --- a/arch/um/include/asm/delay.h +++ b/arch/um/include/asm/delay.h | |||
@@ -1,20 +1,18 @@ | |||
1 | #ifndef __UM_DELAY_H | 1 | #ifndef __UM_DELAY_H |
2 | #define __UM_DELAY_H | 2 | #define __UM_DELAY_H |
3 | 3 | ||
4 | #define MILLION 1000000 | ||
5 | |||
6 | /* Undefined on purpose */ | 4 | /* Undefined on purpose */ |
7 | extern void __bad_udelay(void); | 5 | extern void __bad_udelay(void); |
6 | extern void __bad_ndelay(void); | ||
8 | 7 | ||
9 | extern void __udelay(unsigned long usecs); | 8 | extern void __udelay(unsigned long usecs); |
9 | extern void __ndelay(unsigned long usecs); | ||
10 | extern void __delay(unsigned long loops); | 10 | extern void __delay(unsigned long loops); |
11 | 11 | ||
12 | #define udelay(n) ((__builtin_constant_p(n) && (n) > 20000) ? \ | 12 | #define udelay(n) ((__builtin_constant_p(n) && (n) > 20000) ? \ |
13 | __bad_udelay() : __udelay(n)) | 13 | __bad_udelay() : __udelay(n)) |
14 | 14 | ||
15 | /* It appears that ndelay is not used at all for UML, and has never been | 15 | #define ndelay(n) ((__builtin_constant_p(n) && (n) > 20000) ? \ |
16 | * implemented. */ | 16 | __bad_ndelay() : __ndelay(n)) |
17 | extern void __unimplemented_ndelay(void); | ||
18 | #define ndelay(n) __unimplemented_ndelay() | ||
19 | 17 | ||
20 | #endif | 18 | #endif |
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index 09bd7b585726..939a4a67f0fd 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c | |||
@@ -38,7 +38,6 @@ void flush_thread(void) | |||
38 | 38 | ||
39 | void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) | 39 | void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) |
40 | { | 40 | { |
41 | set_fs(USER_DS); | ||
42 | PT_REGS_IP(regs) = eip; | 41 | PT_REGS_IP(regs) = eip; |
43 | PT_REGS_SP(regs) = esp; | 42 | PT_REGS_SP(regs) = esp; |
44 | } | 43 | } |
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 869bec9f2516..4d93dff6b371 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c | |||
@@ -20,9 +20,8 @@ static void kill_off_processes(void) | |||
20 | os_kill_ptraced_process(userspace_pid[0], 1); | 20 | os_kill_ptraced_process(userspace_pid[0], 1); |
21 | else { | 21 | else { |
22 | struct task_struct *p; | 22 | struct task_struct *p; |
23 | int pid, me; | 23 | int pid; |
24 | 24 | ||
25 | me = os_getpid(); | ||
26 | for_each_process(p) { | 25 | for_each_process(p) { |
27 | if (p->mm == NULL) | 26 | if (p->mm == NULL) |
28 | continue; | 27 | continue; |
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index d66f0388f091..b33f4dfe7ae5 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile | |||
@@ -3,10 +3,12 @@ | |||
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ | 6 | obj-y = aio.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ |
7 | registers.o sigio.o signal.o start_up.o time.o tty.o uaccess.o \ | 7 | registers.o sigio.o signal.o start_up.o time.o tty.o uaccess.o \ |
8 | umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/ | 8 | umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/ |
9 | 9 | ||
10 | obj-$(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) += elf_aux.o | ||
11 | |||
10 | USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \ | 12 | USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \ |
11 | main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \ | 13 | main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \ |
12 | tty.o tls.o uaccess.o umid.o util.o | 14 | tty.o tls.o uaccess.o umid.o util.o |
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 608784d4ec57..953323799381 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c | |||
@@ -14,16 +14,11 @@ | |||
14 | #include "mem_user.h" | 14 | #include "mem_user.h" |
15 | #include <kern_constants.h> | 15 | #include <kern_constants.h> |
16 | 16 | ||
17 | /* Use the one from the kernel - the host may miss it, if having old headers. */ | ||
18 | #if UM_ELF_CLASS == UM_ELFCLASS32 | ||
19 | typedef Elf32_auxv_t elf_auxv_t; | 17 | typedef Elf32_auxv_t elf_auxv_t; |
20 | #else | ||
21 | typedef Elf64_auxv_t elf_auxv_t; | ||
22 | #endif | ||
23 | 18 | ||
24 | /* These are initialized very early in boot and never changed */ | 19 | /* These are initialized very early in boot and never changed */ |
25 | char * elf_aux_platform; | 20 | char * elf_aux_platform; |
26 | long elf_aux_hwcap; | 21 | extern long elf_aux_hwcap; |
27 | unsigned long vsyscall_ehdr; | 22 | unsigned long vsyscall_ehdr; |
28 | unsigned long vsyscall_end; | 23 | unsigned long vsyscall_end; |
29 | unsigned long __kernel_vsyscall; | 24 | unsigned long __kernel_vsyscall; |
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index b6b1096152aa..feff22d64672 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c | |||
@@ -28,14 +28,14 @@ static int helper_child(void *arg) | |||
28 | { | 28 | { |
29 | struct helper_data *data = arg; | 29 | struct helper_data *data = arg; |
30 | char **argv = data->argv; | 30 | char **argv = data->argv; |
31 | int err; | 31 | int err, ret; |
32 | 32 | ||
33 | if (data->pre_exec != NULL) | 33 | if (data->pre_exec != NULL) |
34 | (*data->pre_exec)(data->pre_data); | 34 | (*data->pre_exec)(data->pre_data); |
35 | err = execvp_noalloc(data->buf, argv[0], argv); | 35 | err = execvp_noalloc(data->buf, argv[0], argv); |
36 | 36 | ||
37 | /* If the exec succeeds, we don't get here */ | 37 | /* If the exec succeeds, we don't get here */ |
38 | write(data->fd, &err, sizeof(err)); | 38 | CATCH_EINTR(ret = write(data->fd, &err, sizeof(err))); |
39 | 39 | ||
40 | return 0; | 40 | return 0; |
41 | } | 41 | } |
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index fb2a97a75fb1..8471b817d94f 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #define STACKSIZE (8 * 1024 * 1024) | 21 | #define STACKSIZE (8 * 1024 * 1024) |
22 | #define THREAD_NAME_LEN (256) | 22 | #define THREAD_NAME_LEN (256) |
23 | 23 | ||
24 | long elf_aux_hwcap; | ||
25 | |||
24 | static void set_stklim(void) | 26 | static void set_stklim(void) |
25 | { | 27 | { |
26 | struct rlimit lim; | 28 | struct rlimit lim; |
@@ -143,7 +145,9 @@ int __init main(int argc, char **argv, char **envp) | |||
143 | install_fatal_handler(SIGINT); | 145 | install_fatal_handler(SIGINT); |
144 | install_fatal_handler(SIGTERM); | 146 | install_fatal_handler(SIGTERM); |
145 | 147 | ||
148 | #ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA | ||
146 | scan_elf_aux(envp); | 149 | scan_elf_aux(envp); |
150 | #endif | ||
147 | 151 | ||
148 | do_uml_initcalls(); | 152 | do_uml_initcalls(); |
149 | ret = linux_main(argc, argv); | 153 | ret = linux_main(argc, argv); |
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index e696144d2be3..62878cf1d33f 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c | |||
@@ -176,7 +176,7 @@ static int __init make_tempfile(const char *template, char **out_tempname, | |||
176 | 176 | ||
177 | find_tempdir(); | 177 | find_tempdir(); |
178 | if ((tempdir == NULL) || (strlen(tempdir) >= MAXPATHLEN)) | 178 | if ((tempdir == NULL) || (strlen(tempdir) >= MAXPATHLEN)) |
179 | return -1; | 179 | goto out; |
180 | 180 | ||
181 | if (template[0] != '/') | 181 | if (template[0] != '/') |
182 | strcpy(tempname, tempdir); | 182 | strcpy(tempname, tempdir); |
@@ -191,13 +191,15 @@ static int __init make_tempfile(const char *template, char **out_tempname, | |||
191 | } | 191 | } |
192 | if (do_unlink && (unlink(tempname) < 0)) { | 192 | if (do_unlink && (unlink(tempname) < 0)) { |
193 | perror("unlink"); | 193 | perror("unlink"); |
194 | goto out; | 194 | goto close; |
195 | } | 195 | } |
196 | if (out_tempname) { | 196 | if (out_tempname) { |
197 | *out_tempname = tempname; | 197 | *out_tempname = tempname; |
198 | } else | 198 | } else |
199 | free(tempname); | 199 | free(tempname); |
200 | return fd; | 200 | return fd; |
201 | close: | ||
202 | close(fd); | ||
201 | out: | 203 | out: |
202 | free(tempname); | 204 | free(tempname); |
203 | return -1; | 205 | return -1; |
diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c index 05f5ea8e83d2..45ffe46871e0 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c | |||
@@ -113,3 +113,8 @@ EXPORT_SYMBOL(__stack_smash_handler); | |||
113 | 113 | ||
114 | extern long __guard __attribute__((weak)); | 114 | extern long __guard __attribute__((weak)); |
115 | EXPORT_SYMBOL(__guard); | 115 | EXPORT_SYMBOL(__guard); |
116 | |||
117 | #ifdef _FORTIFY_SOURCE | ||
118 | extern int __sprintf_chk(char *str, int flag, size_t strlen, const char *format); | ||
119 | EXPORT_SYMBOL(__sprintf_chk); | ||
120 | #endif | ||
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 87b659dadf3f..3923cfb87649 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ | 5 | obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ |
6 | ptrace_user.o setjmp.o signal.o stub.o stub_segv.o syscalls.o sysrq.o \ | 6 | ptrace_user.o setjmp.o signal.o stub.o stub_segv.o syscalls.o sysrq.o \ |
7 | sys_call_table.o tls.o atomic64_cx8_32.o | 7 | sys_call_table.o tls.o atomic64_cx8_32.o mem.o |
8 | 8 | ||
9 | obj-$(CONFIG_BINFMT_ELF) += elfcore.o | 9 | obj-$(CONFIG_BINFMT_ELF) += elfcore.o |
10 | 10 | ||
diff --git a/arch/um/sys-i386/asm/elf.h b/arch/um/sys-i386/asm/elf.h index d964a4111ac6..42305551d204 100644 --- a/arch/um/sys-i386/asm/elf.h +++ b/arch/um/sys-i386/asm/elf.h | |||
@@ -105,6 +105,8 @@ extern unsigned long __kernel_vsyscall; | |||
105 | #define FIXADDR_USER_START VSYSCALL_BASE | 105 | #define FIXADDR_USER_START VSYSCALL_BASE |
106 | #define FIXADDR_USER_END VSYSCALL_END | 106 | #define FIXADDR_USER_END VSYSCALL_END |
107 | 107 | ||
108 | #define __HAVE_ARCH_GATE_AREA 1 | ||
109 | |||
108 | /* | 110 | /* |
109 | * Architecture-neutral AT_ values in 0-17, leave some room | 111 | * Architecture-neutral AT_ values in 0-17, leave some room |
110 | * for more of them, start the x86-specific ones at 32. | 112 | * for more of them, start the x86-specific ones at 32. |
diff --git a/arch/um/sys-i386/delay.c b/arch/um/sys-i386/delay.c index d623e074f41d..f3fe1a688f7e 100644 --- a/arch/um/sys-i386/delay.c +++ b/arch/um/sys-i386/delay.c | |||
@@ -1,29 +1,60 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> | ||
3 | * Mostly copied from arch/x86/lib/delay.c | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
1 | #include <linux/module.h> | 10 | #include <linux/module.h> |
2 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
3 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
4 | #include <asm/param.h> | 13 | #include <asm/param.h> |
5 | 14 | ||
6 | void __delay(unsigned long time) | 15 | void __delay(unsigned long loops) |
7 | { | 16 | { |
8 | /* Stolen from the i386 __loop_delay */ | 17 | asm volatile( |
9 | int d0; | 18 | "test %0,%0\n" |
10 | __asm__ __volatile__( | 19 | "jz 3f\n" |
11 | "\tjmp 1f\n" | 20 | "jmp 1f\n" |
21 | |||
12 | ".align 16\n" | 22 | ".align 16\n" |
13 | "1:\tjmp 2f\n" | 23 | "1: jmp 2f\n" |
24 | |||
14 | ".align 16\n" | 25 | ".align 16\n" |
15 | "2:\tdecl %0\n\tjns 2b" | 26 | "2: dec %0\n" |
16 | :"=&a" (d0) | 27 | " jnz 2b\n" |
17 | :"0" (time)); | 28 | "3: dec %0\n" |
29 | |||
30 | : /* we don't need output */ | ||
31 | : "a" (loops) | ||
32 | ); | ||
18 | } | 33 | } |
34 | EXPORT_SYMBOL(__delay); | ||
19 | 35 | ||
20 | void __udelay(unsigned long usecs) | 36 | inline void __const_udelay(unsigned long xloops) |
21 | { | 37 | { |
22 | int i, n; | 38 | int d0; |
23 | 39 | ||
24 | n = (loops_per_jiffy * HZ * usecs) / MILLION; | 40 | xloops *= 4; |
25 | for(i=0;i<n;i++) | 41 | asm("mull %%edx" |
26 | cpu_relax(); | 42 | : "=d" (xloops), "=&a" (d0) |
43 | : "1" (xloops), "0" | ||
44 | (loops_per_jiffy * (HZ/4))); | ||
45 | |||
46 | __delay(++xloops); | ||
27 | } | 47 | } |
48 | EXPORT_SYMBOL(__const_udelay); | ||
28 | 49 | ||
50 | void __udelay(unsigned long usecs) | ||
51 | { | ||
52 | __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */ | ||
53 | } | ||
29 | EXPORT_SYMBOL(__udelay); | 54 | EXPORT_SYMBOL(__udelay); |
55 | |||
56 | void __ndelay(unsigned long nsecs) | ||
57 | { | ||
58 | __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */ | ||
59 | } | ||
60 | EXPORT_SYMBOL(__ndelay); | ||
diff --git a/arch/um/sys-i386/mem.c b/arch/um/sys-i386/mem.c new file mode 100644 index 000000000000..639900a6fde9 --- /dev/null +++ b/arch/um/sys-i386/mem.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/mm.h> | ||
10 | #include <asm/page.h> | ||
11 | #include <asm/mman.h> | ||
12 | |||
13 | static struct vm_area_struct gate_vma; | ||
14 | |||
15 | static int __init gate_vma_init(void) | ||
16 | { | ||
17 | if (!FIXADDR_USER_START) | ||
18 | return 0; | ||
19 | |||
20 | gate_vma.vm_mm = NULL; | ||
21 | gate_vma.vm_start = FIXADDR_USER_START; | ||
22 | gate_vma.vm_end = FIXADDR_USER_END; | ||
23 | gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC; | ||
24 | gate_vma.vm_page_prot = __P101; | ||
25 | |||
26 | /* | ||
27 | * Make sure the vDSO gets into every core dump. | ||
28 | * Dumping its contents makes post-mortem fully interpretable later | ||
29 | * without matching up the same kernel and hardware config to see | ||
30 | * what PC values meant. | ||
31 | */ | ||
32 | gate_vma.vm_flags |= VM_ALWAYSDUMP; | ||
33 | |||
34 | return 0; | ||
35 | } | ||
36 | __initcall(gate_vma_init); | ||
37 | |||
38 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) | ||
39 | { | ||
40 | return FIXADDR_USER_START ? &gate_vma : NULL; | ||
41 | } | ||
42 | |||
43 | int in_gate_area_no_mm(unsigned long addr) | ||
44 | { | ||
45 | if (!FIXADDR_USER_START) | ||
46 | return 0; | ||
47 | |||
48 | if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END)) | ||
49 | return 1; | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | int in_gate_area(struct mm_struct *mm, unsigned long addr) | ||
55 | { | ||
56 | struct vm_area_struct *vma = get_gate_vma(mm); | ||
57 | |||
58 | if (!vma) | ||
59 | return 0; | ||
60 | |||
61 | return (addr >= vma->vm_start) && (addr < vma->vm_end); | ||
62 | } | ||
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 61fc99a42e10..bd4d1d3ba919 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile | |||
@@ -4,10 +4,12 @@ | |||
4 | # Licensed under the GPL | 4 | # Licensed under the GPL |
5 | # | 5 | # |
6 | 6 | ||
7 | obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ | 7 | obj-y = bug.o bugs.o delay.o fault.o ldt.o ptrace.o ptrace_user.o mem.o \ |
8 | setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \ | 8 | setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \ |
9 | sysrq.o ksyms.o tls.o | 9 | sysrq.o ksyms.o tls.o |
10 | 10 | ||
11 | obj-y += vdso/ | ||
12 | |||
11 | subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o \ | 13 | subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o \ |
12 | lib/rwsem.o | 14 | lib/rwsem.o |
13 | subarch-obj-$(CONFIG_MODULES) += kernel/module.o | 15 | subarch-obj-$(CONFIG_MODULES) += kernel/module.o |
diff --git a/arch/um/sys-x86_64/asm/elf.h b/arch/um/sys-x86_64/asm/elf.h index d6d5af376251..11a2bfb38859 100644 --- a/arch/um/sys-x86_64/asm/elf.h +++ b/arch/um/sys-x86_64/asm/elf.h | |||
@@ -119,4 +119,14 @@ extern long elf_aux_hwcap; | |||
119 | 119 | ||
120 | #define SET_PERSONALITY(ex) do ; while(0) | 120 | #define SET_PERSONALITY(ex) do ; while(0) |
121 | 121 | ||
122 | #define __HAVE_ARCH_GATE_AREA 1 | ||
123 | #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 | ||
124 | struct linux_binprm; | ||
125 | extern int arch_setup_additional_pages(struct linux_binprm *bprm, | ||
126 | int uses_interp); | ||
127 | |||
128 | extern unsigned long um_vdso_addr; | ||
129 | #define AT_SYSINFO_EHDR 33 | ||
130 | #define ARCH_DLINFO NEW_AUX_ENT(AT_SYSINFO_EHDR, um_vdso_addr) | ||
131 | |||
122 | #endif | 132 | #endif |
diff --git a/arch/um/sys-x86_64/delay.c b/arch/um/sys-x86_64/delay.c index dee5be66da82..f3fe1a688f7e 100644 --- a/arch/um/sys-x86_64/delay.c +++ b/arch/um/sys-x86_64/delay.c | |||
@@ -1,30 +1,60 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2003 PathScale, Inc. | 2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> |
3 | * Copied from arch/x86_64 | 3 | * Mostly copied from arch/x86/lib/delay.c |
4 | * | 4 | * |
5 | * Licensed under the GPL | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
6 | */ | 8 | */ |
7 | 9 | ||
8 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/kernel.h> | ||
9 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
10 | #include <asm/processor.h> | ||
11 | #include <asm/param.h> | 13 | #include <asm/param.h> |
12 | 14 | ||
13 | void __delay(unsigned long loops) | 15 | void __delay(unsigned long loops) |
14 | { | 16 | { |
15 | unsigned long i; | 17 | asm volatile( |
18 | "test %0,%0\n" | ||
19 | "jz 3f\n" | ||
20 | "jmp 1f\n" | ||
16 | 21 | ||
17 | for(i = 0; i < loops; i++) | 22 | ".align 16\n" |
18 | cpu_relax(); | 23 | "1: jmp 2f\n" |
24 | |||
25 | ".align 16\n" | ||
26 | "2: dec %0\n" | ||
27 | " jnz 2b\n" | ||
28 | "3: dec %0\n" | ||
29 | |||
30 | : /* we don't need output */ | ||
31 | : "a" (loops) | ||
32 | ); | ||
19 | } | 33 | } |
34 | EXPORT_SYMBOL(__delay); | ||
20 | 35 | ||
21 | void __udelay(unsigned long usecs) | 36 | inline void __const_udelay(unsigned long xloops) |
22 | { | 37 | { |
23 | unsigned long i, n; | 38 | int d0; |
24 | 39 | ||
25 | n = (loops_per_jiffy * HZ * usecs) / MILLION; | 40 | xloops *= 4; |
26 | for(i=0;i<n;i++) | 41 | asm("mull %%edx" |
27 | cpu_relax(); | 42 | : "=d" (xloops), "=&a" (d0) |
43 | : "1" (xloops), "0" | ||
44 | (loops_per_jiffy * (HZ/4))); | ||
45 | |||
46 | __delay(++xloops); | ||
28 | } | 47 | } |
48 | EXPORT_SYMBOL(__const_udelay); | ||
29 | 49 | ||
50 | void __udelay(unsigned long usecs) | ||
51 | { | ||
52 | __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */ | ||
53 | } | ||
30 | EXPORT_SYMBOL(__udelay); | 54 | EXPORT_SYMBOL(__udelay); |
55 | |||
56 | void __ndelay(unsigned long nsecs) | ||
57 | { | ||
58 | __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */ | ||
59 | } | ||
60 | EXPORT_SYMBOL(__ndelay); | ||
diff --git a/arch/um/sys-x86_64/mem.c b/arch/um/sys-x86_64/mem.c index 3f8df8abf347..546518727a73 100644 --- a/arch/um/sys-x86_64/mem.c +++ b/arch/um/sys-x86_64/mem.c | |||
@@ -1,16 +1,26 @@ | |||
1 | /* | ||
2 | * Copyright 2003 PathScale, Inc. | ||
3 | * | ||
4 | * Licensed under the GPL | ||
5 | */ | ||
6 | |||
7 | #include "linux/mm.h" | 1 | #include "linux/mm.h" |
8 | #include "asm/page.h" | 2 | #include "asm/page.h" |
9 | #include "asm/mman.h" | 3 | #include "asm/mman.h" |
10 | 4 | ||
11 | unsigned long vm_stack_flags = __VM_STACK_FLAGS; | 5 | const char *arch_vma_name(struct vm_area_struct *vma) |
12 | unsigned long vm_stack_flags32 = __VM_STACK_FLAGS; | 6 | { |
13 | unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS; | 7 | if (vma->vm_mm && vma->vm_start == um_vdso_addr) |
14 | unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS; | 8 | return "[vdso]"; |
15 | unsigned long vm_force_exec32 = PROT_EXEC; | 9 | |
10 | return NULL; | ||
11 | } | ||
12 | |||
13 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) | ||
14 | { | ||
15 | return NULL; | ||
16 | } | ||
17 | |||
18 | int in_gate_area(struct mm_struct *mm, unsigned long addr) | ||
19 | { | ||
20 | return 0; | ||
21 | } | ||
16 | 22 | ||
23 | int in_gate_area_no_mm(unsigned long addr) | ||
24 | { | ||
25 | return 0; | ||
26 | } | ||
diff --git a/arch/um/sys-x86_64/shared/sysdep/vm-flags.h b/arch/um/sys-x86_64/shared/sysdep/vm-flags.h index 3213edfa7888..3978e55132d2 100644 --- a/arch/um/sys-x86_64/shared/sysdep/vm-flags.h +++ b/arch/um/sys-x86_64/shared/sysdep/vm-flags.h | |||
@@ -7,27 +7,9 @@ | |||
7 | #ifndef __VM_FLAGS_X86_64_H | 7 | #ifndef __VM_FLAGS_X86_64_H |
8 | #define __VM_FLAGS_X86_64_H | 8 | #define __VM_FLAGS_X86_64_H |
9 | 9 | ||
10 | #define __VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ | 10 | #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ |
11 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) | 11 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) |
12 | #define __VM_STACK_FLAGS (VM_GROWSDOWN | VM_READ | VM_WRITE | \ | 12 | #define VM_STACK_DEFAULT_FLAGS (VM_GROWSDOWN | VM_READ | VM_WRITE | \ |
13 | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | \ | 13 | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) |
14 | VM_MAYEXEC) | ||
15 | |||
16 | extern unsigned long vm_stack_flags, vm_stack_flags32; | ||
17 | extern unsigned long vm_data_default_flags, vm_data_default_flags32; | ||
18 | extern unsigned long vm_force_exec32; | ||
19 | |||
20 | #ifdef TIF_IA32 | ||
21 | #define VM_DATA_DEFAULT_FLAGS \ | ||
22 | (test_thread_flag(TIF_IA32) ? vm_data_default_flags32 : \ | ||
23 | vm_data_default_flags) | ||
24 | |||
25 | #define VM_STACK_DEFAULT_FLAGS \ | ||
26 | (test_thread_flag(TIF_IA32) ? vm_stack_flags32 : vm_stack_flags) | ||
27 | #endif | ||
28 | |||
29 | #define VM_DATA_DEFAULT_FLAGS vm_data_default_flags | ||
30 | |||
31 | #define VM_STACK_DEFAULT_FLAGS vm_stack_flags | ||
32 | 14 | ||
33 | #endif | 15 | #endif |
diff --git a/arch/um/sys-x86_64/vdso/Makefile b/arch/um/sys-x86_64/vdso/Makefile new file mode 100644 index 000000000000..5dffe6d46686 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/Makefile | |||
@@ -0,0 +1,90 @@ | |||
1 | # | ||
2 | # Building vDSO images for x86. | ||
3 | # | ||
4 | |||
5 | VDSO64-y := y | ||
6 | |||
7 | vdso-install-$(VDSO64-y) += vdso.so | ||
8 | |||
9 | |||
10 | # files to link into the vdso | ||
11 | vobjs-y := vdso-note.o um_vdso.o | ||
12 | |||
13 | # files to link into kernel | ||
14 | obj-$(VDSO64-y) += vdso.o vma.o | ||
15 | |||
16 | vobjs := $(foreach F,$(vobjs-y),$(obj)/$F) | ||
17 | |||
18 | $(obj)/vdso.o: $(obj)/vdso.so | ||
19 | |||
20 | targets += vdso.so vdso.so.dbg vdso.lds $(vobjs-y) | ||
21 | |||
22 | export CPPFLAGS_vdso.lds += -P -C | ||
23 | |||
24 | VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \ | ||
25 | -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 | ||
26 | |||
27 | $(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so | ||
28 | |||
29 | $(obj)/vdso.so.dbg: $(src)/vdso.lds $(vobjs) FORCE | ||
30 | $(call if_changed,vdso) | ||
31 | |||
32 | $(obj)/%.so: OBJCOPYFLAGS := -S | ||
33 | $(obj)/%.so: $(obj)/%.so.dbg FORCE | ||
34 | $(call if_changed,objcopy) | ||
35 | |||
36 | # | ||
37 | # Don't omit frame pointers for ease of userspace debugging, but do | ||
38 | # optimize sibling calls. | ||
39 | # | ||
40 | CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \ | ||
41 | $(filter -g%,$(KBUILD_CFLAGS)) $(call cc-option, -fno-stack-protector) \ | ||
42 | -fno-omit-frame-pointer -foptimize-sibling-calls | ||
43 | |||
44 | $(vobjs): KBUILD_CFLAGS += $(CFL) | ||
45 | |||
46 | # | ||
47 | # vDSO code runs in userspace and -pg doesn't help with profiling anyway. | ||
48 | # | ||
49 | CFLAGS_REMOVE_vdso-note.o = -pg | ||
50 | CFLAGS_REMOVE_um_vdso.o = -pg | ||
51 | |||
52 | targets += vdso-syms.lds | ||
53 | obj-$(VDSO64-y) += vdso-syms.lds | ||
54 | |||
55 | # | ||
56 | # Match symbols in the DSO that look like VDSO*; produce a file of constants. | ||
57 | # | ||
58 | sed-vdsosym := -e 's/^00*/0/' \ | ||
59 | -e 's/^\([0-9a-fA-F]*\) . \(VDSO[a-zA-Z0-9_]*\)$$/\2 = 0x\1;/p' | ||
60 | quiet_cmd_vdsosym = VDSOSYM $@ | ||
61 | define cmd_vdsosym | ||
62 | $(NM) $< | LC_ALL=C sed -n $(sed-vdsosym) | LC_ALL=C sort > $@ | ||
63 | endef | ||
64 | |||
65 | $(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE | ||
66 | $(call if_changed,vdsosym) | ||
67 | |||
68 | # | ||
69 | # The DSO images are built using a special linker script. | ||
70 | # | ||
71 | quiet_cmd_vdso = VDSO $@ | ||
72 | cmd_vdso = $(CC) -nostdlib -o $@ \ | ||
73 | $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ | ||
74 | -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \ | ||
75 | sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' | ||
76 | |||
77 | VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) | ||
78 | GCOV_PROFILE := n | ||
79 | |||
80 | # | ||
81 | # Install the unstripped copy of vdso*.so listed in $(vdso-install-y). | ||
82 | # | ||
83 | quiet_cmd_vdso_install = INSTALL $@ | ||
84 | cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ | ||
85 | $(vdso-install-y): %.so: $(obj)/%.so.dbg FORCE | ||
86 | @mkdir -p $(MODLIB)/vdso | ||
87 | $(call cmd,vdso_install) | ||
88 | |||
89 | PHONY += vdso_install $(vdso-install-y) | ||
90 | vdso_install: $(vdso-install-y) | ||
diff --git a/arch/um/sys-x86_64/vdso/checkundef.sh b/arch/um/sys-x86_64/vdso/checkundef.sh new file mode 100644 index 000000000000..7ee90a9b549d --- /dev/null +++ b/arch/um/sys-x86_64/vdso/checkundef.sh | |||
@@ -0,0 +1,10 @@ | |||
1 | #!/bin/sh | ||
2 | nm="$1" | ||
3 | file="$2" | ||
4 | $nm "$file" | grep '^ *U' > /dev/null 2>&1 | ||
5 | if [ $? -eq 1 ]; then | ||
6 | exit 0 | ||
7 | else | ||
8 | echo "$file: undefined symbols found" >&2 | ||
9 | exit 1 | ||
10 | fi | ||
diff --git a/arch/um/sys-x86_64/vdso/um_vdso.c b/arch/um/sys-x86_64/vdso/um_vdso.c new file mode 100644 index 000000000000..7c441b59d375 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/um_vdso.c | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This vDSO turns all calls into a syscall so that UML can trap them. | ||
9 | */ | ||
10 | |||
11 | |||
12 | /* Disable profiling for userspace code */ | ||
13 | #define DISABLE_BRANCH_PROFILING | ||
14 | |||
15 | #include <linux/time.h> | ||
16 | #include <linux/getcpu.h> | ||
17 | #include <asm/unistd.h> | ||
18 | |||
19 | int __vdso_clock_gettime(clockid_t clock, struct timespec *ts) | ||
20 | { | ||
21 | long ret; | ||
22 | |||
23 | asm("syscall" : "=a" (ret) : | ||
24 | "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : "memory"); | ||
25 | |||
26 | return ret; | ||
27 | } | ||
28 | int clock_gettime(clockid_t, struct timespec *) | ||
29 | __attribute__((weak, alias("__vdso_clock_gettime"))); | ||
30 | |||
31 | int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) | ||
32 | { | ||
33 | long ret; | ||
34 | |||
35 | asm("syscall" : "=a" (ret) : | ||
36 | "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory"); | ||
37 | |||
38 | return ret; | ||
39 | } | ||
40 | int gettimeofday(struct timeval *, struct timezone *) | ||
41 | __attribute__((weak, alias("__vdso_gettimeofday"))); | ||
42 | |||
43 | time_t __vdso_time(time_t *t) | ||
44 | { | ||
45 | long secs; | ||
46 | |||
47 | asm volatile("syscall" | ||
48 | : "=a" (secs) | ||
49 | : "0" (__NR_time), "D" (t) : "cc", "r11", "cx", "memory"); | ||
50 | |||
51 | return secs; | ||
52 | } | ||
53 | int time(time_t *t) __attribute__((weak, alias("__vdso_time"))); | ||
54 | |||
55 | long | ||
56 | __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused) | ||
57 | { | ||
58 | /* | ||
59 | * UML does not support SMP, we can cheat here. :) | ||
60 | */ | ||
61 | |||
62 | if (cpu) | ||
63 | *cpu = 0; | ||
64 | if (node) | ||
65 | *node = 0; | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | long getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) | ||
71 | __attribute__((weak, alias("__vdso_getcpu"))); | ||
diff --git a/arch/um/sys-x86_64/vdso/vdso-layout.lds.S b/arch/um/sys-x86_64/vdso/vdso-layout.lds.S new file mode 100644 index 000000000000..634a2cf62046 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/vdso-layout.lds.S | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Linker script for vDSO. This is an ELF shared object prelinked to | ||
3 | * its virtual address, and with only one read-only segment. | ||
4 | * This script controls its layout. | ||
5 | */ | ||
6 | |||
7 | SECTIONS | ||
8 | { | ||
9 | . = VDSO_PRELINK + SIZEOF_HEADERS; | ||
10 | |||
11 | .hash : { *(.hash) } :text | ||
12 | .gnu.hash : { *(.gnu.hash) } | ||
13 | .dynsym : { *(.dynsym) } | ||
14 | .dynstr : { *(.dynstr) } | ||
15 | .gnu.version : { *(.gnu.version) } | ||
16 | .gnu.version_d : { *(.gnu.version_d) } | ||
17 | .gnu.version_r : { *(.gnu.version_r) } | ||
18 | |||
19 | .note : { *(.note.*) } :text :note | ||
20 | |||
21 | .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr | ||
22 | .eh_frame : { KEEP (*(.eh_frame)) } :text | ||
23 | |||
24 | .dynamic : { *(.dynamic) } :text :dynamic | ||
25 | |||
26 | .rodata : { *(.rodata*) } :text | ||
27 | .data : { | ||
28 | *(.data*) | ||
29 | *(.sdata*) | ||
30 | *(.got.plt) *(.got) | ||
31 | *(.gnu.linkonce.d.*) | ||
32 | *(.bss*) | ||
33 | *(.dynbss*) | ||
34 | *(.gnu.linkonce.b.*) | ||
35 | } | ||
36 | |||
37 | .altinstructions : { *(.altinstructions) } | ||
38 | .altinstr_replacement : { *(.altinstr_replacement) } | ||
39 | |||
40 | /* | ||
41 | * Align the actual code well away from the non-instruction data. | ||
42 | * This is the best thing for the I-cache. | ||
43 | */ | ||
44 | . = ALIGN(0x100); | ||
45 | |||
46 | .text : { *(.text*) } :text =0x90909090 | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * Very old versions of ld do not recognize this name token; use the constant. | ||
51 | */ | ||
52 | #define PT_GNU_EH_FRAME 0x6474e550 | ||
53 | |||
54 | /* | ||
55 | * We must supply the ELF program headers explicitly to get just one | ||
56 | * PT_LOAD segment, and set the flags explicitly to make segments read-only. | ||
57 | */ | ||
58 | PHDRS | ||
59 | { | ||
60 | text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */ | ||
61 | dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ | ||
62 | note PT_NOTE FLAGS(4); /* PF_R */ | ||
63 | eh_frame_hdr PT_GNU_EH_FRAME; | ||
64 | } | ||
diff --git a/arch/um/sys-x86_64/vdso/vdso-note.S b/arch/um/sys-x86_64/vdso/vdso-note.S new file mode 100644 index 000000000000..79a071e4357e --- /dev/null +++ b/arch/um/sys-x86_64/vdso/vdso-note.S | |||
@@ -0,0 +1,12 @@ | |||
1 | /* | ||
2 | * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. | ||
3 | * Here we can supply some information useful to userland. | ||
4 | */ | ||
5 | |||
6 | #include <linux/uts.h> | ||
7 | #include <linux/version.h> | ||
8 | #include <linux/elfnote.h> | ||
9 | |||
10 | ELFNOTE_START(Linux, 0, "a") | ||
11 | .long LINUX_VERSION_CODE | ||
12 | ELFNOTE_END | ||
diff --git a/arch/um/sys-x86_64/vdso/vdso.S b/arch/um/sys-x86_64/vdso/vdso.S new file mode 100644 index 000000000000..ec82c1686bd6 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/vdso.S | |||
@@ -0,0 +1,10 @@ | |||
1 | #include <linux/init.h> | ||
2 | |||
3 | __INITDATA | ||
4 | |||
5 | .globl vdso_start, vdso_end | ||
6 | vdso_start: | ||
7 | .incbin "arch/um/sys-x86_64/vdso/vdso.so" | ||
8 | vdso_end: | ||
9 | |||
10 | __FINIT | ||
diff --git a/arch/um/sys-x86_64/vdso/vdso.lds.S b/arch/um/sys-x86_64/vdso/vdso.lds.S new file mode 100644 index 000000000000..b96b2677cad8 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/vdso.lds.S | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Linker script for 64-bit vDSO. | ||
3 | * We #include the file to define the layout details. | ||
4 | * Here we only choose the prelinked virtual address. | ||
5 | * | ||
6 | * This file defines the version script giving the user-exported symbols in | ||
7 | * the DSO. We can define local symbols here called VDSO* to make their | ||
8 | * values visible using the asm-x86/vdso.h macros from the kernel proper. | ||
9 | */ | ||
10 | |||
11 | #define VDSO_PRELINK 0xffffffffff700000 | ||
12 | #include "vdso-layout.lds.S" | ||
13 | |||
14 | /* | ||
15 | * This controls what userland symbols we export from the vDSO. | ||
16 | */ | ||
17 | VERSION { | ||
18 | LINUX_2.6 { | ||
19 | global: | ||
20 | clock_gettime; | ||
21 | __vdso_clock_gettime; | ||
22 | gettimeofday; | ||
23 | __vdso_gettimeofday; | ||
24 | getcpu; | ||
25 | __vdso_getcpu; | ||
26 | time; | ||
27 | __vdso_time; | ||
28 | local: *; | ||
29 | }; | ||
30 | } | ||
31 | |||
32 | VDSO64_PRELINK = VDSO_PRELINK; | ||
diff --git a/arch/um/sys-x86_64/vdso/vma.c b/arch/um/sys-x86_64/vdso/vma.c new file mode 100644 index 000000000000..9495c8d0ce37 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/vma.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/slab.h> | ||
10 | #include <linux/sched.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <asm/page.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | unsigned int __read_mostly vdso_enabled = 1; | ||
16 | unsigned long um_vdso_addr; | ||
17 | |||
18 | extern unsigned long task_size; | ||
19 | extern char vdso_start[], vdso_end[]; | ||
20 | |||
21 | static struct page **vdsop; | ||
22 | |||
23 | static int __init init_vdso(void) | ||
24 | { | ||
25 | struct page *um_vdso; | ||
26 | |||
27 | BUG_ON(vdso_end - vdso_start > PAGE_SIZE); | ||
28 | |||
29 | um_vdso_addr = task_size - PAGE_SIZE; | ||
30 | |||
31 | vdsop = kmalloc(GFP_KERNEL, sizeof(struct page *)); | ||
32 | if (!vdsop) | ||
33 | goto oom; | ||
34 | |||
35 | um_vdso = alloc_page(GFP_KERNEL); | ||
36 | if (!um_vdso) { | ||
37 | kfree(vdsop); | ||
38 | |||
39 | goto oom; | ||
40 | } | ||
41 | |||
42 | copy_page(page_address(um_vdso), vdso_start); | ||
43 | *vdsop = um_vdso; | ||
44 | |||
45 | return 0; | ||
46 | |||
47 | oom: | ||
48 | printk(KERN_ERR "Cannot allocate vdso\n"); | ||
49 | vdso_enabled = 0; | ||
50 | |||
51 | return -ENOMEM; | ||
52 | } | ||
53 | subsys_initcall(init_vdso); | ||
54 | |||
55 | int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | ||
56 | { | ||
57 | int err; | ||
58 | struct mm_struct *mm = current->mm; | ||
59 | |||
60 | if (!vdso_enabled) | ||
61 | return 0; | ||
62 | |||
63 | down_write(&mm->mmap_sem); | ||
64 | |||
65 | err = install_special_mapping(mm, um_vdso_addr, PAGE_SIZE, | ||
66 | VM_READ|VM_EXEC| | ||
67 | VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| | ||
68 | VM_ALWAYSDUMP, | ||
69 | vdsop); | ||
70 | |||
71 | up_write(&mm->mmap_sem); | ||
72 | |||
73 | return err; | ||
74 | } | ||
diff --git a/arch/xtensa/include/asm/uaccess.h b/arch/xtensa/include/asm/uaccess.h index 82d4e3815c89..3fa526fd3c99 100644 --- a/arch/xtensa/include/asm/uaccess.h +++ b/arch/xtensa/include/asm/uaccess.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #define _XTENSA_UACCESS_H | 17 | #define _XTENSA_UACCESS_H |
18 | 18 | ||
19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/prefetch.h> | ||
20 | #include <asm/types.h> | 21 | #include <asm/types.h> |
21 | 22 | ||
22 | #define VERIFY_READ 0 | 23 | #define VERIFY_READ 0 |
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index c72c9473ef99..a0d042aa2967 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c | |||
@@ -147,6 +147,9 @@ int ptrace_setxregs(struct task_struct *child, void __user *uregs) | |||
147 | elf_xtregs_t *xtregs = uregs; | 147 | elf_xtregs_t *xtregs = uregs; |
148 | int ret = 0; | 148 | int ret = 0; |
149 | 149 | ||
150 | if (!access_ok(VERIFY_READ, uregs, sizeof(elf_xtregs_t))) | ||
151 | return -EFAULT; | ||
152 | |||
150 | #if XTENSA_HAVE_COPROCESSORS | 153 | #if XTENSA_HAVE_COPROCESSORS |
151 | /* Flush all coprocessors before we overwrite them. */ | 154 | /* Flush all coprocessors before we overwrite them. */ |
152 | coprocessor_flush_all(ti); | 155 | coprocessor_flush_all(ti); |