Skip to content

Commit

Permalink
Merge git://git.kernel.org:/pub/scm/linux/kernel/git/davem/sparc
Browse files Browse the repository at this point in the history
Pull sparc updates from David Miller:
 "Just some more random bits from Al, including a conversion over to
  generic extables"

* git://git.kernel.org:/pub/scm/linux/kernel/git/davem/sparc:
  sparc32: take ->thread.flags out
  sparc32: get rid of fake_swapper_regs
  sparc64: get rid of fake_swapper_regs
  sparc32: switch to generic extables
  sparc32: switch copy_user.S away from range exception table entries
  sparc32: get rid of range exception table entries in checksum_32.S
  sparc32: switch __bzero() away from range exception table entries
  sparc32: kill lookup_fault()
  sparc32: don't bother with lookup_fault() in __bzero()
  • Loading branch information
torvalds committed Mar 9, 2021
2 parents 144c79e + cf64c2a commit 987a087
Show file tree
Hide file tree
Showing 21 changed files with 198 additions and 647 deletions.
1 change: 0 additions & 1 deletion arch/sparc/include/asm/elf_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/extable_64.h>
#include <asm/spitfire.h>
#include <asm/adi.h>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_EXTABLE64_H
#define __ASM_EXTABLE64_H
#ifndef __ASM_EXTABLE_H
#define __ASM_EXTABLE_H
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
Expand Down
6 changes: 1 addition & 5 deletions arch/sparc/include/asm/processor_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,12 @@ struct thread_struct {
unsigned long fsr;
unsigned long fpqdepth;
struct fpq fpqueue[16];
unsigned long flags;
mm_segment_t current_ds;
};

#define SPARC_FLAG_KTHREAD 0x1 /* task is a kernel thread */
#define SPARC_FLAG_UNALIGNED 0x2 /* is allowed to do unaligned accesses */

#define INIT_THREAD { \
.flags = SPARC_FLAG_KTHREAD, \
.current_ds = KERNEL_DS, \
.kregs = (struct pt_regs *)(init_stack+THREAD_SIZE)-1 \
}

/* Do necessary setup to start up a newly executed thread. */
Expand Down
1 change: 1 addition & 0 deletions arch/sparc/include/asm/thread_info_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ struct thread_info {
.task = &tsk, \
.current_ds = ASI_P, \
.preempt_count = INIT_PREEMPT_COUNT, \
.kregs = (struct pt_regs *)(init_stack+THREAD_SIZE)-1 \
}

/* how to get the thread information struct from C */
Expand Down
3 changes: 3 additions & 0 deletions arch/sparc/include/asm/uaccess.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef ___ASM_SPARC_UACCESS_H
#define ___ASM_SPARC_UACCESS_H

#include <asm/extable.h>

#if defined(__sparc__) && defined(__arch64__)
#include <asm/uaccess_64.h>
#else
Expand Down
38 changes: 0 additions & 38 deletions arch/sparc/include/asm/uaccess_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@

#include <asm/processor.h>

#define ARCH_HAS_SORT_EXTABLE
#define ARCH_HAS_SEARCH_EXTABLE

/* Sparc is not segmented, however we need to be able to fool access_ok()
* when doing system calls from kernel mode legitimately.
*
Expand All @@ -40,36 +37,6 @@
#define __access_ok(addr, size) (__user_ok((addr) & get_fs().seg, (size)))
#define access_ok(addr, size) __access_ok((unsigned long)(addr), size)

/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
* the address at which the program should continue. No registers are
* modified, so it is entirely up to the continuation code to figure out
* what to do.
*
* All the routines below use bits of fixup code that are out of line
* with the main instruction path. This means when everything is well,
* we don't even have to jump over them. Further, they do not intrude
* on our cache or tlb entries.
*
* There is a special way how to put a range of potentially faulting
* insns (like twenty ldd/std's with now intervening other instructions)
* You specify address of first in insn and 0 in fixup and in the next
* exception_table_entry you specify last potentially faulting insn + 1
* and in fixup the routine which should handle the fault.
* That fixup code will get
* (faulting_insn_address - first_insn_in_the_range_address)/4
* in %g2 (ie. index of the faulting instruction in the range).
*/

