Commit 05bdb8c9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'xtensa-20140830' of git://github.com/czankel/xtensa-linux

Pull Xtensa updates from Chris Zankel:
 "Xtensa improvements for 3.17:
   - support highmem on cores with aliasing data cache.  Enable highmem
     on kc705 by default
   - simplify addition of new core variants (no need to modify Kconfig /
     Makefiles)
   - improve robustness of unaligned access handler and its interaction
     with window overflow/underflow exception handlers
   - deprecate atomic and spill registers syscalls
   - clean up Kconfig: remove orphan MATH_EMULATION, sort 'select'
     statements
   - wire up renameat2 syscall.

  Various fixes:
   - fix address checks in dma_{alloc,free}_coherent (runtime BUG)
   - fix access to THREAD_RA/THREAD_SP/THREAD_DS (debug build breakage)
   - fix TLBTEMP_BASE_2 region handling in fast_second_level_miss
     (runtime unrecoverable exception)
   - fix a6 and a7 handling in fast_syscall_xtensa (runtime userspace
     register clobbering)
   - fix kernel/user jump out of fast_unaligned (potential runtime
     unrecoverabl exception)
   - replace termios IOCTL code definitions with constants (userspace
     build breakage)"

* tag 'xtensa-20140830' of git://github.com/czankel/xtensa-linux: (25 commits)
  xtensa: deprecate fast_xtensa and fast_spill_registers syscalls
  xtensa: don't allow overflow/underflow on unaligned stack
  xtensa: fix a6 and a7 handling in fast_syscall_xtensa
  xtensa: allow single-stepping through unaligned load/store
  xtensa: move invalid unaligned instruction handler closer to its users
  xtensa: make fast_unaligned store restartable
  xtensa: add double exception fixup handler for fast_unaligned
  xtensa: fix kernel/user jump out of fast_unaligned
  xtensa: configure kc705 for highmem
  xtensa: support highmem in aliasing cache flushing code
  xtensa: support aliasing cache in kmap
  xtensa: support aliasing cache in k[un]map_atomic
  xtensa: implement clear_user_highpage and copy_user_highpage
  xtensa: fix TLBTEMP_BASE_2 region handling in fast_second_level_miss
  xtensa: allow fixmap and kmap span more than one page table
  xtensa: make fixmap region addressing grow with index
  xtensa: fix access to THREAD_RA/THREAD_SP/THREAD_DS
  xtensa: add renameat2 syscall
  xtensa: fix address checks in dma_{alloc,free}_coherent
  xtensa: replace IOCTL code definitions with constants
  ...
