798 lines
21 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|