struct exception_table_entry
{
unsigned long insn, fixup;
};

/* Returns 0 if exception not found and fixup otherwise. */
unsigned long search_extables_range(unsigned long addr, unsigned long *g2);

/* Uh, these should become the main single-value transfer routines..
* They automatically use the right size if we just have the right
* pointer type..
Expand Down Expand Up @@ -252,12 +219,7 @@ static inline unsigned long __clear_user(void __user *addr, unsigned long size)
unsigned long ret;

__asm__ __volatile__ (
".section __ex_table,#alloc\n\t"
".align 4\n\t"
".word 1f,3\n\t"
".previous\n\t"
"mov %2, %%o1\n"
"1:\n\t"
"call __bzero\n\t"
" mov %1, %%o0\n\t"
"mov %%o0, %0\n"
Expand Down
1 change: 0 additions & 1 deletion arch/sparc/include/asm/uaccess_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include <linux/string.h>
#include <asm/asi.h>
#include <asm/spitfire.h>
#include <asm/extable_64.h>

#include <asm/processor.h>

Expand Down
2 changes: 1 addition & 1 deletion arch/sparc/kernel/head_32.S
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ continue_boot:

/* I want a kernel stack NOW! */
set init_thread_union, %g1
set (THREAD_SIZE - STACKFRAME_SZ), %g2
set (THREAD_SIZE - STACKFRAME_SZ - TRACEREG_SZ), %g2
add %g1, %g2, %sp
mov 0, %fp /* And for good luck */

Expand Down
2 changes: 1 addition & 1 deletion arch/sparc/kernel/head_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ tlb_fixup_done:
wr %g0, ASI_P, %asi
mov 1, %g1
sllx %g1, THREAD_SHIFT, %g1
sub %g1, (STACKFRAME_SZ + STACK_BIAS), %g1
sub %g1, (STACKFRAME_SZ + STACK_BIAS + TRACEREG_SZ), %g1
add %g6, %g1, %sp

/* Set per-cpu pointer initially to zero, this makes
Expand Down
12 changes: 0 additions & 12 deletions arch/sparc/kernel/process_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,16 +216,6 @@ void flush_thread(void)
clear_thread_flag(TIF_USEDFPU);
#endif
}

/* This task is no longer a kernel thread. */
if (current->thread.flags & SPARC_FLAG_KTHREAD) {
current->thread.flags &= ~SPARC_FLAG_KTHREAD;

/* We must fixup kregs as well. */
/* XXX This was not fixed for ti for a while, worked. Unused? */
current->thread.kregs = (struct pt_regs *)
(task_stack_page(current) + (THREAD_SIZE - TRACEREG_SZ));
}
}

static inline struct sparc_stackf __user *
Expand Down Expand Up @@ -313,7 +303,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
extern int nwindows;
unsigned long psr;
memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ);
p->thread.flags |= SPARC_FLAG_KTHREAD;
p->thread.current_ds = KERNEL_DS;
ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8);
childregs->u_regs[UREG_G1] = sp; /* function */
Expand All @@ -325,7 +314,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
}
memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
childregs->u_regs[UREG_FP] = sp;
p->thread.flags &= ~SPARC_FLAG_KTHREAD;
p->thread.current_ds = USER_DS;
ti->kpc = (((unsigned long) ret_from_fork) - 0x8);
ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
Expand Down
3 changes: 0 additions & 3 deletions arch/sparc/kernel/setup_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,6 @@ static __init void leon_patch(void)
}

struct tt_entry *sparc_ttable;
static struct pt_regs fake_swapper_regs;

/* Called from head_32.S - before we have setup anything
* in the kernel. Be very careful with what you do here.
Expand Down Expand Up @@ -363,8 +362,6 @@ void __init setup_arch(char **cmdline_p)
(*(linux_dbvec->teach_debugger))();
}

init_task.thread.kregs = &fake_swapper_regs;

/* Run-time patch instructions to match the cpu model */
per_cpu_patch();

Expand Down
4 changes: 0 additions & 4 deletions arch/sparc/kernel/setup_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,6 @@ extern int root_mountflags;

