[patch 17/18] x86/entry: Simplify the syscall number logic
Thomas Gleixner
tglx at kernel.org
Tue Jul 7 12:07:05 PDT 2026
Converting from int to long, back to int and then to unsigned int is
confusing at best.
None of this voodoo is required. Negative syscall numbers including -1
don't need any of this treatment and the low level ASM code already does
the sign extension to 64-bit on a 64-bit kernel.
The only point where signedness matters is the comparison against the
maximum syscall number, but that can be simplified by just using a unsigned
argument for the various syscall invocation functions.
Signed-off-by: Thomas Gleixner <tglx at kernel.org>
---
arch/x86/entry/syscall_32.c | 26 +++++++++++---------------
arch/x86/entry/syscall_64.c | 36 ++++++++++++++----------------------
arch/x86/include/asm/syscall.h | 2 +-
3 files changed, 26 insertions(+), 38 deletions(-)
--- a/arch/x86/entry/syscall_32.c
+++ b/arch/x86/entry/syscall_32.c
@@ -41,6 +41,8 @@ const sys_call_ptr_t sys_call_table[] =
#endif
#define __SYSCALL(nr, sym) case nr: return __ia32_##sym(regs);
+
+/* The unsigned int @nr argument is intentional as it creates denser code in a 64-bit build */
static noinline long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
{
switch (nr) {
@@ -49,7 +51,7 @@ static noinline long ia32_sys_call(const
}
}
-static __always_inline int syscall_32_enter(struct pt_regs *regs)
+static __always_inline long syscall_32_enter(struct pt_regs *regs)
{
if (IS_ENABLED(CONFIG_IA32_EMULATION))
current_thread_info()->status |= TS_COMPAT;
@@ -70,17 +72,11 @@ early_param("ia32_emulation", ia32_emula
/*
* Invoke a 32-bit syscall. Called with IRQs on in CT_STATE_KERNEL.
*/
-static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, int nr)
+static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, unsigned long nr)
{
- /*
- * Convert negative numbers to very high and thus out of range
- * numbers for comparisons.
- */
- unsigned int unr = nr;
-
- if (likely(unr < IA32_NR_syscalls)) {
- unr = array_index_nospec(unr, IA32_NR_syscalls);
- regs->ax = ia32_sys_call(regs, unr);
+ if (likely(nr < IA32_NR_syscalls)) {
+ nr = array_index_nospec(nr, IA32_NR_syscalls);
+ regs->ax = ia32_sys_call(regs, (unsigned int)nr);
}
}
@@ -126,7 +122,7 @@ static __always_inline bool int80_is_ext
*/
__visible noinstr void do_int80_emulation(struct pt_regs *regs)
{
- int nr;
+ long nr;
/* Kernel does not use INT $0x80! */
if (unlikely(!user_mode(regs))) {
@@ -205,7 +201,7 @@ static __always_inline bool int80_is_ext
*/
DEFINE_FREDENTRY_RAW(int80_emulation)
{
- int nr;
+ long nr;
enter_from_user_mode_randomize_stack(regs);
@@ -240,7 +236,7 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
/* Handles int $0x80 on a 32bit kernel */
__visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
{
- int nr = syscall_32_enter(regs);
+ long nr = syscall_32_enter(regs);
/*
* Subtlety here: if ptrace pokes something larger than 2^31-1 into
@@ -260,7 +256,7 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
{
- int nr = syscall_32_enter(regs);
+ long nr = syscall_32_enter(regs);
int res;
enter_from_user_mode_randomize_stack(regs);
--- a/arch/x86/entry/syscall_64.c
+++ b/arch/x86/entry/syscall_64.c
@@ -32,6 +32,8 @@ const sys_call_ptr_t sys_call_table[] =
#undef __SYSCALL
#define __SYSCALL(nr, sym) case nr: return __x64_##sym(regs);
+
+/* The unsigned int @nr argument is intentional as it creates denser code */
static noinline long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
{
switch (nr) {
@@ -52,39 +54,29 @@ static noinline long x32_sys_call(const
#endif
}
-static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr)
+static __always_inline bool do_syscall_x64(struct pt_regs *regs, unsigned long nr)
{
- /*
- * Convert negative numbers to very high and thus out of range
- * numbers for comparisons.
- */
- unsigned int unr = nr;
-
- if (likely(unr < NR_syscalls)) {
- unr = array_index_nospec(unr, NR_syscalls);
- regs->ax = x64_sys_call(regs, unr);
+ if (likely(nr < NR_syscalls)) {
+ nr = array_index_nospec(nr, NR_syscalls);
+ regs->ax = x64_sys_call(regs, (unsigned int)nr);
return true;
}
return false;
}
-static __always_inline void do_syscall_x32(struct pt_regs *regs, int nr)
+static __always_inline void do_syscall_x32(struct pt_regs *regs, unsigned long nr)
{
- /*
- * Adjust the starting offset of the table, and convert numbers
- * < __X32_SYSCALL_BIT to very high and thus out of range
- * numbers for comparisons.
- */
- unsigned int xnr = nr - __X32_SYSCALL_BIT;
-
- if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(xnr < X32_NR_syscalls)) {
- xnr = array_index_nospec(xnr, X32_NR_syscalls);
- regs->ax = x32_sys_call(regs, xnr);
+ /* Adjust the starting offset of the table */
+ nr -= __X32_SYSCALL_BIT;
+
+ if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(nr < X32_NR_syscalls)) {
+ nr = array_index_nospec(nr, X32_NR_syscalls);
+ regs->ax = x32_sys_call(regs, (unsigned int)nr);
}
}
/* Returns true to return using SYSRET, or false to use IRET */
-__visible noinstr bool do_syscall_64(struct pt_regs *regs, int nr)
+__visible noinstr bool do_syscall_64(struct pt_regs *regs, long nr)
{
nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
--- a/arch/x86/include/asm/syscall.h
+++ b/arch/x86/include/asm/syscall.h
@@ -164,7 +164,7 @@ static inline int syscall_get_arch(struc
? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64;
}
-bool do_syscall_64(struct pt_regs *regs, int nr);
+bool do_syscall_64(struct pt_regs *regs, long nr);
void do_int80_emulation(struct pt_regs *regs);
#endif /* CONFIG_X86_32 */
More information about the linux-riscv
mailing list