539 lines
15 KiB
C#
539 lines
15 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: IoPort.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 IoPort
|
||
|
{
|
||
|
private readonly ushort port;
|
||
|
private readonly ushort size;
|
||
|
private readonly bool readable;
|
||
|
private readonly bool writable;
|
||
|
|
||
|
#if SINGULARITY_KERNEL
|
||
|
public IoPort(ushort port, ushort size, Access access)
|
||
|
#elif SINGULARITY_PROCESS
|
||
|
internal IoPort(ushort port, ushort size, Access access)
|
||
|
#endif // SINGULARITY_PROCESS
|
||
|
{
|
||
|
this.port = port;
|
||
|
this.size = size;
|
||
|
this.readable = (access & Access.Read) != 0;
|
||
|
this.writable = (access & Access.Write) != 0;
|
||
|
}
|
||
|
|
||
|
#if SINGULARITY_KERNEL
|
||
|
public IoPort(ushort port, ushort size, bool readable, bool writable)
|
||
|
#elif SINGULARITY_PROCESS
|
||
|
internal IoPort(ushort port, ushort size, bool readable, bool writable)
|
||
|
#endif // SINGULARITY_PROCESS
|
||
|
{
|
||
|
this.port = port;
|
||
|
this.size = size;
|
||
|
this.readable = readable;
|
||
|
this.writable = writable;
|
||
|
}
|
||
|
|
||
|
public ushort Port {
|
||
|
[NoHeapAllocation]
|
||
|
get { return port; }
|
||
|
}
|
||
|
|
||
|
public ushort Size {
|
||
|
[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("IO:{0,4:x4}[{1}]",
|
||
|
port,
|
||
|
(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 byte Read8()
|
||
|
{
|
||
|
return Read8(0);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
public ushort Read16()
|
||
|
{
|
||
|
return Read16(0);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
public uint Read32()
|
||
|
{
|
||
|
return Read32(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);
|
||
|
HalWriteInt8(port + offset, value);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
public void Write16(uint offset, ushort value)
|
||
|
{
|
||
|
CheckWrite(offset, 2);
|
||
|
HalWriteInt16(port + offset, value);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
public void Write16(uint offset, ushort[] values)
|
||
|
{
|
||
|
CheckWrite(offset, 2);
|
||
|
for (int i = 0; i < values.Length; i++) {
|
||
|
HalWriteInt16(port + offset, values[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
public void Write32(uint offset, uint value)
|
||
|
{
|
||
|
CheckWrite(offset, 4);
|
||
|
HalWriteInt32(port + offset, value);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
public byte Read8(uint offset)
|
||
|
{
|
||
|
CheckRead(offset, 1);
|
||
|
return HalReadInt8(port + offset);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
public ushort Read16(uint offset)
|
||
|
{
|
||
|
CheckRead(offset, 2);
|
||
|
return HalReadInt16(port + offset);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
public uint Read32(uint offset)
|
||
|
{
|
||
|
CheckRead(offset, 4);
|
||
|
return HalReadInt32(port + 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 unsafe IoResult CheckReadNoThrow(uint offset, int bytes)
|
||
|
{
|
||
|
#if !DONT_CHECK_IO_BOUNDS
|
||
|
if (!this.readable) {
|
||
|
return IoResult.ReadNotSupported;
|
||
|
}
|
||
|
if (offset + bytes > this.size) {
|
||
|
return IoResult.AccessOutOfRange;
|
||
|
}
|
||
|
#endif // DONT_CHECK_IO_BOUNDS
|
||
|
return IoResult.Success;
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
[NoHeapAllocation]
|
||
|
private unsafe IoResult CheckWriteNoThrow(uint offset, int bytes)
|
||
|
{
|
||
|
#if !DONT_CHECK_IO_BOUNDS
|
||
|
if (!this.writable) {
|
||
|
return IoResult.WriteNotSupported;
|
||
|
}
|
||
|
if (offset + bytes > this.size) {
|
||
|
return IoResult.AccessOutOfRange;
|
||
|
}
|
||
|
#endif // DONT_CHECK_IO_BOUNDS
|
||
|
return IoResult.Success;
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
[NoHeapAllocation]
|
||
|
public unsafe IoResult Read8NoThrow(uint offset, out byte value)
|
||
|
{
|
||
|
IoResult check = CheckReadNoThrow(offset, 1);
|
||
|
if (IoResult.Success == check) {
|
||
|
value = HalReadInt8(port + offset);
|
||
|
}
|
||
|
else {
|
||
|
value = 0;
|
||
|
}
|
||
|
return check;
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
[NoHeapAllocation]
|
||
|
public unsafe IoResult Read16NoThrow(uint offset, out ushort value)
|
||
|
{
|
||
|
IoResult check = CheckReadNoThrow(offset, 2);
|
||
|
if (IoResult.Success == check) {
|
||
|
value = HalReadInt16(port + offset);
|
||
|
}
|
||
|
else {
|
||
|
value = 0;
|
||
|
}
|
||
|
return check;
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
[NoHeapAllocation]
|
||
|
public unsafe IoResult Read32NoThrow(uint offset, out uint value)
|
||
|
{
|
||
|
IoResult check = CheckReadNoThrow(offset, 4);
|
||
|
if (IoResult.Success == check) {
|
||
|
value = HalReadInt32(port + 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 unsafe IoResult Write8NoThrow(uint offset, byte value)
|
||
|
{
|
||
|
IoResult check = CheckWriteNoThrow(offset, 1);
|
||
|
if (IoResult.Success == check) {
|
||
|
HalWriteInt8(port + offset, value);
|
||
|
}
|
||
|
return check;
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
[NoHeapAllocation]
|
||
|
public unsafe IoResult Write16NoThrow(uint offset, ushort value)
|
||
|
{
|
||
|
IoResult check = CheckWriteNoThrow(offset, 2);
|
||
|
if (IoResult.Success == check) {
|
||
|
HalWriteInt16(port + offset, value);
|
||
|
}
|
||
|
return check;
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
[NoHeapAllocation]
|
||
|
public unsafe IoResult Write32NoThrow(uint offset, uint value)
|
||
|
{
|
||
|
IoResult check = CheckWriteNoThrow(offset, 4);
|
||
|
if (IoResult.Success == check) {
|
||
|
HalWriteInt32(port + 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);
|
||
|
}
|
||
|
|
||
|
#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 = HalReadInt8(port)) & mask) == 0) {
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DebugBreak();
|
||
|
|
||
|
return HalReadInt8(port);
|
||
|
}
|
||
|
|
||
|
public ushort WaitClear16(ushort mask)
|
||
|
{
|
||
|
CheckRead(0, 2);
|
||
|
|
||
|
for (int i = 0; i < 100000000; i++) {
|
||
|
ushort value;
|
||
|
if (((value = HalReadInt16(port)) & mask) == 0) {
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DebugBreak();
|
||
|
|
||
|
return HalReadInt16(port);
|
||
|
}
|
||
|
|
||
|
public uint WaitClear32(uint mask)
|
||
|
{
|
||
|
CheckRead(0, 4);
|
||
|
|
||
|
for (int i = 0; i < 100000000; i++) {
|
||
|
uint value;
|
||
|
if (((value = HalReadInt32(port)) & mask) == 0) {
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DebugBreak();
|
||
|
|
||
|
return HalReadInt32(port);
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
public byte WaitSet8(byte mask)
|
||
|
{
|
||
|
CheckRead(0, 1);
|
||
|
|
||
|
for (int i = 0; i < 100000000; i++) {
|
||
|
byte value;
|
||
|
if (((value = HalReadInt8(port)) & mask) != 0) {
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DebugBreak();
|
||
|
|
||
|
return HalReadInt8(port);
|
||
|
}
|
||
|
|
||
|
public ushort WaitSet16(ushort mask)
|
||
|
{
|
||
|
CheckRead(0, 2);
|
||
|
|
||
|
for (int i = 0; i < 100000000; i++) {
|
||
|
ushort value;
|
||
|
if (((value = HalReadInt16(port)) & mask) != 0) {
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DebugBreak();
|
||
|
|
||
|
return HalReadInt16(port);
|
||
|
}
|
||
|
|
||
|
public uint WaitSet32(uint mask)
|
||
|
{
|
||
|
CheckRead(0, 4);
|
||
|
|
||
|
for (int i = 0; i < 100000000; i++) {
|
||
|
uint value;
|
||
|
if (((value = HalReadInt32(port)) & mask) != 0) {
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DebugBreak();
|
||
|
|
||
|
return HalReadInt32(port);
|
||
|
}
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in IoPort.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[GCAnnotation(GCOption.NOGC)]
|
||
|
[StackBound(12)]
|
||
|
[NoHeapAllocation]
|
||
|
private static extern byte HalReadInt8(uint port);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in IoPort.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[GCAnnotation(GCOption.NOGC)]
|
||
|
[StackBound(12)]
|
||
|
[NoHeapAllocation]
|
||
|
private static extern void HalWriteInt8(uint port, byte value);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in IoPort.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[GCAnnotation(GCOption.NOGC)]
|
||
|
[StackBound(12)]
|
||
|
[NoHeapAllocation]
|
||
|
private static extern ushort HalReadInt16(uint port);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in IoPort.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[GCAnnotation(GCOption.NOGC)]
|
||
|
[StackBound(12)]
|
||
|
[NoHeapAllocation]
|
||
|
private static extern void HalWriteInt16(uint port, ushort value);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in IoPort.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[GCAnnotation(GCOption.NOGC)]
|
||
|
[StackBound(12)]
|
||
|
[NoHeapAllocation]
|
||
|
private static extern uint HalReadInt32(uint port);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in IoPort.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[GCAnnotation(GCOption.NOGC)]
|
||
|
[StackBound(12)]
|
||
|
[NoHeapAllocation]
|
||
|
private static extern void HalWriteInt32(uint port, uint value);
|
||
|
|
||
|
#if DO_UNSAFE_CODE_IN_IO
|
||
|
[AccessedByRuntime("output to header : defined in IoPort.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[GCAnnotation(GCOption.NOGC)]
|
||
|
[NoHeapAllocation]
|
||
|
private static extern unsafe void HalReadFifo16(uint port,
|
||
|
[In] ushort *data,
|
||
|
uint count);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in IoPort.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[GCAnnotation(GCOption.NOGC)]
|
||
|
[NoHeapAllocation]
|
||
|
private static extern unsafe void HalWriteFifo16(uint port,
|
||
|
[In,Out] ushort *data,
|
||
|
uint Count);
|
||
|
#endif
|
||
|
}
|
||
|
}
|