char reboot_command[COMMAND_LINE_SIZE];

static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };

static void __init per_cpu_patch(void)
{
struct cpuid_patch_entry *p;
Expand Down Expand Up @@ -661,8 +659,6 @@ void __init setup_arch(char **cmdline_p)
rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
#endif

task_thread_info(&init_task)->kregs = &fake_swapper_regs;

#ifdef CONFIG_IP_PNP
if (!ic_set_manually) {
phandle chosen = prom_finddevice("/chosen");
Expand Down
106 changes: 6 additions & 100 deletions arch/sparc/kernel/unaligned_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/uaccess.h>
#include <linux/smp.h>
#include <linux/perf_event.h>
#include <linux/extable.h>

#include <asm/setup.h>

Expand Down Expand Up @@ -213,10 +214,10 @@ static inline int ok_for_kernel(unsigned int insn)

static void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
{
unsigned long g2 = regs->u_regs [UREG_G2];
unsigned long fixup = search_extables_range(regs->pc, &g2);
const struct exception_table_entry *entry;

if (!fixup) {
entry = search_exception_tables(regs->pc);
if (!entry) {
unsigned long address = compute_effective_address(regs, insn);
if(address < PAGE_SIZE) {
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler");
Expand All @@ -232,9 +233,8 @@ static void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
die_if_kernel("Oops", regs);
/* Not reached */
}
regs->pc = fixup;
regs->pc = entry->fixup;
regs->npc = regs->pc + 4;
regs->u_regs [UREG_G2] = g2;
}

asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
Expand Down Expand Up @@ -274,103 +274,9 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
}
}

static inline int ok_for_user(struct pt_regs *regs, unsigned int insn,
enum direction dir)
{
unsigned int reg;
int size = ((insn >> 19) & 3) == 3 ? 8 : 4;

if ((regs->pc | regs->npc) & 3)
return 0;

/* Must access_ok() in all the necessary places. */
#define WINREG_ADDR(regnum) \
((void __user *)(((unsigned long *)regs->u_regs[UREG_FP])+(regnum)))

reg = (insn >> 25) & 0x1f;
if (reg >= 16) {
if (!access_ok(WINREG_ADDR(reg - 16), size))
return -EFAULT;
}
reg = (insn >> 14) & 0x1f;
if (reg >= 16) {
if (!access_ok(WINREG_ADDR(reg - 16), size))
return -EFAULT;
}
if (!(insn & 0x2000)) {
reg = (insn & 0x1f);
if (reg >= 16) {
if (!access_ok(WINREG_ADDR(reg - 16), size))
return -EFAULT;
}
}
#undef WINREG_ADDR
return 0;
}

static void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn)
{
send_sig_fault(SIGBUS, BUS_ADRALN,
(void __user *)safe_compute_effective_address(regs, insn),
0, current);
}

asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn)
{
enum direction dir;

if(!(current->thread.flags & SPARC_FLAG_UNALIGNED) ||
(((insn >> 30) & 3) != 3))
goto kill_user;
dir = decode_direction(insn);
if(!ok_for_user(regs, insn, dir)) {
goto kill_user;
} else {
int err, size = decode_access_size(insn);
unsigned long addr;

if(floating_point_load_or_store_p(insn)) {
printk("User FPU load/store unaligned unsupported.\n");
goto kill_user;
}

addr = compute_effective_address(regs, insn);
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
switch(dir) {
case load:
err = do_int_load(fetch_reg_addr(((insn>>25)&0x1f),
regs),
size, (unsigned long *) addr,
decode_signedness(insn));
break;

case store:
err = do_int_store(((insn>>25)&0x1f), size,
(unsigned long *) addr, regs);
break;

case both:
/*
* This was supported in 2.4. However, we question
* the value of SWAP instruction across word boundaries.
*/
printk("Unaligned SWAP unsupported.\n");
err = -EFAULT;
break;

default:
unaligned_panic("Impossible user unaligned trap.");
goto out;
}
if (err)
goto kill_user;
else
advance(regs);
goto out;
}

kill_user:
user_mna_trap_fault(regs, insn);
out:
;
}
Loading

0 comments on commit 987a087

Please sign in to comment.