parents ca98565a e792290b
......@@ -4,24 +4,23 @@ config ZONE_DMA
config XTENSA
def_bool y
select ARCH_WANT_FRAME_POINTERS
select HAVE_IDE
select GENERIC_ATOMIC64
select GENERIC_CLOCKEVENTS
select VIRT_TO_BUS
select GENERIC_IRQ_SHOW
select GENERIC_SCHED_CLOCK
select MODULES_USE_ELF_RELA
select GENERIC_PCI_IOMAP
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_WANT_OPTIONAL_GPIOLIB
select BUILDTIME_EXTABLE_SORT
select CLONE_BACKWARDS
select IRQ_DOMAIN
select HAVE_OPROFILE
select COMMON_CLK
select GENERIC_ATOMIC64
select GENERIC_CLOCKEVENTS
select GENERIC_IRQ_SHOW
select GENERIC_PCI_IOMAP
select GENERIC_SCHED_CLOCK
select HAVE_FUNCTION_TRACER
select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_OPROFILE
select HAVE_PERF_EVENTS
select COMMON_CLK
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
select VIRT_TO_BUS
help
Xtensa processors are 32-bit RISC machines designed by Tensilica
primarily for embedded systems. These processors are both
......@@ -62,7 +61,9 @@ config TRACE_IRQFLAGS_SUPPORT
def_bool y
config MMU
def_bool n
bool
default n if !XTENSA_VARIANT_CUSTOM
default XTENSA_VARIANT_MMU if XTENSA_VARIANT_CUSTOM
config VARIANT_IRQ_SWITCH
def_bool n
......@@ -102,8 +103,40 @@ config XTENSA_VARIANT_S6000
select VARIANT_IRQ_SWITCH
select ARCH_REQUIRE_GPIOLIB
select XTENSA_CALIBRATE_CCOUNT
config XTENSA_VARIANT_CUSTOM
bool "Custom Xtensa processor configuration"
select MAY_HAVE_SMP
select HAVE_XTENSA_GPIO32
help
Select this variant to use a custom Xtensa processor configuration.
You will be prompted for a processor variant CORENAME.
endchoice
config XTENSA_VARIANT_CUSTOM_NAME
string "Xtensa Processor Custom Core Variant Name"
depends on XTENSA_VARIANT_CUSTOM
help
Provide the name of a custom Xtensa processor variant.
This CORENAME selects arch/xtensa/variant/CORENAME.
Dont forget you have to select MMU if you have one.
config XTENSA_VARIANT_NAME
string
default "dc232b" if XTENSA_VARIANT_DC232B
default "dc233c" if XTENSA_VARIANT_DC233C
default "fsf" if XTENSA_VARIANT_FSF
default "s6000" if XTENSA_VARIANT_S6000
default XTENSA_VARIANT_CUSTOM_NAME if XTENSA_VARIANT_CUSTOM
config XTENSA_VARIANT_MMU
bool "Core variant has a Full MMU (TLB, Pages, Protection, etc)"
depends on XTENSA_VARIANT_CUSTOM
default y
help
Build a Conventional Kernel with full MMU support,
ie: it supports a TLB with auto-loading, page protection.
config XTENSA_UNALIGNED_USER
bool "Unaligned memory access in use space"
help
......@@ -156,13 +189,9 @@ config HOTPLUG_CPU
Say N if you want to disable CPU hotplug.
config MATH_EMULATION
bool "Math emulation"
help
Can we use information of configuration file?
config INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
bool "Initialize Xtensa MMU inside the Linux kernel code"
depends on MMU
default y
help
Earlier version initialized the MMU in the exception vector
......@@ -192,6 +221,7 @@ config INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
config HIGHMEM
bool "High Memory Support"
depends on MMU
help
Linux can use the full amount of RAM in the system by
default. However, the default MMUv2 setup only maps the
......@@ -208,6 +238,32 @@ config HIGHMEM
If unsure, say Y.
config FAST_SYSCALL_XTENSA
bool "Enable fast atomic syscalls"
default n
help
fast_syscall_xtensa is a syscall that can make atomic operations
on UP kernel when processor has no s32c1i support.
This syscall is deprecated. It may have issues when called with
invalid arguments. It is provided only for backwards compatibility.
Only enable it if your userspace software requires it.
If unsure, say N.
config FAST_SYSCALL_SPILL_REGISTERS
bool "Enable spill registers syscall"
default n
help
fast_syscall_spill_registers is a syscall that spills all active
register windows of a calling userspace task onto its stack.
This syscall is deprecated. It may have issues when called with
invalid arguments. It is provided only for backwards compatibility.
Only enable it if your userspace software requires it.
If unsure, say N.
endmenu
config XTENSA_CALIBRATE_CCOUNT
......@@ -250,12 +306,14 @@ config XTENSA_PLATFORM_ISS
config XTENSA_PLATFORM_XT2000
bool "XT2000"
select HAVE_IDE
help
XT2000 is the name of Tensilica's feature-rich emulation platform.
This hardware is capable of running a full Linux distribution.
config XTENSA_PLATFORM_S6105
bool "S6105"
select HAVE_IDE
select SERIAL_CONSOLE
select NO_IOPORT_MAP
......
......@@ -4,6 +4,7 @@
# for more details.
#
# Copyright (C) 2001 - 2005 Tensilica Inc.
# Copyright (C) 2014 Cadence Design Systems Inc.
#
# This file is included by the global makefile so that you can add your own
# architecture-specific flags and dependencies. Remember to do have actions
......@@ -13,11 +14,7 @@
# Core configuration.
# (Use VAR=<xtensa_config> to use another default compiler.)
variant-$(CONFIG_XTENSA_VARIANT_FSF) := fsf
variant-$(CONFIG_XTENSA_VARIANT_DC232B) := dc232b
variant-$(CONFIG_XTENSA_VARIANT_DC233C) := dc233c
variant-$(CONFIG_XTENSA_VARIANT_S6000) := s6000
variant-$(CONFIG_XTENSA_VARIANT_LINUX_CUSTOM) := custom
variant-y := $(patsubst "%",%,$(CONFIG_XTENSA_VARIANT_NAME))
VARIANT = $(variant-y)
export VARIANT
......
......@@ -4,8 +4,11 @@
/ {
compatible = "cdns,xtensa-kc705";
chosen {
bootargs = "earlycon=uart8250,mmio32,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug memmap=0x38000000";
};
memory@0 {
device_type = "memory";
reg = <0x00000000 0x08000000>;
reg = <0x00000000 0x38000000>;
};
};
......@@ -66,7 +66,6 @@ CONFIG_XTENSA_ARCH_LINUX_BE=y
CONFIG_MMU=y
# CONFIG_XTENSA_UNALIGNED_USER is not set
# CONFIG_PREEMPT is not set
# CONFIG_MATH_EMULATION is not set
# CONFIG_HIGHMEM is not set
#
......
......@@ -146,7 +146,6 @@ CONFIG_XTENSA_VARIANT_FSF=y
# CONFIG_XTENSA_VARIANT_S6000 is not set
# CONFIG_XTENSA_UNALIGNED_USER is not set
# CONFIG_PREEMPT is not set
# CONFIG_MATH_EMULATION is not set
CONFIG_XTENSA_CALIBRATE_CCOUNT=y
CONFIG_SERIAL_CONSOLE=y
CONFIG_XTENSA_ISS_NETWORK=y
......@@ -308,7 +307,7 @@ CONFIG_MISC_DEVICES=y
# EEPROM support
#
# CONFIG_EEPROM_93CX6 is not set
CONFIG_HAVE_IDE=y
# CONFIG_HAVE_IDE is not set
# CONFIG_IDE is not set
#
......
......@@ -109,7 +109,6 @@ CONFIG_VARIANT_IRQ_SWITCH=y
CONFIG_XTENSA_VARIANT_S6000=y
# CONFIG_XTENSA_UNALIGNED_USER is not set
CONFIG_PREEMPT=y
# CONFIG_MATH_EMULATION is not set
# CONFIG_HIGHMEM is not set
CONFIG_XTENSA_CALIBRATE_CCOUNT=y
CONFIG_SERIAL_CONSOLE=y
......
......@@ -37,6 +37,7 @@
* specials for cache aliasing:
*
* __flush_invalidate_dcache_page_alias(vaddr,paddr)
* __invalidate_dcache_page_alias(vaddr,paddr)
* __invalidate_icache_page_alias(vaddr,paddr)
*/
......@@ -62,6 +63,7 @@ extern void __flush_invalidate_dcache_range(unsigned long, unsigned long);
#if defined(CONFIG_MMU) && (DCACHE_WAY_SIZE > PAGE_SIZE)
extern void __flush_invalidate_dcache_page_alias(unsigned long, unsigned long);
extern void __invalidate_dcache_page_alias(unsigned long, unsigned long);
#else
static inline void __flush_invalidate_dcache_page_alias(unsigned long virt,
unsigned long phys) { }
......
......@@ -23,8 +23,8 @@
* Here we define all the compile-time 'special' virtual
* addresses. The point is to have a constant address at
* compile time, but to set the physical address only
* in the boot process. We allocate these special addresses
* from the end of the consistent memory region backwards.
* in the boot process. We allocate these special addresses
* from the start of the consistent memory region upwards.
* Also this lets us do fail-safe vmalloc(), we
* can guarantee that these special addresses and
* vmalloc()-ed addresses never overlap.
......@@ -38,7 +38,8 @@ enum fixed_addresses {
#ifdef CONFIG_HIGHMEM
/* reserved pte's for temporary kernel mappings */
FIX_KMAP_BEGIN,
FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS) - 1,
FIX_KMAP_END = FIX_KMAP_BEGIN +
(KM_TYPE_NR * NR_CPUS * DCACHE_N_COLORS) - 1,
#endif
__end_of_fixed_addresses
};
......@@ -47,7 +48,28 @@ enum fixed_addresses {
#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_START ((FIXADDR_TOP - FIXADDR_SIZE) & PMD_MASK)
#include <asm-generic/fixmap.h>
#define __fix_to_virt(x) (FIXADDR_START + ((x) << PAGE_SHIFT))
#define __virt_to_fix(x) (((x) - FIXADDR_START) >> PAGE_SHIFT)
#ifndef __ASSEMBLY__
/*
* 'index to address' translation. If anyone tries to use the idx
* directly without translation, we catch the bug with a NULL-deference
* kernel oops. Illegal ranges of incoming indices are caught too.
*/
static __always_inline unsigned long fix_to_virt(const unsigned int idx)
{
BUILD_BUG_ON(idx >= __end_of_fixed_addresses);
return __fix_to_virt(idx);
}
static inline unsigned long virt_to_fix(const unsigned long vaddr)
{
BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
return __virt_to_fix(vaddr);
}
#endif
#define kmap_get_fixmap_pte(vaddr) \
pte_offset_kernel( \
......
......@@ -12,19 +12,55 @@
#ifndef _XTENSA_HIGHMEM_H
#define _XTENSA_HIGHMEM_H
#include <linux/wait.h>
#include <asm/cacheflush.h>
#include <asm/fixmap.h>
#include <asm/kmap_types.h>
#include <asm/pgtable.h>
#define PKMAP_BASE (FIXADDR_START - PMD_SIZE)
#define LAST_PKMAP PTRS_PER_PTE
#define PKMAP_BASE ((FIXADDR_START - \
(LAST_PKMAP + 1) * PAGE_SIZE) & PMD_MASK)
#define LAST_PKMAP (PTRS_PER_PTE * DCACHE_N_COLORS)
#define LAST_PKMAP_MASK (LAST_PKMAP - 1)
#define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
#define kmap_prot PAGE_KERNEL
#if DCACHE_WAY_SIZE > PAGE_SIZE
#define get_pkmap_color get_pkmap_color
static inline int get_pkmap_color(struct page *page)
{
return DCACHE_ALIAS(page_to_phys(page));
}
extern unsigned int last_pkmap_nr_arr[];
static inline unsigned int get_next_pkmap_nr(unsigned int color)
{
last_pkmap_nr_arr[color] =
(last_pkmap_nr_arr[color] + DCACHE_N_COLORS) & LAST_PKMAP_MASK;
return last_pkmap_nr_arr[color] + color;
}
static inline int no_more_pkmaps(unsigned int pkmap_nr, unsigned int color)
{
return pkmap_nr < DCACHE_N_COLORS;
}
static inline int get_pkmap_entries_count(unsigned int color)
{
return LAST_PKMAP / DCACHE_N_COLORS;
}
extern wait_queue_head_t pkmap_map_wait_arr[];
static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color)
{
return pkmap_map_wait_arr + color;
}
#endif
extern pte_t *pkmap_page_table;
void *kmap_high(struct page *page);
......
......@@ -78,7 +78,9 @@
# define DCACHE_ALIAS_EQ(a,b) ((((a) ^ (b)) & DCACHE_ALIAS_MASK) == 0)
#else
# define DCACHE_ALIAS_ORDER 0
# define DCACHE_ALIAS(a) ((void)(a), 0)
#endif
#define DCACHE_N_COLORS (1 << DCACHE_ALIAS_ORDER)
#if ICACHE_WAY_SIZE > PAGE_SIZE
# define ICACHE_ALIAS_ORDER (ICACHE_WAY_SHIFT - PAGE_SHIFT)
......@@ -134,6 +136,7 @@ static inline __attribute_const__ int get_order(unsigned long size)
#endif
struct page;
struct vm_area_struct;
extern void clear_page(void *page);
extern void copy_page(void *to, void *from);
......@@ -143,8 +146,15 @@ extern void copy_page(void *to, void *from);
*/
#if DCACHE_WAY_SIZE > PAGE_SIZE
extern void clear_user_page(void*, unsigned long, struct page*);
extern void copy_user_page(void*, void*, unsigned long, struct page*);
extern void clear_page_alias(void *vaddr, unsigned long paddr);
extern void copy_page_alias(void *to, void *from,
unsigned long to_paddr, unsigned long from_paddr);
#define clear_user_highpage clear_user_highpage
void clear_user_highpage(struct page *page, unsigned long vaddr);
#define __HAVE_ARCH_COPY_USER_HIGHPAGE
void copy_user_highpage(struct page *to, struct page *from,
unsigned long vaddr, struct vm_area_struct *vma);
#else
# define clear_user_page(page, vaddr, pg) clear_page(page)
# define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
......
......@@ -67,7 +67,12 @@
#define VMALLOC_START 0xC0000000
#define VMALLOC_END 0xC7FEFFFF
#define TLBTEMP_BASE_1 0xC7FF0000
#define TLBTEMP_BASE_2 0xC7FF8000
#define TLBTEMP_BASE_2 (TLBTEMP_BASE_1 + DCACHE_WAY_SIZE)
#if 2 * DCACHE_WAY_SIZE > ICACHE_WAY_SIZE
#define TLBTEMP_SIZE (2 * DCACHE_WAY_SIZE)
#else
#define TLBTEMP_SIZE ICACHE_WAY_SIZE
#endif
/*
* For the Xtensa architecture, the PTE layout is as follows:
......
......@@ -52,7 +52,12 @@
*/
.macro get_fs ad, sp
GET_CURRENT(\ad,\sp)
#if THREAD_CURRENT_DS > 1020
addi \ad, \ad, TASK_THREAD
l32i \ad, \ad, THREAD_CURRENT_DS - TASK_THREAD
#else
l32i \ad, \ad, THREAD_CURRENT_DS
#endif
.endm
/*
......
......@@ -28,17 +28,17 @@
#define TCSETSW 0x5403
#define TCSETSF 0x5404
#define TCGETA _IOR('t', 23, struct termio)
#define TCSETA _IOW('t', 24, struct termio)
#define TCSETAW _IOW('t', 25, struct termio)
#define TCSETAF _IOW('t', 28, struct termio)
#define TCGETA 0x80127417 /* _IOR('t', 23, struct termio) */
#define TCSETA 0x40127418 /* _IOW('t', 24, struct termio) */
#define TCSETAW 0x40127419 /* _IOW('t', 25, struct termio) */
#define TCSETAF 0x4012741C /* _IOW('t', 28, struct termio) */
#define TCSBRK _IO('t', 29)
#define TCXONC _IO('t', 30)
#define TCFLSH _IO('t', 31)
#define TIOCSWINSZ _IOW('t', 103, struct winsize)
#define TIOCGWINSZ _IOR('t', 104, struct winsize)
#define TIOCSWINSZ 0x40087467 /* _IOW('t', 103, struct winsize) */
#define TIOCGWINSZ 0x80087468 /* _IOR('t', 104, struct winsize) */
#define TIOCSTART _IO('t', 110) /* start output, like ^Q */
#define TIOCSTOP _IO('t', 111) /* stop output, like ^S */
#define TIOCOUTQ _IOR('t', 115, int) /* output queue size */
......@@ -88,7 +88,6 @@
#define TIOCSETD _IOW('T', 35, int)
#define TIOCGETD _IOR('T', 36, int)
#define TCSBRKP _IOW('T', 37, int) /* Needed for POSIX tcsendbreak()*/
#define TIOCTTYGSTRUCT _IOR('T', 38, struct tty_struct) /* For debugging only*/
#define TIOCSBRK _IO('T', 39) /* BSD compatibility */
#define TIOCCBRK _IO('T', 40) /* BSD compatibility */
#define TIOCGSID _IOR('T', 41, pid_t) /* Return the session ID of FD*/
......@@ -114,8 +113,10 @@
#define TIOCSERGETLSR _IOR('T', 89, unsigned int) /* Get line status reg. */
/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
# define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
#define TIOCSERGETMULTI _IOR('T', 90, struct serial_multiport_struct) /* Get multiport config */
#define TIOCSERSETMULTI _IOW('T', 91, struct serial_multiport_struct) /* Set multiport config */
#define TIOCSERGETMULTI 0x80a8545a /* Get multiport config */
/* _IOR('T', 90, struct serial_multiport_struct) */
#define TIOCSERSETMULTI 0x40a8545b /* Set multiport config */
/* _IOW('T', 91, struct serial_multiport_struct) */
#define TIOCMIWAIT _IO('T', 92) /* wait for a change on serial input line(s) */
#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
......
......@@ -739,7 +739,10 @@ __SYSCALL(334, sys_sched_setattr, 2)
#define __NR_sched_getattr 335
__SYSCALL(335, sys_sched_getattr, 3)
#define __NR_syscall_count 336
#define __NR_renameat2 336
__SYSCALL(336, sys_renameat2, 5)
#define __NR_syscall_count 337
/*
* sysxtensa syscall handler
......
......@@ -8,6 +8,7 @@
* this archive for more details.
*
* Copyright (C) 2001 - 2005 Tensilica, Inc.
* Copyright (C) 2014 Cadence Design Systems Inc.
*
* Rewritten by Chris Zankel <chris@zankel.net>
*
......@@ -174,6 +175,10 @@ ENTRY(fast_unaligned)
s32i a0, a2, PT_AREG2
s32i a3, a2, PT_AREG3
rsr a3, excsave1
movi a4, fast_unaligned_fixup
s32i a4, a3, EXC_TABLE_FIXUP
/* Keep value of SAR in a0 */
rsr a0, sar
......@@ -225,10 +230,6 @@ ENTRY(fast_unaligned)
addx8 a5, a6, a5
jx a5 # jump into table
/* Invalid instruction, CRITICAL! */
.Linvalid_instruction_load:
j .Linvalid_instruction
/* Load: Load memory address. */
.Lload: movi a3, ~3
......@@ -272,18 +273,6 @@ ENTRY(fast_unaligned)
/* Set target register. */
1:
#if XCHAL_HAVE_LOOPS
rsr a5, lend # check if we reached LEND
bne a7, a5, 1f
rsr a5, lcount # and LCOUNT != 0
beqz a5, 1f
addi a5, a5, -1 # decrement LCOUNT and set
rsr a7, lbeg # set PC to LBEGIN
wsr a5, lcount
#endif
1: wsr a7, epc1 # skip load instruction
extui a4, a4, INSN_T, 4 # extract target register
movi a5, .Lload_table
addx8 a4, a4, a5
......@@ -326,6 +315,35 @@ ENTRY(fast_unaligned)
mov a3, a14 ; _j 1f; .align 8
mov a3, a15 ; _j 1f; .align 8
/* We cannot handle this exception. */
.extern _kernel_exception
.Linvalid_instruction_load:
.Linvalid_instruction_store:
movi a4, 0
rsr a3, excsave1
s32i a4, a3, EXC_TABLE_FIXUP
/* Restore a4...a8 and SAR, set SP, and jump to default exception. */
l32i a8, a2, PT_AREG8
l32i a7, a2, PT_AREG7
l32i a6, a2, PT_AREG6
l32i a5, a2, PT_AREG5
l32i a4, a2, PT_AREG4
wsr a0, sar
mov a1, a2
rsr a0, ps
bbsi.l a0, PS_UM_BIT, 2f # jump if user mode
movi a0, _kernel_exception
jx a0
2: movi a0, _user_exception
jx a0
1: # a7: instruction pointer, a4: instruction, a3: value
movi a6, 0 # mask: ffffffff:00000000
......@@ -353,17 +371,6 @@ ENTRY(fast_unaligned)
/* Get memory address */
1:
#if XCHAL_HAVE_LOOPS
rsr a4, lend # check if we reached LEND
bne a7, a4, 1f
rsr a4, lcount # and LCOUNT != 0
beqz a4, 1f
addi a4, a4, -1 # decrement LCOUNT and set
rsr a7, lbeg # set PC to LBEGIN
wsr a4, lcount
#endif
1: wsr a7, epc1 # skip store instruction
movi a4, ~3
and a4, a4, a8 # align memory address
......@@ -375,25 +382,25 @@ ENTRY(fast_unaligned)
#endif
__ssa8r a8
__src_b a7, a5, a6 # lo-mask F..F0..0 (BE) 0..0F..F (LE)
__src_b a8, a5, a6 # lo-mask F..F0..0 (BE) 0..0F..F (LE)
__src_b a6, a6, a5 # hi-mask 0..0F..F (BE) F..F0..0 (LE)
#ifdef UNALIGNED_USER_EXCEPTION
l32e a5, a4, -8
#else
l32i a5, a4, 0 # load lower address word
#endif
and a5, a5, a7 # mask
__sh a7, a3 # shift value
or a5, a5, a7 # or with original value
and a5, a5, a8 # mask
__sh a8, a3 # shift value
or a5, a5, a8 # or with original value
#ifdef UNALIGNED_USER_EXCEPTION
s32e a5, a4, -8
l32e a7, a4, -4
l32e a8, a4, -4
#else
s32i a5, a4, 0 # store
l32i a7, a4, 4 # same for upper address word
l32i a8, a4, 4 # same for upper address word
#endif
__sl a5, a3
and a6, a7, a6
and a6, a8, a6
or a6, a6, a5
#ifdef UNALIGNED_USER_EXCEPTION
s32e a6, a4, -4
......@@ -401,9 +408,27 @@ ENTRY(fast_unaligned)
s32i a6, a4, 4
#endif
/* Done. restore stack and return */
.Lexit:
#if XCHAL_HAVE_LOOPS
rsr a4, lend # check if we reached LEND
bne a7, a4, 1f
rsr a4, lcount # and LCOUNT != 0
beqz a4, 1f
addi a4, a4, -1 # decrement LCOUNT and set
rsr a7, lbeg # set PC to LBEGIN
wsr a4, lcount
#endif
1: wsr a7, epc1 # skip emulated instruction
/* Update icount if we're single-stepping in userspace. */
rsr a4, icountlevel
beqz a4, 1f
bgeui a4, LOCKLEVEL + 1, 1f
rsr a4, icount
addi a4, a4, 1
wsr a4, icount
1: