Commit c4a7c77f authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

parents a36f4961 017fb98e
......@@ -249,8 +249,6 @@ struct tt_entry *sparc_ttable;
struct pt_regs fake_swapper_regs;
extern void paging_init(void);
void __init setup_arch(char **cmdline_p)
{
int i;
......
......@@ -540,8 +540,11 @@ bootup_user_stack_end:
prom_tba: .xword 0
tlb_type: .word 0 /* Must NOT end up in BSS */
.section ".fixup",#alloc,#execinstr
.globl __ret_efault
.globl __ret_efault, __retl_efault
__ret_efault:
ret
restore %g0, -EFAULT, %o0
__retl_efault:
retl
mov -EFAULT, %o0
......@@ -31,6 +31,7 @@
#include <asm/visasm.h>
#include <asm/spitfire.h>
#include <asm/page.h>
#include <asm/cpudata.h>
/* Returning from ptrace is a bit tricky because the syscall return
* low level code assumes any value returned which is negative and
......@@ -132,12 +133,16 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) {
unsigned long start = __pa(kaddr);
unsigned long end = start + len;
unsigned long dcache_line_size;
dcache_line_size = local_cpu_data().dcache_line_size;
if (tlb_type == spitfire) {
for (; start < end; start += 32)
for (; start < end; start += dcache_line_size)
spitfire_put_dcache_tag(start & 0x3fe0, 0x0);
} else {
for (; start < end; start += 32)
start &= ~(dcache_line_size - 1);
for (; start < end; start += dcache_line_size)
__asm__ __volatile__(
"stxa %%g0, [%0] %1\n\t"
"membar #Sync"
......@@ -150,8 +155,11 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
if (write && tlb_type == spitfire) {
unsigned long start = (unsigned long) kaddr;
unsigned long end = start + len;
unsigned long icache_line_size;
icache_line_size = local_cpu_data().icache_line_size;
for (; start < end; start += 32)
for (; start < end; start += icache_line_size)
flushi(start);
}
}
......
......@@ -464,8 +464,6 @@ static void __init boot_flags_init(char *commands)
}
}
extern int prom_probe_memory(void);
extern unsigned long start, end;
extern void panic_setup(char *, int *);
extern unsigned short root_flags;
......@@ -492,12 +490,8 @@ void register_prom_callbacks(void)
"' linux-.soft2 to .soft2");
}
extern void paging_init(void);
void __init setup_arch(char **cmdline_p)
{
int i;
/* Initialize PROM console and command line. */
*cmdline_p = prom_getbootargs();
strcpy(saved_command_line, *cmdline_p);
......@@ -516,21 +510,6 @@ void __init setup_arch(char **cmdline_p)
boot_flags_init(*cmdline_p);
idprom_init();
(void) prom_probe_memory();
phys_base = 0xffffffffffffffffUL;
for (i = 0; sp_banks[i].num_bytes != 0; i++) {
unsigned long top;
if (sp_banks[i].base_addr < phys_base)
phys_base = sp_banks[i].base_addr;
top = sp_banks[i].base_addr +
sp_banks[i].num_bytes;
}
pfn_base = phys_base >> PAGE_SHIFT;
kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
if (!root_flags)
root_mountflags &= ~MS_RDONLY;
......
......@@ -157,173 +157,199 @@ sys32_socketcall: /* %o0=call, %o1=args */
or %g2, %lo(__socketcall_table_begin), %g2
jmpl %g2 + %o0, %g0
nop
do_einval:
retl
mov -EINVAL, %o0
/* Each entry is exactly 32 bytes. */
.align 32
__socketcall_table_begin:
/* Each entry is exactly 32 bytes. */
do_sys_socket: /* sys_socket(int, int, int) */
ldswa [%o1 + 0x0] %asi, %o0
1: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_socket), %g1
ldswa [%o1 + 0x8] %asi, %o2
2: ldswa [%o1 + 0x8] %asi, %o2
jmpl %g1 + %lo(sys_socket), %g0
ldswa [%o1 + 0x4] %asi, %o1
3: ldswa [%o1 + 0x4] %asi, %o1
nop
nop
nop
do_sys_bind: /* sys_bind(int fd, struct sockaddr *, int) */
ldswa [%o1 + 0x0] %asi, %o0
4: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_bind), %g1
ldswa [%o1 + 0x8] %asi, %o2
5: ldswa [%o1 + 0x8] %asi, %o2
jmpl %g1 + %lo(sys_bind), %g0
lduwa [%o1 + 0x4] %asi, %o1
6: lduwa [%o1 + 0x4] %asi, %o1
nop
nop
nop
do_sys_connect: /* sys_connect(int, struct sockaddr *, int) */
ldswa [%o1 + 0x0] %asi, %o0
7: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_connect), %g1
ldswa [%o1 + 0x8] %asi, %o2
8: ldswa [%o1 + 0x8] %asi, %o2
jmpl %g1 + %lo(sys_connect), %g0
lduwa [%o1 + 0x4] %asi, %o1
9: lduwa [%o1 + 0x4] %asi, %o1
nop
nop
nop
do_sys_listen: /* sys_listen(int, int) */
ldswa [%o1 + 0x0] %asi, %o0
10: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_listen), %g1
jmpl %g1 + %lo(sys_listen), %g0
ldswa [%o1 + 0x4] %asi, %o1
11: ldswa [%o1 + 0x4] %asi, %o1
nop
nop
nop
nop
do_sys_accept: /* sys_accept(int, struct sockaddr *, int *) */
ldswa [%o1 + 0x0] %asi, %o0
12: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_accept), %g1
lduwa [%o1 + 0x8] %asi, %o2
13: lduwa [%o1 + 0x8] %asi, %o2
jmpl %g1 + %lo(sys_accept), %g0
lduwa [%o1 + 0x4] %asi, %o1
14: lduwa [%o1 + 0x4] %asi, %o1
nop
nop
nop
do_sys_getsockname: /* sys_getsockname(int, struct sockaddr *, int *) */
ldswa [%o1 + 0x0] %asi, %o0
15: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_getsockname), %g1
lduwa [%o1 + 0x8] %asi, %o2
16: lduwa [%o1 + 0x8] %asi, %o2
jmpl %g1 + %lo(sys_getsockname), %g0
lduwa [%o1 + 0x4] %asi, %o1
17: lduwa [%o1 + 0x4] %asi, %o1
nop
nop
nop
do_sys_getpeername: /* sys_getpeername(int, struct sockaddr *, int *) */
ldswa [%o1 + 0x0] %asi, %o0
18: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_getpeername), %g1
lduwa [%o1 + 0x8] %asi, %o2
19: lduwa [%o1 + 0x8] %asi, %o2
jmpl %g1 + %lo(sys_getpeername), %g0
lduwa [%o1 + 0x4] %asi, %o1
20: lduwa [%o1 + 0x4] %asi, %o1
nop
nop
nop
do_sys_socketpair: /* sys_socketpair(int, int, int, int *) */
ldswa [%o1 + 0x0] %asi, %o0
21: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_socketpair), %g1
ldswa [%o1 + 0x8] %asi, %o2
lduwa [%o1 + 0xc] %asi, %o3
22: ldswa [%o1 + 0x8] %asi, %o2
23: lduwa [%o1 + 0xc] %asi, %o3
jmpl %g1 + %lo(sys_socketpair), %g0
ldswa [%o1 + 0x4] %asi, %o1
24: ldswa [%o1 + 0x4] %asi, %o1
nop
nop
do_sys_send: /* sys_send(int, void *, size_t, unsigned int) */
ldswa [%o1 + 0x0] %asi, %o0
25: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_send), %g1
lduwa [%o1 + 0x8] %asi, %o2
lduwa [%o1 + 0xc] %asi, %o3
26: lduwa [%o1 + 0x8] %asi, %o2
27: lduwa [%o1 + 0xc] %asi, %o3
jmpl %g1 + %lo(sys_send), %g0
lduwa [%o1 + 0x4] %asi, %o1
28: lduwa [%o1 + 0x4] %asi, %o1
nop
nop
do_sys_recv: /* sys_recv(int, void *, size_t, unsigned int) */
ldswa [%o1 + 0x0] %asi, %o0
29: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_recv), %g1
lduwa [%o1 + 0x8] %asi, %o2
lduwa [%o1 + 0xc] %asi, %o3
30: lduwa [%o1 + 0x8] %asi, %o2
31: lduwa [%o1 + 0xc] %asi, %o3
jmpl %g1 + %lo(sys_recv), %g0
lduwa [%o1 + 0x4] %asi, %o1
32: lduwa [%o1 + 0x4] %asi, %o1
nop
nop
do_sys_sendto: /* sys_sendto(int, u32, compat_size_t, unsigned int, u32, int) */
ldswa [%o1 + 0x0] %asi, %o0
33: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_sendto), %g1
lduwa [%o1 + 0x8] %asi, %o2
lduwa [%o1 + 0xc] %asi, %o3
lduwa [%o1 + 0x10] %asi, %o4
ldswa [%o1 + 0x14] %asi, %o5
34: lduwa [%o1 + 0x8] %asi, %o2
35: lduwa [%o1 + 0xc] %asi, %o3
36: lduwa [%o1 + 0x10] %asi, %o4
37: ldswa [%o1 + 0x14] %asi, %o5
jmpl %g1 + %lo(sys_sendto), %g0
lduwa [%o1 + 0x4] %asi, %o1
38: lduwa [%o1 + 0x4] %asi, %o1
do_sys_recvfrom: /* sys_recvfrom(int, u32, compat_size_t, unsigned int, u32, u32) */
ldswa [%o1 + 0x0] %asi, %o0
39: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_recvfrom), %g1
lduwa [%o1 + 0x8] %asi, %o2
lduwa [%o1 + 0xc] %asi, %o3
lduwa [%o1 + 0x10] %asi, %o4
lduwa [%o1 + 0x14] %asi, %o5
40: lduwa [%o1 + 0x8] %asi, %o2
41: lduwa [%o1 + 0xc] %asi, %o3
42: lduwa [%o1 + 0x10] %asi, %o4
43: lduwa [%o1 + 0x14] %asi, %o5
jmpl %g1 + %lo(sys_recvfrom), %g0
lduwa [%o1 + 0x4] %asi, %o1
44: lduwa [%o1 + 0x4] %asi, %o1
do_sys_shutdown: /* sys_shutdown(int, int) */
ldswa [%o1 + 0x0] %asi, %o0
45: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(sys_shutdown), %g1
jmpl %g1 + %lo(sys_shutdown), %g0
ldswa [%o1 + 0x4] %asi, %o1
46: ldswa [%o1 + 0x4] %asi, %o1
nop
nop
nop
nop
do_sys_setsockopt: /* compat_sys_setsockopt(int, int, int, char *, int) */
ldswa [%o1 + 0x0] %asi, %o0
47: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(compat_sys_setsockopt), %g1
ldswa [%o1 + 0x8] %asi, %o2
lduwa [%o1 + 0xc] %asi, %o3
ldswa [%o1 + 0x10] %asi, %o4
48: ldswa [%o1 + 0x8] %asi, %o2
49: lduwa [%o1 + 0xc] %asi, %o3
50: ldswa [%o1 + 0x10] %asi, %o4
jmpl %g1 + %lo(compat_sys_setsockopt), %g0
ldswa [%o1 + 0x4] %asi, %o1
51: ldswa [%o1 + 0x4] %asi, %o1
nop
do_sys_getsockopt: /* compat_sys_getsockopt(int, int, int, u32, u32) */
ldswa [%o1 + 0x0] %asi, %o0
52: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(compat_sys_getsockopt), %g1
ldswa [%o1 + 0x8] %asi, %o2
lduwa [%o1 + 0xc] %asi, %o3
lduwa [%o1 + 0x10] %asi, %o4
53: ldswa [%o1 + 0x8] %asi, %o2
54: lduwa [%o1 + 0xc] %asi, %o3
55: lduwa [%o1 + 0x10] %asi, %o4
jmpl %g1 + %lo(compat_sys_getsockopt), %g0
ldswa [%o1 + 0x4] %asi, %o1
56: ldswa [%o1 + 0x4] %asi, %o1
nop
do_sys_sendmsg: /* compat_sys_sendmsg(int, struct compat_msghdr *, unsigned int) */
ldswa [%o1 + 0x0] %asi, %o0
57: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(compat_sys_sendmsg), %g1
lduwa [%o1 + 0x8] %asi, %o2
58: lduwa [%o1 + 0x8] %asi, %o2
jmpl %g1 + %lo(compat_sys_sendmsg), %g0
lduwa [%o1 + 0x4] %asi, %o1
59: lduwa [%o1 + 0x4] %asi, %o1
nop
nop
nop
do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int) */
ldswa [%o1 + 0x0] %asi, %o0
60: ldswa [%o1 + 0x0] %asi, %o0
sethi %hi(compat_sys_recvmsg), %g1
lduwa [%o1 + 0x8] %asi, %o2
61: lduwa [%o1 + 0x8] %asi, %o2
jmpl %g1 + %lo(compat_sys_recvmsg), %g0
lduwa [%o1 + 0x4] %asi, %o1
62: lduwa [%o1 + 0x4] %asi, %o1
nop
nop
nop
__socketcall_table_end:
do_einval:
retl
mov -EINVAL, %o0
do_efault:
retl
mov -EFAULT, %o0
.section __ex_table
.align 4
.word __socketcall_table_begin, 0, __socketcall_table_end, do_efault
.word 1b, __retl_efault, 2b, __retl_efault
.word 3b, __retl_efault, 4b, __retl_efault
.word 5b, __retl_efault, 6b, __retl_efault
.word 7b, __retl_efault, 8b, __retl_efault
.word 9b, __retl_efault, 10b, __retl_efault
.word 11b, __retl_efault, 12b, __retl_efault
.word 13b, __retl_efault, 14b, __retl_efault
.word 15b, __retl_efault, 16b, __retl_efault
.word 17b, __retl_efault, 18b, __retl_efault
.word 19b, __retl_efault, 20b, __retl_efault
.word 21b, __retl_efault, 22b, __retl_efault
.word 23b, __retl_efault, 24b, __retl_efault
.word 25b, __retl_efault, 26b, __retl_efault
.word 27b, __retl_efault, 28b, __retl_efault
.word 29b, __retl_efault, 30b, __retl_efault
.word 31b, __retl_efault, 32b, __retl_efault
.word 33b, __retl_efault, 34b, __retl_efault
.word 35b, __retl_efault, 36b, __retl_efault
.word 37b, __retl_efault, 38b, __retl_efault
.word 39b, __retl_efault, 40b, __retl_efault
.word 41b, __retl_efault, 42b, __retl_efault
.word 43b, __retl_efault, 44b, __retl_efault
.word 45b, __retl_efault, 46b, __retl_efault
.word 47b, __retl_efault, 48b, __retl_efault
.word 49b, __retl_efault, 50b, __retl_efault
.word 51b, __retl_efault, 52b, __retl_efault
.word 53b, __retl_efault, 54b, __retl_efault
.word 55b, __retl_efault, 56b, __retl_efault
.word 57b, __retl_efault, 58b, __retl_efault
.word 59b, __retl_efault, 60b, __retl_efault
.word 61b, __retl_efault, 62b, __retl_efault
.previous
......@@ -189,19 +189,18 @@ void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, un
if (regs->tstate & TSTATE_PRIV) {
/* Test if this comes from uaccess places. */
unsigned long fixup;
unsigned long g2 = regs->u_regs[UREG_G2];
const struct exception_table_entry *entry;
if ((fixup = search_extables_range(regs->tpc, &g2))) {
/* Ouch, somebody is trying ugly VM hole tricks on us... */
entry = search_exception_tables(regs->tpc);
if (entry) {
/* Ouch, somebody is trying VM hole tricks on us... */
#ifdef DEBUG_EXCEPTIONS
printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc);
printk("EX_TABLE: insn<%016lx> fixup<%016lx> "
"g2<%016lx>\n", regs->tpc, fixup, g2);
printk("EX_TABLE: insn<%016lx> fixup<%016lx>\n",
regs->tpc, entry->fixup);
#endif
regs->tpc = fixup;
regs->tpc = entry->fixup;
regs->tnpc = regs->tpc + 4;
regs->u_regs[UREG_G2] = g2;
return;
}
/* Shit... */
......@@ -758,26 +757,12 @@ void __init cheetah_ecache_flush_init(void)
ecache_flush_size = (2 * largest_size);
ecache_flush_linesize = smallest_linesize;
/* Discover a physically contiguous chunk of physical
* memory in 'sp_banks' of size ecache_flush_size calculated
* above. Store the physical base of this area at
* ecache_flush_physbase.
*/
for (node = 0; ; node++) {
if (sp_banks[node].num_bytes == 0)
break;
if (sp_banks[node].num_bytes >= ecache_flush_size) {
ecache_flush_physbase = sp_banks[node].base_addr;
break;
}
}
ecache_flush_physbase = find_ecache_flush_span(ecache_flush_size);
/* Note: Zero would be a valid value of ecache_flush_physbase so
* don't use that as the success test. :-)
*/
if (sp_banks[node].num_bytes == 0) {
if (ecache_flush_physbase == ~0UL) {
prom_printf("cheetah_ecache_flush_init: Cannot find %d byte "
"contiguous physical memory.\n", ecache_flush_size);
"contiguous physical memory.\n",
ecache_flush_size);
prom_halt();
}
......@@ -1346,16 +1331,12 @@ static int cheetah_fix_ce(unsigned long physaddr)
/* Return non-zero if PADDR is a valid physical memory address. */
static int cheetah_check_main_memory(unsigned long paddr)
{
int i;
unsigned long vaddr = PAGE_OFFSET + paddr;
for (i = 0; ; i++) {
if (sp_banks[i].num_bytes == 0)
break;
if (paddr >= sp_banks[i].base_addr &&
paddr < (sp_banks[i].base_addr + sp_banks[i].num_bytes))
return 1;
}
if (vaddr > (unsigned long) high_memory)
return 0;
return kern_addr_valid(vaddr);
}
void cheetah_cee_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
......@@ -1610,10 +1591,10 @@ void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned
/* OK, usermode access. */
recoverable = 1;
} else {
unsigned long g2 = regs->u_regs[UREG_G2];
unsigned long fixup = search_extables_range(regs->tpc, &g2);
const struct exception_table_entry *entry;
if (fixup != 0UL) {
entry = search_exception_tables(regs->tpc);
if (entry) {
/* OK, kernel access to userspace. */
recoverable = 1;
......@@ -1632,9 +1613,8 @@ void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned
* recoverable condition.
*/
if (recoverable) {
regs->tpc = fixup;
regs->tpc = entry->fixup;
regs->tnpc = regs->tpc + 4;
regs->u_regs[UREG_G2] = g2;
}
}
}
......
......@@ -6,13 +6,6 @@
.text
kernel_unaligned_trap_fault:
call kernel_mna_trap_fault
nop
retl
nop
.size kern_unaligned_trap_fault, .-kern_unaligned_trap_fault
.globl __do_int_store
__do_int_store:
rd %asi, %o4
......@@ -51,24 +44,24 @@ __do_int_store:
0:
wr %o4, 0x0, %asi
retl
nop
mov 0, %o0
.size __do_int_store, .-__do_int_store
.section __ex_table
.word 4b, kernel_unaligned_trap_fault
.word 5b, kernel_unaligned_trap_fault
.word 6b, kernel_unaligned_trap_fault
.word 7b, kernel_unaligned_trap_fault
.word 8b, kernel_unaligned_trap_fault
.word 9b, kernel_unaligned_trap_fault
.word 10b, kernel_unaligned_trap_fault
.word 11b, kernel_unaligned_trap_fault
.word 12b, kernel_unaligned_trap_fault
.word 13b, kernel_unaligned_trap_fault
.word 14b, kernel_unaligned_trap_fault
.word 15b, kernel_unaligned_trap_fault
.word 16b, kernel_unaligned_trap_fault
.word 17b, kernel_unaligned_trap_fault
.word 4b, __retl_efault
.word 5b, __retl_efault
.word 6b, __retl_efault
.word 7b, __retl_efault
.word 8b, __retl_efault
.word 9b, __retl_efault
.word 10b, __retl_efault
.word 11b, __retl_efault
.word 12b, __retl_efault
.word 13b, __retl_efault
.word 14b, __retl_efault
.word 15b, __retl_efault
.word 16b, __retl_efault
.word 17b, __retl_efault
.previous
.globl do_int_load
......@@ -133,21 +126,21 @@ do_int_load:
0:
wr %o5, 0x0, %asi
retl
nop
mov 0, %o0
.size __do_int_load, .-__do_int_load
.section __ex_table
.word 4b, kernel_unaligned_trap_fault
.word 5b, kernel_unaligned_trap_fault
.word 6b, kernel_unaligned_trap_fault
.word 7b, kernel_unaligned_trap_fault
.word 8b, kernel_unaligned_trap_fault
.word 9b, kernel_unaligned_trap_fault
.word 10b, kernel_unaligned_trap_fault
.word 11b, kernel_unaligned_trap_fault
.word 12b, kernel_unaligned_trap_fault
.word 13b, kernel_unaligned_trap_fault
.word 14b, kernel_unaligned_trap_fault
.word 15b, kernel_unaligned_trap_fault
.word 16b, kernel_unaligned_trap_fault
.word 4b, __retl_efault
.word 5b, __retl_efault
.word 6b, __retl_efault
.word 7b, __retl_efault
.word 8b, __retl_efault
.word 9b, __retl_efault
.word 10b, __retl_efault
.word 11b, __retl_efault
.word 12b, __retl_efault
.word 13b, __retl_efault
.word 14b, __retl_efault
.word 15b, __retl_efault
.word 16b, __retl_efault
.previous
......@@ -180,13 +180,13 @@ static void __attribute_used__ unaligned_panic(char *str, struct pt_regs *regs)
die_if_kernel(str, regs);
}
extern void do_int_load(unsigned long *dest_reg, int size,
extern int do_int_load(unsigned long *dest_reg, int size,
unsigned long *saddr, int is_signed, int asi);
extern void __do_int_store(unsigned long *dst_addr, int size,
extern int __do_int_store(unsigned long *dst_addr, int size,
unsigned long src_val, int asi);
static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr,
static inline int do_int_store(int reg_num, int size, unsigned long *dst_addr,
struct pt_regs *regs, int asi, int orig_asi)
{
unsigned long zero = 0;
......@@ -219,7 +219,7 @@ static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr,
break;
};
}
__do_int_store(dst_addr, size, src_val, asi);
return __do_int_store(dst_addr, size, src_val, asi);
}
static inline void advance(struct pt_regs *regs)
......@@ -242,14 +242,14 @@ static inline int ok_for_kernel(unsigned int insn)
return !floating_point_load_or_store_p(insn);
}
void kernel_mna_trap_fault(void)
static void kernel_mna_trap_fault(void)
{
struct pt_regs *regs = current_thread_info()->kern_una_regs;
unsigned int insn = current_thread_info()->kern_una_insn;
unsigned long g2 = regs->u_regs[UREG_G2];
unsigned long fixup = search_extables_range(regs->tpc, &g2);
const struct exception_table_entry *entry;
if (!fixup) {
entry = search_exception_tables(regs->tpc);
if (!entry) {
unsigned long address;
address = compute_effective_address(regs, insn,
......@@ -270,9 +270,8 @@ void kernel_mna_trap_fault(void)
die_if_kernel("Oops", regs);
/* Not reached */
}
regs->tpc = fixup;
regs->tpc = entry->fixup;
regs->tnpc = regs->tpc + 4;
regs->u_regs [UREG_G2] = g2;
regs->tstate &= ~TSTATE_ASI;
regs->tstate |= (ASI_AIUS << 24UL);
......@@ -295,7 +294,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
kernel_mna_trap_fault();
} else {
unsigned long addr, *reg_addr;
int orig_asi, asi;
int orig_asi, asi, err;
addr = compute_effective_address(regs, insn,
((insn >> 25) & 0x1f));
......@@ -320,9 +319,10 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
switch (dir) {
case load:
reg_addr = fetch_reg_addr(((insn>>25)&0x1f), regs);
do_int_load(reg_addr, size, (unsigned long *) addr,
err = do_int_load(reg_addr, size,
(unsigned long *) addr,
decode_signedness(insn), asi);
if (unlikely(asi != orig_asi)) {
if (likely(!err) && unlikely(asi != orig_asi)) {
unsigned long val_in = *reg_addr;
switch (size) {
case 2:
......@@ -344,7 +344,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
break;
case store:
do_int_store(((insn>>25)&0x1f), size,
err = do_int_store(((insn>>25)&0x1f), size,
(unsigned long *) addr, regs,
asi, orig_asi);
break;
......@@ -353,6 +353,9 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
panic("Impossible kernel unaligned trap.");
/* Not reached... */
}
if (unlikely(err))
kernel_mna_trap_fault();
else
advance(regs);
}
}
......
......@@ -125,15 +125,11 @@ __strncpy_from_user:
add %o2, %o3, %o0
.size __strncpy_from_user, .-__strncpy_from_user
.section .fixup,#alloc,#execinstr
.align 4
4: retl
mov -EFAULT, %o0
.section __ex_table,#alloc
.align 4
.word 60b, 4b
.word 61b, 4b
.word 62b, 4b
.word 63b, 4b
.word 64b, 4b
.word 60b, __retl_efault
.word 61b, __retl_efault
.word 62b, __retl_efault
.word 63b, __retl_efault
.word 64b, __retl_efault
.previous
......@@ -11,61 +11,56 @@
/* Calculating the exact fault address when using
* block loads and stores can be very complicated.
*
* Instead of trying to be clever and handling all
* of the cases, just fix things up simply here.
*/
unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size)
static unsigned long compute_size(unsigned long start, unsigned long size, unsigned long *offset)
{
char *dst = to;
const char __user *src = from;
unsigned long fault_addr = current_thread_info()->fault_address;
unsigned long end = start + size;
while (size) {
if (__get_user(*dst, src))
break;
dst++;
src++;
size--;
if (fault_addr < start || fault_addr >= end) {
*offset = 0;
} else {
*offset = start - fault_addr;
size = end - fault_addr;
}
return size;
}
if (size)
memset(dst, 0, size);
unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size)
{
unsigned long offset;
size = compute_size((unsigned long) from, size, &offset);
if (likely(size))
memset(to + offset, 0, size);
return size;
}
unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size)
{
char __user *dst = to;
const char *src = from;
while (size) {
if (__put_user(*src, dst))
break;
dst++;
src++;
size--;
}
unsigned long offset;
return size;
return compute_size((unsigned long) to, size, &offset);
}
unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size)
{
char __user *dst = to;
char __user *src = from;
unsigned long fault_addr = current_thread_info()->fault_address;
unsigned long start = (unsigned long) to;
unsigned long end = start + size;
while (size) {
char tmp;
if (fault_addr >= start && fault_addr < end)
return end - fault_addr;
if (__get_user(tmp, src))
break;
if (__put_user(tmp, dst))
break;
dst++;
src++;
size--;
}
start = (unsigned long) from;
end = start + size;
if (fault_addr >= start && fault_addr < end)
return end - fault_addr;
return size;
}
......@@ -5,6 +5,6 @@
EXTRA_AFLAGS := -ansi
EXTRA_CFLAGS := -Werror
obj-y := ultra.o tlb.o fault.o init.o generic.o extable.o
obj-y := ultra.o tlb.o fault.o init.o generic.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
/*
* linux/arch/sparc64/mm/extable.c
*/
#include <linux/config.h>
#include <linux/module.h>
#include <asm/uaccess.h>
extern const struct exception_table_entry __start___ex_table[];
extern const struct exception_table_entry __stop___ex_table[];
void sort_extable(struct exception_table_entry *start,
struct exception_table_entry *finish)
{
}
/* Caller knows they are in a range if ret->fixup == 0 */
const struct exception_table_entry *
search_extable(const struct exception_table_entry *start,
const struct exception_table_entry *last,
unsigned long value)
{
const struct exception_table_entry *walk;
/* Single insn entries are encoded as:
* word 1: insn address
* word 2: fixup code address
*
* Range entries are encoded as:
* word 1: first insn address
* word 2: 0
* word 3: last insn address + 4 bytes
* word 4: fixup code address
*
* See asm/uaccess.h for more details.
*/
/* 1. Try to find an exact match. */
for (walk = start; walk <= last; walk++) {
if (walk->fixup == 0) {
/* A range entry, skip both parts. */
walk++;
continue;
}
if (walk->insn == value)
return walk;
}
/* 2. Try to find a range match. */
for (walk = start; walk <= (last - 1); walk++) {
if (walk->fixup)
continue;
if (walk[0].insn <= value && walk[1].insn > value)
return walk;
walk++;
}
return NULL;
}
/* Special extable search, which handles ranges. Returns fixup */
unsigned long search_extables_range(unsigned long addr, unsigned long *g2)
{
const struct exception_table_entry *entry;
entry = search_exception_tables(addr);
if (!entry)
return 0;
/* Inside range? Fix g2 and return correct fixup */
if (!entry->fixup) {
*g2 = (addr - entry->insn) / 4;
return (entry + 1)->fixup;
}
return entry->fixup;
}
......@@ -32,8 +32,6 @@
#define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
/*
* To debug kernel to catch accesses to certain virtual/physical addresses.
* Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.
......@@ -71,53 +69,6 @@ void set_brkpt(unsigned long addr, unsigned char mask, int flags, int mode)
: "memory");
}
/* Nice, simple, prom library does all the sweating for us. ;) */
unsigned long __init prom_probe_memory (void)
{
register struct linux_mlist_p1275 *mlist;
register unsigned long bytes, base_paddr, tally;
register int i;
i = 0;
mlist = *prom_meminfo()->p1275_available;
bytes = tally = mlist->num_bytes;
base_paddr = mlist->start_adr;
sp_banks[0].base_addr = base_paddr;
sp_banks[0].num_bytes = bytes;
while (mlist->theres_more != (void *) 0) {
i++;
mlist = mlist->theres_more;
bytes = mlist->num_bytes;
tally += bytes;
if (i >= SPARC_PHYS_BANKS-1) {
printk ("The machine has more banks than "
"this kernel can support\n"
"Increase the SPARC_PHYS_BANKS "
"setting (currently %d)\n",
SPARC_PHYS_BANKS);
i = SPARC_PHYS_BANKS-1;
break;
}
sp_banks[i].base_addr = mlist->start_adr;
sp_banks[i].num_bytes = mlist->num_bytes;
}
i++;
sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL;
sp_banks[i].num_bytes = 0;
/* Now mask all bank sizes on a page boundary, it is all we can
* use anyways.
*/
for (i = 0; sp_banks[i].num_bytes != 0; i++)
sp_banks[i].num_bytes &= PAGE_MASK;
return tally;
}
static void __kprobes unhandled_fault(unsigned long address,
struct task_struct *tsk,
struct pt_regs *regs)
......@@ -242,7 +193,6 @@ static unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn)
static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
unsigned int insn, unsigned long address)
{
unsigned long g2;
unsigned char asi = ASI_P;
if ((!insn) && (regs->tstate & TSTATE_PRIV))
......@@ -273,11 +223,9 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
}
}
g2 = regs->u_regs[UREG_G2];
/* Is this in ex_table? */
if (regs->tstate & TSTATE_PRIV) {
unsigned long fixup;
const struct exception_table_entry *entry;
if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) {
if (insn & 0x2000)
......@@ -288,10 +236,9 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
/* Look in asi.h: All _S asis have LS bit set */
if ((asi & 0x1) &&
(fixup = search_extables_range(regs->tpc, &g2))) {
regs->tpc = fixup;
(entry = search_exception_tables(regs->tpc))) {
regs->tpc = entry->fixup;
regs->tnpc = regs->tpc + 4;
regs->u_regs[UREG_G2] = g2;
return;
}
} else {
......@@ -461,7 +408,7 @@ good_area:
}
up_read(&mm->mmap_sem);
goto fault_done;
return;
/*
* Something tried to access memory that isn't in our memory map..
......@@ -473,8 +420,7 @@ bad_area:
handle_kernel_fault:
do_kernel_fault(regs, si_code, fault_code, insn, address);
goto fault_done;
return;
/*
* We ran out of memory, or some other thing happened to us that made
......@@ -505,9 +451,4 @@ do_sigbus:
/* Kernel mode? Handle exceptions or die */
if (regs->tstate & TSTATE_PRIV)
goto handle_kernel_fault;
fault_done:
/* These values are no longer needed, clear them. */
set_thread_fault_code(0);
current_thread_info()->fault_address = 0;
}
This diff is collapsed.
......@@ -6,5 +6,5 @@
EXTRA_AFLAGS := -ansi
EXTRA_CFLAGS := -Werror
lib-y := bootstr.o devops.o init.o memory.o misc.o \
lib-y := bootstr.o devops.o init.o misc.o \
tree.o console.o printf.o p1275.o cif.o
......@@ -27,7 +27,6 @@ int prom_chosen_node;
* failure. It gets passed the pointer to the PROM vector.
*/
extern void prom_meminit(void);
extern void prom_cif_init(void *, void *);
void __init prom_init(void *cif_handler, void *cif_stack)
......@@ -90,8 +89,6 @@ void __init prom_init(void *cif_handler, void *cif_stack)
printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + bufadjust);
prom_meminit();
/* Initialization successful. */
return;
......
/* $Id: memory.c,v 1.5 1999/08/31 06:55:04 davem Exp $
* memory.c: Prom routine for acquiring various bits of information
* about RAM on the machine, both virtual and physical.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
/* This routine, for consistency, returns the ram parameters in the
* V0 prom memory descriptor format. I choose this format because I
* think it was the easiest to work with. I feel the religious
* arguments now... ;) Also, I return the linked lists sorted to
* prevent paging_init() upset stomach as I have not yet written
* the pepto-bismol kernel module yet.
*/
struct linux_prom64_registers prom_reg_memlist[64];
struct linux_prom64_registers prom_reg_tmp[64];
struct linux_mlist_p1275 prom_phys_total[64];
struct linux_mlist_p1275 prom_prom_taken[64];
struct linux_mlist_p1275 prom_phys_avail[64];
struct linux_mlist_p1275 *prom_ptot_ptr = prom_phys_total;
struct linux_mlist_p1275 *prom_ptak_ptr = prom_prom_taken;
struct linux_mlist_p1275 *prom_pavl_ptr = prom_phys_avail;
struct linux_mem_p1275 prom_memlist;
/* Internal Prom library routine to sort a linux_mlist_p1275 memory
* list. Used below in initialization.
*/
static void __init
prom_sortmemlist(struct linux_mlist_p1275 *thislist)
{
int swapi = 0;
int i, mitr;
unsigned long tmpaddr, tmpsize;
unsigned long lowest;
for(i=0; thislist[i].theres_more; i++) {
lowest = thislist[i].start_adr;
for(mitr = i+1; thislist[mitr-1].theres_more; mitr++)
if(thislist[mitr].start_adr < lowest) {
lowest = thislist[mitr].start_adr;
swapi = mitr;
}
if(lowest == thislist[i].start_adr) continue;
tmpaddr = thislist[swapi].start_adr;
tmpsize = thislist[swapi].num_bytes;
for(mitr = swapi; mitr > i; mitr--) {
thislist[mitr].start_adr = thislist[mitr-1].start_adr;
thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;
}
thislist[i].start_adr = tmpaddr;
thislist[i].num_bytes = tmpsize;
}
}
/* Initialize the memory lists based upon the prom version. */
void __init prom_meminit(void)
{
int node = 0;
unsigned int iter, num_regs;
node = prom_finddevice("/memory");
num_regs = prom_getproperty(node, "available",
(char *) prom_reg_memlist,
sizeof(prom_reg_memlist));
num_regs = (num_regs/sizeof(struct linux_prom64_registers));
for(iter=0; iter<num_regs; iter++) {
prom_phys_avail[iter].start_adr =
prom_reg_memlist[iter].phys_addr;
prom_phys_avail[iter].num_bytes =
prom_reg_memlist[iter].reg_size;
prom_phys_avail[iter].theres_more =
&prom_phys_avail[iter+1];
}
prom_phys_avail[iter-1].theres_more = NULL;
num_regs = prom_getproperty(node, "reg",
(char *) prom_reg_memlist,
sizeof(prom_reg_memlist));
num_regs = (num_regs/sizeof(struct linux_prom64_registers));
for(iter=0; iter<num_regs; iter++) {
prom_phys_total[iter].start_adr =
prom_reg_memlist[iter].phys_addr;
prom_phys_total[iter].num_bytes =
prom_reg_memlist[iter].reg_size;
prom_phys_total[iter].theres_more =
&prom_phys_total[iter+1];
}
prom_phys_total[iter-1].theres_more = NULL;
node = prom_finddevice("/virtual-memory");
num_regs = prom_getproperty(node, "available",
(char *) prom_reg_memlist,
sizeof(prom_reg_memlist));
num_regs = (num_regs/sizeof(struct linux_prom64_registers));
/* Convert available virtual areas to taken virtual
* areas. First sort, then convert.
*/
for(iter=0; iter<num_regs; iter++) {
prom_prom_taken[iter].start_adr =
prom_reg_memlist[iter].phys_addr;
prom_prom_taken[iter].num_bytes =
prom_reg_memlist[iter].reg_size;
prom_prom_taken[iter].theres_more =
&prom_prom_taken[iter+1];
}
prom_prom_taken[iter-1].theres_more = NULL;
prom_sortmemlist(prom_prom_taken);
/* Finally, convert. */
for(iter=0; iter<num_regs; iter++) {
prom_prom_taken[iter].start_adr =
prom_prom_taken[iter].start_adr +
prom_prom_taken[iter].num_bytes;
prom_prom_taken[iter].num_bytes =
prom_prom_taken[iter+1].start_adr -
prom_prom_taken[iter].start_adr;
}
prom_prom_taken[iter-1].num_bytes =
-1UL - prom_prom_taken[iter-1].start_adr;
/* Sort the other two lists. */
prom_sortmemlist(prom_phys_total);
prom_sortmemlist(prom_phys_avail);
/* Link all the lists into the top-level descriptor. */
prom_memlist.p1275_totphys=&prom_ptot_ptr;
prom_memlist.p1275_prommap=&prom_ptak_ptr;
prom_memlist.p1275_available=&prom_pavl_ptr;
}
/* This returns a pointer to our libraries internal p1275 format
* memory descriptor.
*/
struct linux_mem_p1275 *
prom_meminfo(void)
{
return &prom_memlist;
}
......@@ -475,7 +475,7 @@ static int __devinit radeon_probe_pll_params(struct radeonfb_info *rinfo)
*/
/* Flush PCI buffers ? */
tmp = INREG(DEVICE_ID);
tmp = INREG16(DEVICE_ID);
local_irq_disable();
......
......@@ -395,6 +395,8 @@ static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
#define INREG8(addr) readb((rinfo->mmio_base)+addr)
#define OUTREG8(addr,val) writeb(val, (rinfo->mmio_base)+addr)
#define INREG16(addr) readw((rinfo->mmio_base)+addr)
#define OUTREG16(addr,val) writew(val, (rinfo->mmio_base)+addr)
#define INREG(addr) readl((rinfo->mmio_base)+addr)
#define OUTREG(addr,val) writel(val, (rinfo->mmio_base)+addr)
......
......@@ -82,6 +82,8 @@ extern unsigned long page_kernel;
/* Top-level page directory */
extern pgd_t swapper_pg_dir[1024];
extern void paging_init(void);
/* Page table for 0-4MB for everybody, on the Sparc this
* holds the same as on the i386.
*/
......
......@@ -186,8 +186,8 @@ struct linux_prom_registers {
};
struct linux_prom64_registers {
long phys_addr;
long reg_size;
unsigned long phys_addr;
unsigned long reg_size;
};
struct linux_prom_irqs {
......
......@@ -95,20 +95,6 @@ extern int prom_devclose(int device_handle);
extern void prom_seek(int device_handle, unsigned int seek_hival,
unsigned int seek_lowval);
/* Machine memory configuration routine. */
/* This function returns a V0 format memory descriptor table, it has three
* entries. One for the total amount of physical ram on the machine, one
* for the amount of physical ram available, and one describing the virtual
* areas which are allocated by the prom. So, in a sense the physical
* available is a calculation of the total physical minus the physical mapped
* by the prom with virtual mappings.
*
* These lists are returned pre-sorted, this should make your life easier
* since the prom itself is way too lazy to do such nice things.
*/
extern struct linux_mem_p1275 *prom_meminfo(void);
/* Miscellaneous routines, don't really fit in any category per se. */
/* Reboot the machine with the command line passed. */
......
......@@ -140,23 +140,6 @@ extern unsigned long page_to_pfn(struct page *);
#define virt_to_phys __pa
#define phys_to_virt __va
/* The following structure is used to hold the physical
* memory configuration of the machine. This is filled in
* probe_memory() and is later used by mem_init() to set up
* mem_map[]. We statically allocate SPARC_PHYS_BANKS of
* these structs, this is arbitrary. The entry after the
* last valid one has num_bytes==0.
*/
struct sparc_phys_banks {
unsigned long base_addr;
unsigned long num_bytes;
};
#define SPARC_PHYS_BANKS 32
extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
#endif /* !(__ASSEMBLY__) */
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
......
......@@ -341,6 +341,9 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *p
extern pgd_t swapper_pg_dir[2048];
extern pmd_t swapper_low_pmd_dir[2048];
extern void paging_init(void);
extern unsigned long find_ecache_flush_span(unsigned long size);
/* These do nothing with the way I have things setup. */
#define mmu_lockarea(vaddr, len) (vaddr)
#define mmu_unlockarea(vaddr, len) do { } while(0)
......
......@@ -70,26 +70,14 @@ static inline int access_ok(int type, const void __user * addr, unsigned long si
* 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 insn, fixup;
struct exception_table_entry {
unsigned int insn, fixup;
};
/* Special exable search, which handles ranges. Returns fixup */
unsigned long search_extables_range(unsigned long addr, unsigned long *g2);
extern void __ret_efault(void);
extern void __retl_efault(void);
/* Uh, these should become the main single-value transfer routines..
* They automatically use the right size if we just have the right
......@@ -263,7 +251,7 @@ copy_from_user(void *to, const void __user *from, unsigned long size)
{
unsigned long ret = ___copy_from_user(to, from, size);
if (ret)
if (unlikely(ret))
ret = copy_from_user_fixup(to, from, size);
return ret;
}
......@@ -279,7 +267,7 @@ copy_to_user(void __user *to, const void *from, unsigned long size)
{
unsigned long ret = ___copy_to_user(to, from, size);
if (ret)
if (unlikely(ret))
ret = copy_to_user_fixup(to, from, size);
return ret;
}
......@@ -295,7 +283,7 @@ copy_in_user(void __user *to, void __user *from, unsigned long size)
{
unsigned long ret = ___copy_in_user(to, from, size);
if (ret)
if (unlikely(ret))
ret = copy_in_user_fixup(to, from, size);
return ret;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment