singrdk/base/Kernel/Singularity/Io/IoMappedPort.cs

798 lines
21 KiB
C#

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: IoMappedPort.cs
//
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if SINGULARITY_PROCESS
using Microsoft.Singularity.V1.Services;
#endif
namespace Microsoft.Singularity.Io
{
[CLSCompliant(false)]
public sealed class IoMappedPort
{
private readonly UIntPtr address;
private readonly uint size;
private readonly bool readable;
private readonly bool writable;
#if SINGULARITY_KERNEL
public IoMappedPort(UIntPtr address, uint size, Access access)
#elif SINGULARITY_PROCESS
internal IoMappedPort(UIntPtr address, uint size, Access access)
#endif // SINGULARITY_PROCESS
{
this.address = address;
this.size = size;
this.readable = (access & Access.Read) != 0;
this.writable = (access & Access.Write) != 0;
}
#if SINGULARITY_KERNEL
public IoMappedPort(UIntPtr address, uint size, bool readable, bool writable)
#elif SINGULARITY_PROCESS
internal IoMappedPort(UIntPtr address, uint size, bool readable, bool writable)
#endif // SINGULARITY_PROCESS
{
this.address = address;
this.size = size;
this.readable = readable;
this.writable = writable;
}
public UIntPtr Address {
[NoHeapAllocation]
get { return address; }
}
public uint Length {
[NoHeapAllocation]
get { return size; }
}
public bool Readable {
[NoHeapAllocation]
get { return readable; }
}
public bool Writable {
[NoHeapAllocation]
get { return writable; }
}
public override string ToString()
{
return String.Format("IOMapped:{0,8:x8}[{1}]",
address,
(readable && writable) ? "R/W" :
(readable) ? "R" : "W");
}
[Inline]
public void Write8(byte value)
{
Write8(0, value);
}
[Inline]
public void Write16(ushort value)
{
Write16(0, value);
}
[Inline]
public void Write16(ushort[] values)
{
Write16(0, values);
}
[Inline]
public void Write32(uint value)
{
Write32(0, value);
}
[Inline]
public void Write64(ulong value)
{
Write64(0, value);
}
[Inline]
public byte Read8()
{
return Read8(0);
}
[Inline]
public ushort Read16()
{
return Read16(0);
}
[Inline]
public uint Read32()
{
return Read32(0);
}
[Inline]
public ulong Read64()
{
return Read64(0);
}
///////////////////////////////////////////////////////////////////////
//
[Inline]
private void CheckRead(uint offset, uint bytes)
{
#if !DONT_CHECK_IO_BOUNDS
if (!readable) {
Error.ReadNotSupported();
}
else if (offset + bytes > size) {
Error.AccessOutOfRange();
}
#endif // DONT_CHECK_IO_BOUNDS
}
[Inline]
private void CheckWrite(uint offset, uint bytes)
{
#if !DONT_CHECK_IO_BOUNDS
if (!writable) {
Error.WriteNotSupported();
}
else if (offset + bytes > size) {
Error.AccessOutOfRange();
}
#endif // DONT_CHECK_IO_BOUNDS
}
[Inline]
[NoHeapAllocation]
private void DebugBreak()
{
#if SINGULARITY_KERNEL
DebugStub.Break();
#elif SINGULARITY_PROCESS
DebugService.Break();
#endif // SINGULARITY_PROCESS
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//
[Inline]
public void Write8(uint offset, byte value)
{
CheckWrite(offset, 1);
HalWrite8(offset, value);
}
[Inline]
public void Write16(uint offset, ushort value)
{
CheckWrite(offset, 2);
HalWrite16(offset, value);
}
[Inline]
public void Write16(uint offset, ushort[] values)
{
CheckWrite(offset, 2);
for (int i = 0; i < values.Length; i++) {
HalWrite16(offset, values[i]);
}
}
[Inline]
public void Write32(uint offset, uint value)
{
CheckWrite(offset, 4);
HalWrite32(offset, value);
}
[Inline]
public void Write64(uint offset, ulong value)
{
CheckWrite(offset, 8);
HalWrite64(offset, value);
}
[Inline]
public byte Read8(uint offset)
{
CheckRead(offset, 1);
return HalRead8(offset);
}
[Inline]
public ushort Read16(uint offset)
{
CheckRead(offset, 2);
return HalRead16(offset);
}
[Inline]
public uint Read32(uint offset)
{
CheckRead(offset, 4);
return HalRead32(offset);
}
[Inline]
public ulong Read64(uint offset)
{
CheckRead(offset, 8);
return HalRead64(offset);
}
///////////////////////////////////////////////////////////////////////
// Export non-exception throwing operations
//
// These are intended for use in the kernel on
// NoHeapAllocation paths. The caller is expected to
// check the result and/or know pre-conditions for the
// I/O operation.
#region NoHeapAllocation Read/Write operations
#if SINGULARITY_KERNEL
[Inline]
[NoHeapAllocation]
private IoResult CheckReadNoThrow(uint offset, int bytes)
{
#if !DONT_CHECK_IO_BOUNDS
if (!readable) {
return IoResult.ReadNotSupported;
}
if (offset + bytes > size) {
return IoResult.AccessOutOfRange;
}
#endif // DONT_CHECK_IO_BOUNDS
return IoResult.Success;
}
[Inline]
[NoHeapAllocation]
private IoResult CheckWriteNoThrow(uint offset, int bytes)
{
#if !DONT_CHECK_IO_BOUNDS
if (!writable) {
return IoResult.WriteNotSupported;
}
if (offset + bytes > size) {
return IoResult.AccessOutOfRange;
}
#endif // DONT_CHECK_IO_BOUNDS
return IoResult.Success;
}
[Inline]
[NoHeapAllocation]
public IoResult Read8NoThrow(uint offset, out byte value)
{
IoResult check = CheckReadNoThrow(offset, 1);
if (IoResult.Success == check) {
value = HalRead8(offset);
}
else {
value = 0;
}
return check;
}
[Inline]
[NoHeapAllocation]
public IoResult Read16NoThrow(uint offset, out ushort value)
{
IoResult check = CheckReadNoThrow(offset, 2);
if (IoResult.Success == check) {
value = HalRead16(offset);
}
else {
value = 0;
}
return check;
}
[Inline]
[NoHeapAllocation]
public IoResult Read32NoThrow(uint offset, out uint value)
{
IoResult check = CheckReadNoThrow(offset, 4);
if (IoResult.Success == check) {
value = HalRead32(offset);
}
else {
value = 0;
}
return check;
}
[Inline]
[NoHeapAllocation]
public IoResult Read64NoThrow(uint offset, out ulong value)
{
IoResult check = CheckReadNoThrow(offset, 8);
if (IoResult.Success == check) {
value = HalRead64(offset);
}
else {
value = 0;
}
return check;
}
[Inline]
[NoHeapAllocation]
public IoResult Read8NoThrow(out byte value)
{
return Read8NoThrow(0, out value);
}
[Inline]
[NoHeapAllocation]
public IoResult Read16NoThrow(out ushort value)
{
return Read16NoThrow(0, out value);
}
[Inline]
[NoHeapAllocation]
public IoResult Read32NoThrow(out uint value)
{
return Read32NoThrow(0, out value);
}
[Inline]
[NoHeapAllocation]
public IoResult Write8NoThrow(uint offset, byte value)
{
IoResult check = CheckWriteNoThrow(offset, 1);
if (IoResult.Success == check) {
HalWrite8(offset, value);
}
return check;
}
[Inline]
[NoHeapAllocation]
public IoResult Write16NoThrow(uint offset, ushort value)
{
IoResult check = CheckWriteNoThrow(offset, 2);
if (IoResult.Success == check) {
HalWrite16(offset, value);
}
return check;
}
[Inline]
[NoHeapAllocation]
public IoResult Write32NoThrow(uint offset, uint value)
{
IoResult check = CheckWriteNoThrow(offset, 4);
if (IoResult.Success == check) {
HalWrite32(offset, value);
}
return check;
}
[Inline]
[NoHeapAllocation]
public IoResult Write64NoThrow(uint offset, ulong value)
{
IoResult check = CheckWriteNoThrow(offset, 8);
if (IoResult.Success == check) {
HalWrite64(offset, value);
}
return check;
}
[Inline]
[NoHeapAllocation]
public IoResult Write8NoThrow(byte value)
{
return Write8NoThrow(0, value);
}
[Inline]
[NoHeapAllocation]
public IoResult Write16NoThrow(ushort value)
{
return Write16NoThrow(0, value);
}
[Inline]
[NoHeapAllocation]
public IoResult Write32NoThrow(uint value)
{
return Write32NoThrow(0, value);
}
[Inline]
[NoHeapAllocation]
public IoResult Write64NoThrow(ulong value)
{
return Write64NoThrow(0, value);
}
//////////////////////////////////////////////////////////////////////////////
[Inline]
[NoHeapAllocation]
private bool CheckReadNoThrow(uint offset, int bytes, ref IoResult result)
{
#if !DONT_CHECK_IO_BOUNDS
if (!readable) {
result = IoResult.ReadNotSupported;
return false;
}
if (offset + bytes > size) {
result = IoResult.AccessOutOfRange;
return false;
}
#endif // DONT_CHECK_IO_BOUNDS
return true;
}
[Inline]
[NoHeapAllocation]
private bool CheckWriteNoThrow(uint offset, int bytes, ref IoResult result)
{
#if !DONT_CHECK_IO_BOUNDS
if (!writable) {
result = IoResult.WriteNotSupported;
return false;
}
if (offset + bytes > size) {
result = IoResult.AccessOutOfRange;
return false;
}
#endif // DONT_CHECK_IO_BOUNDS
return true;
}
[Inline]
[NoHeapAllocation]
public byte Read8NoThrow(uint offset, ref IoResult result)
{
if (CheckReadNoThrow(offset, 1, ref result)) {
return HalRead8(offset);
}
else {
return 0;
}
}
[Inline]
[NoHeapAllocation]
public ushort Read16NoThrow(uint offset, ref IoResult result)
{
if (CheckReadNoThrow(offset, 2, ref result)) {
return HalRead16(offset);
}
else {
return 0;
}
}
[Inline]
[NoHeapAllocation]
public uint Read32NoThrow(uint offset, ref IoResult result)
{
if (CheckReadNoThrow(offset, 4, ref result)) {
return HalRead32(offset);
}
else {
return 0;
}
}
[Inline]
[NoHeapAllocation]
public ulong Read64NoThrow(uint offset, ref IoResult result)
{
if (CheckReadNoThrow(offset, 8, ref result)) {
return HalRead64(offset);
}
else {
return 0;
}
}
[Inline]
[NoHeapAllocation]
public byte Read8NoThrow(ref IoResult result)
{
return Read8NoThrow(0, ref result);
}
[Inline]
[NoHeapAllocation]
public ushort Read16NoThrow(ref IoResult result)
{
return Read16NoThrow(0, ref result);
}
[Inline]
[NoHeapAllocation]
public uint Read32NoThrow(ref IoResult result)
{
return Read32NoThrow(0, ref result);
}
[Inline]
[NoHeapAllocation]
public ulong Read64NoThrow(ref IoResult result)
{
return Read64NoThrow(0, ref result);
}
[Inline]
[NoHeapAllocation]
public void Write8NoThrow(uint offset, byte value, ref IoResult result)
{
if (CheckWriteNoThrow(offset, 1, ref result)) {
HalWrite8(offset, value);
}
}
[Inline]
[NoHeapAllocation]
public void Write16NoThrow(uint offset, ushort value, ref IoResult result)
{
if (CheckWriteNoThrow(offset, 2, ref result)) {
HalWrite16(offset, value);
}
}
[Inline]
[NoHeapAllocation]
public void Write32NoThrow(uint offset, uint value, ref IoResult result)
{
if (CheckWriteNoThrow(offset, 4, ref result)) {
HalWrite32(offset, value);
}
}
[Inline]
[NoHeapAllocation]
public void Write64NoThrow(uint offset, ulong value, ref IoResult result)
{
if (CheckWriteNoThrow(offset, 8, ref result)) {
HalWrite64(offset, value);
}
}
[Inline]
[NoHeapAllocation]
public void Write8NoThrow(byte value, ref IoResult result)
{
Write8NoThrow(0, value, ref result);
}
[Inline]
[NoHeapAllocation]
public void Write16NoThrow(ushort value, ref IoResult result)
{
Write16NoThrow(0, value, ref result);
}
[Inline]
[NoHeapAllocation]
public void Write32NoThrow(uint value, ref IoResult result)
{
Write32NoThrow(0, value, ref result);
}
[Inline]
[NoHeapAllocation]
public void Write64NoThrow(ulong value, ref IoResult result)
{
Write64NoThrow(0, value, ref result);
}
#endif // SINGULARITY_KERNEL
#endregion // NoHeapAllocation Read/Write operations
//////////////////////////////////////////////////////////////////////
//
public byte WaitClear8(byte mask)
{
CheckRead(0, 1);
for (int i = 0; i < 100000000; i++) {
byte value;
if (((value = HalRead8(0)) & mask) == 0) {
return value;
}
}
DebugBreak();
return HalRead8(0);
}
public ushort WaitClear16(ushort mask)
{
CheckRead(0, 2);
for (int i = 0; i < 100000000; i++) {
ushort value;
if (((value = HalRead16(0)) & mask) == 0) {
return value;
}
}
DebugBreak();
return HalRead16(0);
}
public uint WaitClear32(uint mask)
{
CheckRead(0, 4);
for (int i = 0; i < 100000000; i++) {
uint value;
if (((value = HalRead32(0)) & mask) == 0) {
return value;
}
}
DebugBreak();
return HalRead32(0);
}
public ulong WaitClear64(ulong mask)
{
CheckRead(0, 8);
for (int i = 0; i < 100000000; i++) {
ulong value;
if (((value = HalRead64(0)) & mask) == 0) {
return value;
}
}
DebugBreak();
return HalRead64(0);
}
//////////////////////////////////////////////////////////////////////
//
public byte WaitSet8(byte mask)
{
CheckRead(0, 1);
for (int i = 0; i < 100000000; i++) {
byte value;
if (((value = HalRead8(0)) & mask) != 0) {
return value;
}
}
DebugBreak();
return HalRead8(0);
}
public ushort WaitSet16(ushort mask)
{
CheckRead(0, 2);
for (int i = 0; i < 100000000; i++) {
ushort value;
if (((value = HalRead16(0)) & mask) != 0) {
return value;
}
}
DebugBreak();
return HalRead16(0);
}
public uint WaitSet32(uint mask)
{
CheckRead(0, 4);
for (int i = 0; i < 100000000; i++) {
uint value;
if (((value = HalRead32(0)) & mask) != 0) {
return value;
}
}
DebugBreak();
return HalRead32(0);
}
public ulong WaitSet64(ulong mask)
{
CheckRead(0, 8);
for (int i = 0; i < 100000000; i++) {
ulong value;
if (((value = HalRead64(0)) & mask) != 0) {
return value;
}
}
DebugBreak();
return HalRead64(0);
}
//////////////////////////////////////////////////////////////////////
//
[NoHeapAllocation]
private unsafe byte HalRead8(uint offset)
{
return *((/*volatile*/ byte *)(address + offset));
}
[NoHeapAllocation]
private unsafe void HalWrite8(uint offset, byte value)
{
*((/*volatile*/ byte *)(address + offset)) = value;
}
[NoHeapAllocation]
private unsafe ushort HalRead16(uint offset)
{
return *((/*volatile*/ ushort *)(address + offset));
}
[NoHeapAllocation]
private unsafe void HalWrite16(uint offset, ushort value)
{
*((/*volatile*/ ushort *)(address + offset)) = value;
}
[NoHeapAllocation]
private unsafe uint HalRead32(uint offset)
{
return *((/*volatile*/ uint *)(address + offset));
}
[NoHeapAllocation]
private unsafe void HalWrite32(uint offset, uint value)
{
*((/*volatile*/ uint *)(address + offset)) = value;
}
[NoHeapAllocation]
private unsafe ulong HalRead64(uint offset)
{
return *((/*volatile*/ ulong *)(address + offset));
}
[NoHeapAllocation]
private unsafe void HalWrite64(uint offset, ulong value)
{
*((/*volatile*/ ulong *)(address + offset)) = value;
}
}
}