mirror of https://github.com/PCSX2/pcsx2.git
newHostVM: (Restored booting) -
* Added some bounds checking to debug builds for VTLB mappings. * Fixed a VU mapping bug that caused boot crashing * Fixed some startup, shutdown, and reset resource management. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@4021 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
be1a590464
commit
239c9f83d8
|
@ -57,7 +57,6 @@ public:
|
||||||
pxFailRel( "Don't call me, damnit. Use DispatchException instead." );
|
pxFailRel( "Don't call me, damnit. Use DispatchException instead." );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void OnPageFaultEvent( const PageFaultInfo& evtinfo, bool& handled ) {}
|
virtual void OnPageFaultEvent( const PageFaultInfo& evtinfo, bool& handled ) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -93,7 +92,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
virtual void OnPageFaultEvent( const PageFaultInfo& info, bool& handled )
|
virtual void OnPageFaultEvent( const PageFaultInfo& info, bool& handled )
|
||||||
{
|
{
|
||||||
OnPageFaultEvent( info, handled );
|
Owner->OnPageFaultEvent( info, handled );
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -230,9 +229,10 @@ public:
|
||||||
|
|
||||||
using _parent::operator[];
|
using _parent::operator[];
|
||||||
|
|
||||||
protected:
|
|
||||||
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
|
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
// This function is called from OnPageFaultEvent after the address has been translated
|
// This function is called from OnPageFaultEvent after the address has been translated
|
||||||
// and confirmed to apply to this reserved area in question. OnPageFaultEvent contains
|
// and confirmed to apply to this reserved area in question. OnPageFaultEvent contains
|
||||||
// a try/catch exception handler, which ensures "reasonable" error response behavior if
|
// a try/catch exception handler, which ensures "reasonable" error response behavior if
|
||||||
|
|
|
@ -383,7 +383,6 @@ set(pcsx2IPUHeaders
|
||||||
|
|
||||||
# Linux sources
|
# Linux sources
|
||||||
set(pcsx2LinuxSources
|
set(pcsx2LinuxSources
|
||||||
Linux/LnxHostSys.cpp
|
|
||||||
Linux/LnxKeyCodes.cpp)
|
Linux/LnxKeyCodes.cpp)
|
||||||
|
|
||||||
# Linux headers
|
# Linux headers
|
||||||
|
|
|
@ -99,9 +99,9 @@ void iopMemoryReserve::Reset()
|
||||||
//for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16];
|
//for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16];
|
||||||
}
|
}
|
||||||
|
|
||||||
void iopMemoryReserve::Shutdown()
|
void iopMemoryReserve::Decommit()
|
||||||
{
|
{
|
||||||
_parent::Shutdown();
|
_parent::Decommit();
|
||||||
|
|
||||||
safe_aligned_free(psxMemWLUT);
|
safe_aligned_free(psxMemWLUT);
|
||||||
psxMemRLUT = NULL;
|
psxMemRLUT = NULL;
|
||||||
|
|
|
@ -317,7 +317,6 @@
|
||||||
<Unit filename="../IopSio2.cpp" />
|
<Unit filename="../IopSio2.cpp" />
|
||||||
<Unit filename="../IopSio2.h" />
|
<Unit filename="../IopSio2.h" />
|
||||||
<Unit filename="../Ipu_fifo.h" />
|
<Unit filename="../Ipu_fifo.h" />
|
||||||
<Unit filename="LnxHostSys.cpp" />
|
|
||||||
<Unit filename="LnxKeyCodes.cpp">
|
<Unit filename="LnxKeyCodes.cpp">
|
||||||
<Option compiler="gcc" use="1" buildCommand="$compiler $options $includes `pkg-config gtk+-2.0 --cflags` -c $file -o $object" />
|
<Option compiler="gcc" use="1" buildCommand="$compiler $options $includes `pkg-config gtk+-2.0 --cflags` -c $file -o $object" />
|
||||||
</Unit>
|
</Unit>
|
||||||
|
|
|
@ -579,7 +579,7 @@ void memClearPageAddr(u32 vaddr)
|
||||||
|
|
||||||
class mmap_PageFaultHandler : public EventListener_PageFault
|
class mmap_PageFaultHandler : public EventListener_PageFault
|
||||||
{
|
{
|
||||||
protected:
|
public:
|
||||||
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
|
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -339,7 +339,6 @@ SysMainMemory::SysMainMemory()
|
||||||
|
|
||||||
SysMainMemory::~SysMainMemory() throw()
|
SysMainMemory::~SysMainMemory() throw()
|
||||||
{
|
{
|
||||||
ShutdownAll();
|
|
||||||
ReleaseAll();
|
ReleaseAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,6 +355,7 @@ void SysMainMemory::ReserveAll()
|
||||||
|
|
||||||
void SysMainMemory::CommitAll()
|
void SysMainMemory::CommitAll()
|
||||||
{
|
{
|
||||||
|
vtlb_Core_Alloc();
|
||||||
if (m_ee.IsCommitted() && m_iop.IsCommitted() && m_vu.IsCommitted()) return;
|
if (m_ee.IsCommitted() && m_iop.IsCommitted() && m_vu.IsCommitted()) return;
|
||||||
|
|
||||||
DevCon.WriteLn( "PS2vm: Allocating host memory for all virtual systems..." );
|
DevCon.WriteLn( "PS2vm: Allocating host memory for all virtual systems..." );
|
||||||
|
@ -377,22 +377,30 @@ void SysMainMemory::ResetAll()
|
||||||
m_vu.Reset();
|
m_vu.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysMainMemory::ShutdownAll()
|
void SysMainMemory::DecommitAll()
|
||||||
{
|
{
|
||||||
Console.WriteLn( "PS2vm: Shutting down host memory for all virtual systems..." );
|
if (!m_ee.IsCommitted() && !m_iop.IsCommitted() && !m_vu.IsCommitted()) return;
|
||||||
|
|
||||||
m_ee.Shutdown();
|
Console.WriteLn( "PS2vm: Decommitting host memory for all virtual systems..." );
|
||||||
m_iop.Shutdown();
|
|
||||||
m_vu.Shutdown();
|
m_ee.Decommit();
|
||||||
|
m_iop.Decommit();
|
||||||
|
m_vu.Decommit();
|
||||||
|
|
||||||
|
vtlb_Core_Free();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysMainMemory::ReleaseAll()
|
void SysMainMemory::ReleaseAll()
|
||||||
{
|
{
|
||||||
|
DecommitAll();
|
||||||
|
|
||||||
Console.WriteLn( "PS2vm: Releasing host memory maps for all virtual systems..." );
|
Console.WriteLn( "PS2vm: Releasing host memory maps for all virtual systems..." );
|
||||||
|
|
||||||
m_ee.Shutdown();
|
vtlb_Core_Free(); // Just to be sure... (calling order could result in it getting missed during Decommit).
|
||||||
m_iop.Shutdown();
|
|
||||||
m_vu.Shutdown();
|
m_ee.Decommit();
|
||||||
|
m_iop.Decommit();
|
||||||
|
m_vu.Decommit();
|
||||||
|
|
||||||
safe_delete(Source_PageFault);
|
safe_delete(Source_PageFault);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,25 +47,25 @@ namespace HostMemoryMap
|
||||||
static const uptr sVU1rec = _256mb - (_8mb*2);
|
static const uptr sVU1rec = _256mb - (_8mb*2);
|
||||||
|
|
||||||
// PS2 main memory, SPR, and ROMs
|
// PS2 main memory, SPR, and ROMs
|
||||||
static const uptr EEmem = 0x30000000;
|
static const uptr EEmem = 0x20000000;
|
||||||
|
|
||||||
// IOP main memory and ROMs
|
// IOP main memory and ROMs
|
||||||
static const uptr IOPmem = 0x34000000;
|
static const uptr IOPmem = 0x24000000;
|
||||||
|
|
||||||
// VU0 and VU1 memory.
|
// VU0 and VU1 memory.
|
||||||
static const uptr VUmem = 0x38000000;
|
static const uptr VUmem = 0x28000000;
|
||||||
|
|
||||||
// EE recompiler code cache area (64mb)
|
// EE recompiler code cache area (64mb)
|
||||||
static const uptr EErec = 0x40000000;
|
static const uptr EErec = 0x30000000;
|
||||||
|
|
||||||
// IOP recompiler code cache area (16 or 32mb)
|
// IOP recompiler code cache area (16 or 32mb)
|
||||||
static const uptr IOPrec = 0x44000000;
|
static const uptr IOPrec = 0x34000000;
|
||||||
|
|
||||||
// microVU1 recompiler code cache area (32 or 64mb)
|
// microVU1 recompiler code cache area (32 or 64mb)
|
||||||
static const uptr mVU0rec = 0x48000000;
|
static const uptr mVU0rec = 0x38000000;
|
||||||
|
|
||||||
// microVU0 recompiler code cache area (64mb)
|
// microVU0 recompiler code cache area (64mb)
|
||||||
static const uptr mVU1rec = 0x50000000;
|
static const uptr mVU1rec = 0x40000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -86,7 +86,7 @@ public:
|
||||||
virtual void ReserveAll();
|
virtual void ReserveAll();
|
||||||
virtual void CommitAll();
|
virtual void CommitAll();
|
||||||
virtual void ResetAll();
|
virtual void ResetAll();
|
||||||
virtual void ShutdownAll();
|
virtual void DecommitAll();
|
||||||
virtual void ReleaseAll();
|
virtual void ReleaseAll();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ void SysCoreThread::ResetQuick()
|
||||||
void SysCoreThread::Reset()
|
void SysCoreThread::Reset()
|
||||||
{
|
{
|
||||||
ResetQuick();
|
ResetQuick();
|
||||||
GetVmMemory().ShutdownAll();
|
GetVmMemory().DecommitAll();
|
||||||
SysClearExecutionCache();
|
SysClearExecutionCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,10 @@ void vuMemoryReserve::Reserve()
|
||||||
//_parent::Reserve(EmuConfig.HostMemMap.VUmem);
|
//_parent::Reserve(EmuConfig.HostMemMap.VUmem);
|
||||||
|
|
||||||
u8* curpos = m_reserve.GetPtr();
|
u8* curpos = m_reserve.GetPtr();
|
||||||
VU0.Micro = curpos; curpos += 0x1000;
|
VU0.Micro = curpos; curpos += VU0_PROGSIZE;
|
||||||
VU0.Mem = curpos; curpos += 0x4000;
|
VU0.Mem = curpos; curpos += VU0_MEMSIZE;
|
||||||
VU1.Micro = curpos; curpos += 0x4000;
|
VU1.Micro = curpos; curpos += VU1_PROGSIZE;
|
||||||
VU1.Mem = curpos;
|
VU1.Mem = curpos; curpos += VU1_MEMSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vuMemoryReserve::Release()
|
void vuMemoryReserve::Release()
|
||||||
|
|
|
@ -378,24 +378,25 @@ __ri vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMem
|
||||||
// function.
|
// function.
|
||||||
//
|
//
|
||||||
// The memory region start and size parameters must be pagesize aligned.
|
// The memory region start and size parameters must be pagesize aligned.
|
||||||
void vtlb_MapHandler(vtlbHandler handler,u32 start,u32 size)
|
void vtlb_MapHandler(vtlbHandler handler, u32 start, u32 size)
|
||||||
{
|
{
|
||||||
verify(0==(start&VTLB_PAGE_MASK));
|
verify(0==(start&VTLB_PAGE_MASK));
|
||||||
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
||||||
s32 value=handler|0x80000000;
|
|
||||||
|
|
||||||
while(size>0)
|
s32 value = handler | 0x80000000;
|
||||||
|
u32 end = start + (size - VTLB_PAGE_SIZE);
|
||||||
|
pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) );
|
||||||
|
|
||||||
|
while (start <= end)
|
||||||
{
|
{
|
||||||
vtlbdata.pmap[start>>VTLB_PAGE_BITS]=value;
|
vtlbdata.pmap[start>>VTLB_PAGE_BITS] = value;
|
||||||
|
start += VTLB_PAGE_SIZE;
|
||||||
start+=VTLB_PAGE_SIZE;
|
|
||||||
size-=VTLB_PAGE_SIZE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize)
|
void vtlb_MapBlock(void* base, u32 start, u32 size, u32 blocksize)
|
||||||
{
|
{
|
||||||
s32 baseint=(s32)base;
|
s32 baseint = (s32)base;
|
||||||
|
|
||||||
verify(0==(start&VTLB_PAGE_MASK));
|
verify(0==(start&VTLB_PAGE_MASK));
|
||||||
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
||||||
|
@ -404,19 +405,21 @@ void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize)
|
||||||
verify(0==(blocksize&VTLB_PAGE_MASK) && blocksize>0);
|
verify(0==(blocksize&VTLB_PAGE_MASK) && blocksize>0);
|
||||||
verify(0==(size%blocksize));
|
verify(0==(size%blocksize));
|
||||||
|
|
||||||
while(size>0)
|
u32 end = start + (size - VTLB_PAGE_SIZE);
|
||||||
{
|
pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) );
|
||||||
u32 blocksz=blocksize;
|
|
||||||
s32 ptr=baseint;
|
|
||||||
|
|
||||||
while(blocksz>0)
|
while (start <= end)
|
||||||
{
|
{
|
||||||
vtlbdata.pmap[start>>VTLB_PAGE_BITS]=ptr;
|
u32 loopsz = blocksize;
|
||||||
|
s32 ptr = baseint;
|
||||||
|
|
||||||
start+=VTLB_PAGE_SIZE;
|
while (loopsz > 0)
|
||||||
ptr+=VTLB_PAGE_SIZE;
|
{
|
||||||
blocksz-=VTLB_PAGE_SIZE;
|
vtlbdata.pmap[start>>VTLB_PAGE_BITS] = ptr;
|
||||||
size-=VTLB_PAGE_SIZE;
|
|
||||||
|
start += VTLB_PAGE_SIZE;
|
||||||
|
ptr += VTLB_PAGE_SIZE;
|
||||||
|
loopsz -= VTLB_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,13 +430,15 @@ void vtlb_Mirror(u32 new_region,u32 start,u32 size)
|
||||||
verify(0==(start&VTLB_PAGE_MASK));
|
verify(0==(start&VTLB_PAGE_MASK));
|
||||||
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
||||||
|
|
||||||
while(size>0)
|
u32 end = start + (size-VTLB_PAGE_SIZE);
|
||||||
{
|
pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) );
|
||||||
vtlbdata.pmap[start>>VTLB_PAGE_BITS]=vtlbdata.pmap[new_region>>VTLB_PAGE_BITS];
|
|
||||||
|
|
||||||
start+=VTLB_PAGE_SIZE;
|
while(start <= end)
|
||||||
new_region+=VTLB_PAGE_SIZE;
|
{
|
||||||
size-=VTLB_PAGE_SIZE;
|
vtlbdata.pmap[start>>VTLB_PAGE_BITS] = vtlbdata.pmap[new_region>>VTLB_PAGE_BITS];
|
||||||
|
|
||||||
|
start += VTLB_PAGE_SIZE;
|
||||||
|
new_region += VTLB_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,6 +475,7 @@ void vtlb_VMap(u32 vaddr,u32 paddr,u32 sz)
|
||||||
if (pme<0)
|
if (pme<0)
|
||||||
pme|=paddr;// top bit is set anyway ...
|
pme|=paddr;// top bit is set anyway ...
|
||||||
}
|
}
|
||||||
|
|
||||||
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=pme-vaddr;
|
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=pme-vaddr;
|
||||||
vaddr+=VTLB_PAGE_SIZE;
|
vaddr+=VTLB_PAGE_SIZE;
|
||||||
paddr+=VTLB_PAGE_SIZE;
|
paddr+=VTLB_PAGE_SIZE;
|
||||||
|
@ -568,11 +574,14 @@ void vtlb_Term()
|
||||||
// default is used.
|
// default is used.
|
||||||
void vtlb_Core_Alloc()
|
void vtlb_Core_Alloc()
|
||||||
{
|
{
|
||||||
|
if (!vtlbdata.vmap)
|
||||||
|
{
|
||||||
vtlbdata.vmap = (s32*)_aligned_malloc( VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap), 16 );
|
vtlbdata.vmap = (s32*)_aligned_malloc( VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap), 16 );
|
||||||
if (!vtlbdata.vmap)
|
if (!vtlbdata.vmap)
|
||||||
throw Exception::OutOfMemory( L"VTLB Virtual Address Translation LUT" )
|
throw Exception::OutOfMemory( L"VTLB Virtual Address Translation LUT" )
|
||||||
.SetDiagMsg(pxsFmt("(%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb)
|
.SetDiagMsg(pxsFmt("(%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vtlb_Core_Free()
|
void vtlb_Core_Free()
|
||||||
|
@ -596,7 +605,7 @@ void VtlbMemoryReserve::SetBaseAddr( uptr newaddr )
|
||||||
|
|
||||||
void VtlbMemoryReserve::Reserve( sptr hostptr )
|
void VtlbMemoryReserve::Reserve( sptr hostptr )
|
||||||
{
|
{
|
||||||
m_reserve.Reserve();
|
m_reserve.ReserveAt( hostptr );
|
||||||
if (!m_reserve.IsOk())
|
if (!m_reserve.IsOk())
|
||||||
throw Exception::OutOfMemory( m_reserve.GetName() );
|
throw Exception::OutOfMemory( m_reserve.GetName() );
|
||||||
}
|
}
|
||||||
|
@ -610,13 +619,11 @@ void VtlbMemoryReserve::Commit()
|
||||||
|
|
||||||
void VtlbMemoryReserve::Reset()
|
void VtlbMemoryReserve::Reset()
|
||||||
{
|
{
|
||||||
if (!m_reserve.Commit())
|
Commit();
|
||||||
throw Exception::OutOfMemory( m_reserve.GetName() );
|
|
||||||
|
|
||||||
memzero_sse_a(m_reserve.GetPtr(), m_reserve.GetCommittedBytes());
|
memzero_sse_a(m_reserve.GetPtr(), m_reserve.GetCommittedBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VtlbMemoryReserve::Shutdown()
|
void VtlbMemoryReserve::Decommit()
|
||||||
{
|
{
|
||||||
m_reserve.Reset();
|
m_reserve.Reset();
|
||||||
}
|
}
|
||||||
|
|
16
pcsx2/vtlb.h
16
pcsx2/vtlb.h
|
@ -107,7 +107,7 @@ public:
|
||||||
|
|
||||||
virtual void Commit();
|
virtual void Commit();
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
virtual void Shutdown();
|
virtual void Decommit();
|
||||||
virtual void SetBaseAddr( uptr newaddr );
|
virtual void SetBaseAddr( uptr newaddr );
|
||||||
|
|
||||||
bool IsCommitted() const;
|
bool IsCommitted() const;
|
||||||
|
@ -149,7 +149,7 @@ public:
|
||||||
void Reserve();
|
void Reserve();
|
||||||
void Release();
|
void Release();
|
||||||
void Reset();
|
void Reset();
|
||||||
void Shutdown();
|
void Decommit();
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -178,8 +178,8 @@ namespace vtlb_private
|
||||||
static const uint VTLB_PAGE_MASK = 4095;
|
static const uint VTLB_PAGE_MASK = 4095;
|
||||||
static const uint VTLB_PAGE_SIZE = 4096;
|
static const uint VTLB_PAGE_SIZE = 4096;
|
||||||
|
|
||||||
static const uint VTLB_PMAP_ITEMS = _256mb / VTLB_PAGE_SIZE;
|
static const uint VTLB_PMAP_SZ = _1mb * 512;
|
||||||
static const uint VTLB_PMAP_SZ = _256mb;
|
static const uint VTLB_PMAP_ITEMS = VTLB_PMAP_SZ / VTLB_PAGE_SIZE;
|
||||||
static const uint VTLB_VMAP_ITEMS = _4gb / VTLB_PAGE_SIZE;
|
static const uint VTLB_VMAP_ITEMS = _4gb / VTLB_PAGE_SIZE;
|
||||||
|
|
||||||
struct MapData
|
struct MapData
|
||||||
|
@ -193,10 +193,10 @@ namespace vtlb_private
|
||||||
|
|
||||||
s32* vmap; //4MB (allocated by vtlb_init)
|
s32* vmap; //4MB (allocated by vtlb_init)
|
||||||
|
|
||||||
u8* reserve_base; //base of the memory array
|
MapData()
|
||||||
|
{
|
||||||
u8* alloc_base; //base of the memory array
|
vmap = NULL;
|
||||||
int alloc_current; //current base
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
extern __aligned(64) MapData vtlbdata;
|
extern __aligned(64) MapData vtlbdata;
|
||||||
|
|
Loading…
Reference in New Issue