351 lines
11 KiB
C#
351 lines
11 KiB
C#
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: Pic.cs
|
|
//
|
|
// Note:
|
|
// http://home.ozonline.com.au/davmac/davpage/PIC.html
|
|
//
|
|
|
|
//#define DEBUG_INTERRUPTS
|
|
//#define DEBUG_DISPATCH_IO
|
|
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Threading;
|
|
using Microsoft.Singularity.Configuration;
|
|
using Microsoft.Singularity.Io;
|
|
|
|
namespace Microsoft.Singularity.Hal
|
|
{
|
|
// declare resources for the kernel manifest
|
|
[DriverCategory]
|
|
[Signature("/pnp/PNP0000")]
|
|
public sealed class PicResources : DriverCategoryDeclaration
|
|
{
|
|
[IoPortRange(0, Default = 0x20, Length = 0x02)]
|
|
public IoPortRange port1;
|
|
|
|
[IoPortRange(1, Default = 0xa0, Length = 0x02)]
|
|
public IoPortRange port2;
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
public sealed class Pic : HalPic
|
|
{
|
|
// Constants for PIC interrupt vectors.
|
|
public const byte PIC0_BIOS_VECTOR = 0x08; // IRQ0..IRQ7
|
|
public const byte PIC1_BIOS_VECTOR = 0x70; // IRQ8..IRQF
|
|
|
|
public const byte PIC_NS_EOI = 0x20; // OCW1: End of Interrupt.
|
|
public const ushort PIC_I_PIC1 = 0x04; // IRQ 2 / INT 0x0a 10
|
|
public const byte PIC_VECTORS = 16;
|
|
|
|
private ushort irqMask;
|
|
private byte baseVector;
|
|
|
|
private IoPort pic0CtrlPort;
|
|
private IoPort pic0MaskPort;
|
|
private IoPort pic1CtrlPort;
|
|
private IoPort pic1MaskPort;
|
|
|
|
internal Pic(PnpConfig config)
|
|
{
|
|
// /pnp/08/00/01/PNP0000 0003 cfg dis
|
|
// I/O Port inf=01 min=0020 max=0020 aln=01 len=02 0020..0021
|
|
// I/O Port inf=01 min=00a0 max=00a0 aln=01 len=02 00a0..00a1
|
|
// IRQ mask=0004 type=79
|
|
|
|
// Range[0]: 0x20; // PIC0
|
|
// Range[1]: 0xA0; // PIC1
|
|
|
|
pic0CtrlPort = ((IoPortRange)config.DynamicRanges[0])
|
|
.PortAtOffset(0, 1, Access.ReadWrite);
|
|
pic0MaskPort = ((IoPortRange)config.DynamicRanges[0])
|
|
.PortAtOffset(1, 1, Access.ReadWrite);
|
|
pic1CtrlPort = ((IoPortRange)config.DynamicRanges[1])
|
|
.PortAtOffset(0, 1, Access.ReadWrite);
|
|
pic1MaskPort = ((IoPortRange)config.DynamicRanges[1])
|
|
.PortAtOffset(1, 1, Access.ReadWrite);
|
|
}
|
|
|
|
public byte Initialize(byte baseVector)
|
|
{
|
|
DebugStub.Print("Pic.Initializing IRQs at interrupt {0:x2}\n",
|
|
__arglist(baseVector));
|
|
|
|
this.baseVector = baseVector;
|
|
irqMask = unchecked((ushort)~PIC_I_PIC1);
|
|
|
|
// Set ICW1 (must be followed by ICW2, ICW3, and ICW4).
|
|
// 00010001b - 8-byte,cascaded,triggered,w/ICW4
|
|
pic1CtrlPort.Write8(0x11);
|
|
pic0CtrlPort.Write8(0x11);
|
|
|
|
// Set ICW2..ICW3 (must follow ICW1)
|
|
pic1MaskPort.Write8((byte)(baseVector + 8));
|
|
pic0MaskPort.Write8(baseVector);
|
|
|
|
pic1MaskPort.Write8(0x02); // Cascaded interrupt number
|
|
pic0MaskPort.Write8(0x04); // Cascaded interrupt bit.
|
|
|
|
pic1MaskPort.Write8(1); // End of Interrupt
|
|
pic0MaskPort.Write8(1);
|
|
|
|
pic1CtrlPort.Write8(0x20); // EOI
|
|
pic0CtrlPort.Write8(0x20); // EOI
|
|
|
|
MaskAll();
|
|
|
|
return PIC_VECTORS;
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
this.Initialize(0x70);
|
|
}
|
|
|
|
public void ReleaseResources()
|
|
{
|
|
UnmaskAll();
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
public override byte InterruptToIrq(byte interrupt)
|
|
{
|
|
return (byte)(interrupt - baseVector);
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
public override byte IrqToInterrupt(byte irq)
|
|
{
|
|
return (byte)(baseVector + irq);
|
|
}
|
|
|
|
public override byte MaximumIrq
|
|
{
|
|
[NoHeapAllocation]
|
|
get { return PIC_VECTORS - 1; }
|
|
}
|
|
|
|
[System.Diagnostics.Conditional("PIC_DEBUG")]
|
|
private void DumpRegisters()
|
|
{
|
|
pic0CtrlPort.Write8(0x04 | 0x02); // OCW3 - read IRR
|
|
byte irr0 = pic0CtrlPort.Read8();
|
|
pic0CtrlPort.Write8(0x04 | 0x03); // OCW3 - read ISR
|
|
byte isr0 = pic0CtrlPort.Read8();
|
|
pic1CtrlPort.Write8(0x04 | 0x02); // OCW3 - read IRR
|
|
byte irr1 = pic1CtrlPort.Read8();
|
|
pic1CtrlPort.Write8(0x04 | 0x03); // OCW3 - read ISR
|
|
byte isr1 = pic1CtrlPort.Read8();
|
|
byte mask0 = pic0MaskPort.Read8();
|
|
byte mask1 = pic1MaskPort.Read8();
|
|
|
|
DebugStub.Print("PIC IRR: {0:x2}{1:x2} ISR: {2:x2}{3:x2} Mask:{4:x2}{5:x2}\n",
|
|
__arglist(irr1, irr0, isr1, isr0, mask1, mask0));
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
public override void ClearInterrupt(byte interrupt)
|
|
{
|
|
byte irq = InterruptToIrq(interrupt);
|
|
|
|
Mask(irq);
|
|
AckIrq(irq);
|
|
|
|
#if DEBUG_INTERRUPTS
|
|
DebugStub.Print("pic.ClearInterrupt({0:x2})\n",
|
|
__arglist(irqMask));
|
|
#endif
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
public override void AckIrq(byte irq)
|
|
{
|
|
DebugStub.Assert(Processor.InterruptsDisabled());
|
|
#if PIC_DEBUG
|
|
DumpRegisters();
|
|
#endif
|
|
|
|
// Mark the IRQ as activated and mask it
|
|
#if DEBUG_INTERRUPTS
|
|
DebugStub.Print("Int{0:x2} Acked, Mask={1:x4}\n",
|
|
__arglist(irq + baseVector, irqMask));
|
|
#endif
|
|
|
|
// Quite the interrupt controller.
|
|
IoResult result;
|
|
if (irq >= 8) {
|
|
result = pic1CtrlPort.Write8NoThrow(PIC_NS_EOI);
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
}
|
|
result = pic0CtrlPort.Write8NoThrow(PIC_NS_EOI);
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
|
|
#if PIC_DEBUG
|
|
DumpRegisters();
|
|
#endif
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
public ushort Pending()
|
|
{
|
|
byte irr0;
|
|
byte irr1;
|
|
|
|
IoResult result = pic0CtrlPort.Write8NoThrow(0x04 | 0x02); // OCW3 - read IRR
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
|
|
result = pic0CtrlPort.Read8NoThrow(out irr0);
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
|
|
result = pic1CtrlPort.Write8NoThrow(0x04 | 0x02); // OCW3 - read IRR
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
|
|
result = pic1CtrlPort.Read8NoThrow(out irr1);
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
|
|
return (ushort) (irr0 | (irr1<<8));
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
public override void EnableIrq(byte irq)
|
|
{
|
|
if (irq == 2 || irq >= PIC_VECTORS) {
|
|
DebugStub.Break();
|
|
// throw new OverflowException
|
|
// (String.Format("irq {0} out of range.", irq));
|
|
}
|
|
|
|
#if DEBUG_INTERRUPTS
|
|
DebugStub.Print("Int{0:x2} Enable, Mask={1:x4}\n",
|
|
__arglist(irq + baseVector, irqMask));
|
|
#endif
|
|
|
|
bool saved = Processor.DisableInterrupts();
|
|
try {
|
|
Unmask(irq);
|
|
DumpRegisters();
|
|
}
|
|
finally {
|
|
Processor.RestoreInterrupts(saved);
|
|
}
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
public override void DisableIrq(byte irq)
|
|
{
|
|
if (irq == 2 || irq >= PIC_VECTORS) {
|
|
DebugStub.Break();
|
|
// throw new OverflowException
|
|
// (String.Format("irq {0} out of range.", irq));
|
|
}
|
|
|
|
#if DEBUG_INTERRUPTS
|
|
DebugStub.Print("Int{0:x2} Disable\n",
|
|
__arglist(irq + baseVector));
|
|
#endif
|
|
bool saved = Processor.DisableInterrupts();
|
|
try {
|
|
Mask(irq);
|
|
DumpRegisters();
|
|
}
|
|
finally {
|
|
Processor.RestoreInterrupts(saved);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
[NoHeapAllocation]
|
|
private void Mask(byte irq)
|
|
{
|
|
DebugStub.Assert(Processor.InterruptsDisabled());
|
|
ushort newMask = (ushort)(irqMask | (1 << irq));
|
|
if (newMask != irqMask) {
|
|
#if DEBUG_DISPATCH_IO
|
|
DebugStub.WriteLine("-- Mask IRQs: old={0:x4} new={1:x4}",
|
|
__arglist(irqMask, newMask));
|
|
#endif
|
|
irqMask = newMask;
|
|
IoResult result;
|
|
result = pic1MaskPort.Write8NoThrow((byte)(irqMask >> 8));
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
result = pic0MaskPort.Write8NoThrow((byte)(irqMask & 0xff));
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
#if PIC_DEBUG
|
|
byte mask0;
|
|
pic0MaskPort.Read8NoThrow(out mask0);
|
|
byte mask1;
|
|
pic1MaskPort.Read8NoThrow(out mask1);
|
|
|
|
DebugStub.Print("PIC Mask: {0:x2}{1:x2}\n",
|
|
__arglist(mask1, mask0));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
private void Unmask(byte irq)
|
|
{
|
|
DebugStub.Assert(Processor.InterruptsDisabled());
|
|
ushort newMask = (ushort)(irqMask & ~(1 << irq));
|
|
if (newMask != irqMask) {
|
|
#if DEBUG_DISPATCH_IO
|
|
DebugStub.WriteLine("-- Unmask IRQs: old={0:x4} new={1:x4}",
|
|
__arglist(irqMask, newMask));
|
|
#endif
|
|
irqMask = newMask;
|
|
IoResult result;
|
|
|
|
result = pic1MaskPort.Write8NoThrow((byte)(irqMask >> 8));
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
|
|
result = pic0MaskPort.Write8NoThrow((byte)(irqMask & 0xff));
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
#if PIC_DEBUG
|
|
byte mask0;
|
|
result = pic0MaskPort.Read8(out mask0);
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
|
|
byte mask1;
|
|
result = pic1MaskPort.Read8(out mask1);
|
|
DebugStub.Assert(IoResult.Success == result);
|
|
|
|
DebugStub.Print("PIC Mask: {0:x2}{1:x2}\n",
|
|
__arglist(mask1, mask0));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
public bool IrqMasked(byte irq)
|
|
{
|
|
if (irq >= PIC_VECTORS) {
|
|
return false;
|
|
}
|
|
return (irqMask & (1u << irq)) != 0;
|
|
}
|
|
|
|
private void MaskAll()
|
|
{
|
|
DebugStub.Assert(Processor.InterruptsDisabled());
|
|
pic1MaskPort.Write8(0xff);
|
|
pic0MaskPort.Write8(0xff);
|
|
}
|
|
|
|
private void UnmaskAll()
|
|
{
|
|
DebugStub.Assert(Processor.InterruptsDisabled());
|
|
pic1MaskPort.Write8((byte)(irqMask >> 8));
|
|
pic0MaskPort.Write8((byte)(irqMask & 0xff));
|
|
}
|
|
}
|
|
}
|