Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: sdei: move uaccess logic to arch/arm64/

The SDEI support code is split across arch/arm64/ and drivers/firmware/,
largley this is split so that the arch-specific portions are under
arch/arm64, and the management logic is under drivers/firmware/.
However, exception entry fixups are currently under drivers/firmware.

Let's move the exception entry fixups under arch/arm64/. This
de-clutters the management logic, and puts all the arch-specific
portions in one place. Doing this also allows the fixups to be applied
earlier, so things like PAN and UAO will be in a known good state before
we run other logic. This will also make subsequent refactoring easier.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20201202131558.39270-2-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Mark Rutland and committed by
Catalin Marinas
a0ccf2ba d87a8e65

+12 -20
+12 -6
arch/arm64/kernel/sdei.c
··· 178 178 sdei_api_event_context(i, &regs->regs[i]); 179 179 } 180 180 181 - /* 182 - * We didn't take an exception to get here, set PAN. UAO will be cleared 183 - * by sdei_event_handler()s force_uaccess_begin() call. 184 - */ 185 - __uaccess_enable_hw_pan(); 186 - 187 181 err = sdei_event_handler(regs, arg); 188 182 if (err) 189 183 return SDEI_EV_FAILED; ··· 221 227 __sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg) 222 228 { 223 229 unsigned long ret; 230 + mm_segment_t orig_addr_limit; 231 + 232 + /* 233 + * We didn't take an exception to get here, so the HW hasn't set PAN or 234 + * cleared UAO, and the exception entry code hasn't reset addr_limit. 235 + * Set PAN, then use force_uaccess_begin() to clear UAO and reset 236 + * addr_limit. 237 + */ 238 + __uaccess_enable_hw_pan(); 239 + orig_addr_limit = force_uaccess_begin(); 224 240 225 241 nmi_enter(); 226 242 227 243 ret = _sdei_handler(regs, arg); 228 244 229 245 nmi_exit(); 246 + 247 + force_uaccess_end(orig_addr_limit); 230 248 231 249 return ret; 232 250 }
-14
drivers/firmware/arm_sdei.c
··· 31 31 #include <linux/slab.h> 32 32 #include <linux/smp.h> 33 33 #include <linux/spinlock.h> 34 - #include <linux/uaccess.h> 35 34 36 35 /* 37 36 * The call to use to reach the firmware. ··· 1091 1092 struct sdei_registered_event *arg) 1092 1093 { 1093 1094 int err; 1094 - mm_segment_t orig_addr_limit; 1095 1095 u32 event_num = arg->event_num; 1096 - 1097 - /* 1098 - * Save restore 'fs'. 1099 - * The architecture's entry code save/restores 'fs' when taking an 1100 - * exception from the kernel. This ensures addr_limit isn't inherited 1101 - * if you interrupted something that allowed the uaccess routines to 1102 - * access kernel memory. 1103 - * Do the same here because this doesn't come via the same entry code. 1104 - */ 1105 - orig_addr_limit = force_uaccess_begin(); 1106 1096 1107 1097 err = arg->callback(event_num, regs, arg->callback_arg); 1108 1098 if (err) 1109 1099 pr_err_ratelimited("event %u on CPU %u failed with error: %d\n", 1110 1100 event_num, smp_processor_id(), err); 1111 - 1112 - force_uaccess_end(orig_addr_limit); 1113 1101 1114 1102 return err; 1115 1103 }