//++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blkd1394.cpp // // Abstract: // // This module implements the 1394 transport for KD. // //-- #include "bl.h" #include "blkd1394.h" #if defined(BOOT_X64) BOOLEAN BlKd1394InitHardware( UINT16 Channel, PVOID IoRegion ) { return FALSE; } BOOLEAN BlKd1394Connect( VOID ) { return FALSE; } BOOLEAN BlKd1394SendPacket( UINT16 PacketType, PCVOID Header, UINT16 HeaderSize, PCVOID Data, UINT16 DataSize) { return FALSE; } #else // !defined(BOOT_X64) #define PACKET_READY 0x00000000 // Aka STATUS_SUCCESS #define PACKET_PENDING 0x00000103 // Aka STATUS_PENDING // // Change these macros to debug the debugger transport. // #define KDDBG if (0) BlVideoPrintf #define KDDBG2 if (0) BlVideoPrintf // // These structures are accessed directly by the host using RDMA. // #define DEBUG_BUS1394_MAX_PACKET_SIZE 4000 #define DEBUG_1394_MAJOR_VERSION 0x1 #define DEBUG_1394_MINOR_VERSION 0x0 #define DEBUG_1394_CONFIG_TAG 0xBABABABA typedef struct _DEBUG_1394_SEND_PACKET { UINT32 TransferStatus; UINT32 PacketHeader[4]; UINT32 Length; UINT8 Packet[DEBUG_BUS1394_MAX_PACKET_SIZE]; UINT8 Padding[72]; } DEBUG_1394_SEND_PACKET; C_ASSERT(sizeof(DEBUG_1394_SEND_PACKET) == 4096); typedef struct _DEBUG_1394_RECEIVE_PACKET { UINT32 TransferStatus; UINT32 Length; UINT8 Packet[DEBUG_BUS1394_MAX_PACKET_SIZE]; UINT8 Padding[88]; } DEBUG_1394_RECEIVE_PACKET; C_ASSERT(sizeof(DEBUG_1394_RECEIVE_PACKET) == 4096); typedef struct _DEBUG_1394_CONFIG { UINT32 Tag; UINT16 MajorVersion; UINT16 MinorVersion; UINT32 Id; UINT32 BusPresent; UINT64 SendPacket; UINT64 ReceivePacket; } DEBUG_1394_CONFIG; C_ASSERT(sizeof(DEBUG_1394_CONFIG) == 32); typedef struct _DEBUG_1394_DATA { UINT32 CromBuffer[248]; // our config ROM - must be 1k aligned DEBUG_1394_CONFIG Config; // our config for this session DEBUG_1394_SEND_PACKET SendPacket; // our send packet (isoch packet) DEBUG_1394_RECEIVE_PACKET ReceivePacket; // our receive packet } DEBUG_1394_DATA; C_ASSERT(sizeof(DEBUG_1394_DATA) == 1024 + 4096 + 4096); // // Timing constants. // #define TIMEOUT_COUNT 100000 #define MAX_REGISTER_READS 400000 // // Static Data Structures // static DEBUG_1394_DATA * Kd1394Data = NULL; static volatile OHCI_REGISTER_MAP * KdRegisters = NULL; UINT32 BlKd1394StallExecution( UINT32 LoopCount ) //++ // // Routine Description: // // Stall for a finite time to allow hardware to respond. // // Arguments: // // LoopCount - Number of times to run the outer loop. // // Return Value: // // Ignored. // //-- { volatile UINT32 b; volatile UINT32 k; volatile UINT32 i; b = 1; for (k = 0; k < LoopCount; k++) { BlKdSpin(); for (i = 1; i < 10000; i++) { b = b * (i>>k); } } return b; } UINT32 BlKd1394ByteSwap( UINT32 Source ) //++ // // Routine Description: // // Reverse the order of byte in the UINT32. // // Arguments: // // Source - 32-bit UINT32 value. // // Return Value: // // The input value with byte pairs 0:3 and 1:2 swapped. // //-- { return (((Source) << (8 * 3)) | ((Source & 0x0000FF00) << (8 * 1)) | ((Source & 0x00FF0000) >> (8 * 1)) | ((Source) >> (8 * 3))); } UINT32 BlKd1394Crc16( UINT32 Data, UINT32 Check ) //++ // // Routine Description: // // Derive the 16-bit CRC as defined by IEEE 1212 clause 8.1.5. (ISO/IEC 13213) // First edition 1994-10-05. // // Arguments: // // Data - UINT32 data to derive CRC from. // // Check - check value. // // Return Value: // // The 16-bit CRC. // //-- { UINT32 Next = Check; INT32 Shift; for (Shift = 28; Shift >= 0; Shift -= 4) { UINT32 Sum; Sum = ((Next >> 12) ^ (Data >> Shift)) & 0xf; Next = (Next << 4) ^ (Sum << 12) ^ (Sum << 5) ^ (Sum); } return (Next & 0xFFFF); } UINT16 BlKd1394CalculateCrc( UINT32 *Quadlet, UINT32 Length ) //++ // // Routine Description: // // Calculate a CRC for the pointer to the Quadlet data. // // Arguments: // // Quadlet - Pointer to data to CRC. // // Length - Length of data to CRC. // // Return Value: // // The 16-bit CRC. // //-- { UINT32 Temp = 0; UINT32 Index; Temp = 0; for (Index = 0; Index < Length; Index++) { Temp = BlKd1394Crc16(Quadlet[Index], Temp); } return (UINT16)Temp; } BOOLEAN BlKd1394InitHardware( UINT16 Channel, PVOID IoRegion ) //++ // // Routine Description: // // Initialize the 1394 hardware and connect it to KD. // // Arguments: // // Channel - KD 1394 Channel. Default is channel 0, but can be changed if 1394 is shared. // // IoRegion - Pointer to the 1394 registers mapped into our address space. // // Return Value: // // The 16-bit CRC. // //-- { UINT32 ulVersion; UINT8 MajorVersion; HC_CONTROL_REGISTER HCControl; UINT32 retry; LINK_CONTROL_REGISTER LinkControl; NODE_ID_REGISTER NodeId; BUS_OPTIONS_REGISTER BusOptions; CONFIG_ROM_INFO ConfigRomHeader; IMMEDIATE_ENTRY CromEntry; DIRECTORY_INFO DirInfo; PHY_CONTROL_REGISTER PhyControl; UINT8 Data; volatile OHCI_REGISTER_MAP * Registers; #if KD_VERBOSE BlVideoPrintf("1394: IoRegion: %p\n", IoRegion); #endif // // Note: Kd1394Data must be in the low 32-bits of address space due to // limits on valid 1394 DMA addresses. It must also be contiguous. // It must be in the low 24-bits of address space to statisfy KD. // Kd1394Data = (DEBUG_1394_DATA *) BlSingularityOhci1394Buffer; BlRtlZeroMemory(Kd1394Data, sizeof(*Kd1394Data)); // // Get our base address. // Registers = (volatile OHCI_REGISTER_MAP *)IoRegion; // // Initialize our config info for host debugger to read. // Kd1394Data->Config.Tag = DEBUG_1394_CONFIG_TAG; Kd1394Data->Config.MajorVersion = DEBUG_1394_MAJOR_VERSION; Kd1394Data->Config.MinorVersion = DEBUG_1394_MINOR_VERSION; Kd1394Data->Config.Id = Channel; Kd1394Data->Config.BusPresent = FALSE; Kd1394Data->Config.SendPacket = (UINT64) &Kd1394Data->SendPacket; Kd1394Data->Config.ReceivePacket = (UINT64) &Kd1394Data->ReceivePacket; // // Get the transport version. // ulVersion = Registers->Version.all; MajorVersion = (UINT8)(ulVersion >> 16); // // Make sure we have a valid version. // if (MajorVersion != 1) { // INVESTIGATE #if KD_VERBOSE BlVideoPrintf("1394: MajorVersion != 1\n"); #endif return FALSE; } // // Soft reset to initialize the controller. // HCControl.all = 0; HCControl.SoftReset = TRUE; Registers->HCControlSet.all = HCControl.all; // // wait until reset completes. // retry = 1000; // ?? do { HCControl.all = Registers->HCControlSet.all; BlKd1394StallExecution(1); } while ((HCControl.SoftReset) && (--retry)); if (retry == 0) { #if KD_VERBOSE BlVideoPrintf("1394: Reset failed\n"); #endif return FALSE; } // // Enable link to phy communication. // HCControl.all = 0; HCControl.Lps = TRUE; Registers->HCControlSet.all = HCControl.all; BlKd1394StallExecution(20); // // Initialize HCControl register // Send data in little-endian order (i.e. do byte swap). // HCControl.all = 0; HCControl.NoByteSwapData = TRUE; Registers->HCControlClear.all = HCControl.all; // // Enable posted writes. // HCControl.all = 0; HCControl.PostedWriteEnable = TRUE; Registers->HCControlSet.all = HCControl.all; // // Setup the link control. // LinkControl.all = 0; LinkControl.CycleTimerEnable = TRUE; LinkControl.CycleMaster = TRUE; LinkControl.RcvPhyPkt = TRUE; LinkControl.RcvSelfId = TRUE; Registers->LinkControlClear.all = LinkControl.all; LinkControl.all = 0; LinkControl.CycleTimerEnable = TRUE; LinkControl.CycleMaster = TRUE; Registers->LinkControlSet.all = LinkControl.all; // // Set the bus number (hardcoded to 0x3FF) - ??? what about node id?? // NodeId.all = 0; NodeId.BusId = (UINT16)0x3FF; Registers->NodeId.all = NodeId.all; // // Do something with the crom... // // // 0xf0000404 - bus id register // Kd1394Data->CromBuffer[1] = 0x31333934; // // 0xf0000408 - bus options register // BusOptions.all = BlKd1394ByteSwap(Registers->BusOptions.all); BusOptions.Pmc = FALSE; BusOptions.Bmc = FALSE; BusOptions.Isc = FALSE; BusOptions.Cmc = FALSE; BusOptions.Irmc = FALSE; BusOptions.g = 1; Kd1394Data->CromBuffer[2] = BlKd1394ByteSwap(BusOptions.all); // // 0xf000040c - global unique id hi // Kd1394Data->CromBuffer[3] = Registers->GuidHi; // // 0xf0000410 - global unique id lo // Kd1394Data->CromBuffer[4] = Registers->GuidLo; // // 0xf0000400 - config ROM header - set last to calculate CRC! // ConfigRomHeader.all = 0; ConfigRomHeader.CRI_Info_Length = 4; ConfigRomHeader.CRI_CRC_Length = 4; ConfigRomHeader.CRI_CRC_Value = BlKd1394CalculateCrc(&Kd1394Data->CromBuffer[1], ConfigRomHeader.CRI_CRC_Length); Kd1394Data->CromBuffer[0] = ConfigRomHeader.all; Kd1394Data->CromBuffer[6] = 0xC083000C; // 0xf0000418 - node capabilities Kd1394Data->CromBuffer[7] = 0xF2500003; // 0xf000041C - module vendor id // // KD's state machine looks for 1c w/ 50f2, 1d w/ 02, then 1e w/ address. // Kd1394Data->CromBuffer[8] = 0xF250001C; // 0xf0000420 - extended key (for KD) Kd1394Data->CromBuffer[9] = 0x0200001D; // 0xf0000424 - debug key (for KD) // // 0xf0000428 - debug value (for KD) // CromEntry.all = (UINT32)(ULONG_PTR) &Kd1394Data->Config; CromEntry.IE_Key = 0x1E; Kd1394Data->CromBuffer[10] = BlKd1394ByteSwap(CromEntry.all); // // 0xf0000414 - root directory header - set last to calculate CRC! // DirInfo.all = 0; DirInfo.DI_Length = 5; DirInfo.DI_CRC = BlKd1394CalculateCrc(&Kd1394Data->CromBuffer[6], DirInfo.DI_Length); Kd1394Data->CromBuffer[5] = BlKd1394ByteSwap(DirInfo.all); // // Write the first few registers. // Registers->ConfigRomHeader.all = Kd1394Data->CromBuffer[0]; Registers->BusId = Kd1394Data->CromBuffer[1]; Registers->BusOptions.all = Kd1394Data->CromBuffer[2]; Registers->GuidHi = Kd1394Data->CromBuffer[3]; Registers->GuidLo = Kd1394Data->CromBuffer[4]; // // Set our crom. // Registers->ConfigRomMap = (UINT32)(ULONG_PTR) &Kd1394Data->CromBuffer; // // Disable all interrupts, we use polling for the debugger transport. // Registers->IntMaskClear.all = 0xFFFFFFFF; // // Enable the link. // HCControl.all = 0; HCControl.LinkEnable = TRUE; Registers->HCControlSet.all = HCControl.all; BlKd1394StallExecution(1000); // // Enable access filters to all nodes. // Registers->AsynchReqFilterLoSet = 0xFFFFFFFF; Registers->AsynchReqFilterHiSet = 0xFFFFFFFF; Registers->PhyReqFilterHiSet = 0xFFFFFFFF; Registers->PhyReqFilterLoSet = 0xFFFFFFFF; // // Hard reset on the bus (so KD will look for us). // PhyControl.all = 0; PhyControl.RdReg = TRUE; PhyControl.RegAddr = 1; Registers->PhyControl.all = PhyControl.all; retry = MAX_REGISTER_READS; do { PhyControl.all = Registers->PhyControl.all; } while ((!PhyControl.RdDone) && --retry); if (retry == 0) { #if KD_VERBOSE BlVideoPrintf("1394: Bus read failed.\n"); #endif return FALSE; } Data = ((UINT8)PhyControl.RdData | PHY_INITIATE_BUS_RESET); PhyControl.all = 0; PhyControl.WrReg = TRUE; PhyControl.RegAddr = 1; PhyControl.WrData = Data; Registers->PhyControl.all = PhyControl.all; retry = MAX_REGISTER_READS; do { PhyControl.all = Registers->PhyControl.all; } while (PhyControl.WrReg && --retry); if (retry == 0) { #if KD_VERBOSE BlVideoPrintf("1394: Hard reset of bus failed\n"); #endif return FALSE; } #if KD_VERBOSE BlVideoPrintf("1394: Hardware init succeeded.\n"); #endif KdRegisters = Registers; return TRUE; } VOID BlKd1394EnablePhysicalAccess( VOID ) { HC_CONTROL_REGISTER HCControl; INT_EVENT_MASK_REGISTER IntEvent; // // See if ohci1394 is being loaded... // HCControl.all = KdRegisters->HCControlSet.all; if (!HCControl.LinkEnable || !HCControl.Lps || HCControl.SoftReset) { KDDBG("1394: EnablePhysicalAccess HCControl=%08x!\n", HCControl.all); return; } // // If the bus reset interrupt is not cleared, we have to clear it... // IntEvent.all = KdRegisters->IntEventSet.all; if (IntEvent.BusReset) { KDDBG("1394: EnablePhysicalAccess IntEvent =%08x!\n", IntEvent.all); IntEvent.all = 0; IntEvent.BusReset = 1; KdRegisters->IntEventClear.all = IntEvent.all; } // // Re-enable physical access as it may be necessary. // KdRegisters->AsynchReqFilterHiSet = 0xFFFFFFFF; KdRegisters->AsynchReqFilterLoSet = 0xFFFFFFFF; KdRegisters->PhyReqFilterHiSet = 0xFFFFFFFF; KdRegisters->PhyReqFilterLoSet = 0xFFFFFFFF; return; } BOOLEAN BlKd1394SendPacket( UINT16 PacketType, PCVOID Header, UINT16 HeaderSize, PCVOID Data, UINT16 DataSize) //++ // // Routine Description: // // This routine sends a packet to the host machine that is running the kernel debugger and // waits for an ACK. // // Arguments: // // PacketType - Supplies the type of the packet to send. // // Header - Supplies a pointer to the header. // // HeaderSize - Supplies the size of the header. // // Data - Supplies a pointer to the data. // // DataSize - Supplies the size of the data. // // Return Value: // // TRUE, if send operation was successful. // FALSE, otherwise. // //-- { KD_PACKET PacketHeader; UINT32 Retries; UINT32 count; volatile UINT32 *pStatus; KDDBG2("BlKd1394SendPacket\n"); // // Abort if the hardware hasn't been initialized. // if (KdRegisters == NULL) { return FALSE; } // // Initialize the packet header. // PacketHeader.PacketLeader = KD_PACKET_LEADER; PacketHeader.ByteCount = HeaderSize + DataSize; PacketHeader.PacketType = PacketType; PacketHeader.PacketId = BlKdNextPacketId++; PacketHeader.Checksum = (BlKdComputeChecksum(Header, HeaderSize) + BlKdComputeChecksum(Data, DataSize)); // // Setup our send packet. // BlRtlZeroMemory(&Kd1394Data->SendPacket, sizeof(DEBUG_1394_SEND_PACKET)); Kd1394Data->SendPacket.Length = 0; // Redundant. // // Copy our packet header into the transmit region. // BlRtlCopyMemory(&Kd1394Data->SendPacket.PacketHeader[0], &PacketHeader, sizeof(KD_PACKET)); // // Setup our message header. // if (HeaderSize > 0) { BlRtlCopyMemory(&Kd1394Data->SendPacket.Packet[0], Header, HeaderSize); Kd1394Data->SendPacket.Length = HeaderSize; } // // Setup our message data. // if (DataSize > 0) { BlRtlCopyMemory(&Kd1394Data->SendPacket.Packet[Kd1394Data->SendPacket.Length], Data, DataSize); Kd1394Data->SendPacket.Length += DataSize; } // // Mark the packet as ready for processing by host. // Kd1394Data->SendPacket.TransferStatus = PACKET_PENDING; // // Wait for our packet to be acknowledged by the host. // for (Retries = KD_RETRY_COUNT; Retries > 0; Retries--) { KDDBG2("LOOP %d [SendPacket=%p %08x %08x %08x %02x %02x %02x %02x]\n", Retries, &Kd1394Data->SendPacket, Kd1394Data->SendPacket.TransferStatus, * (UINT32*) &Kd1394Data->SendPacket.PacketHeader, Kd1394Data->SendPacket.Length, Kd1394Data->SendPacket.Packet[0], Kd1394Data->SendPacket.Packet[1], Kd1394Data->SendPacket.Packet[2], Kd1394Data->SendPacket.Packet[3]); // // make sure our link is enabled.. // BlKd1394EnablePhysicalAccess(); pStatus = &Kd1394Data->ReceivePacket.TransferStatus; // // now sit here and poll for a response from the host machine // for (count = 0; count < TIMEOUT_COUNT; count++) { // // make sure our link is enabled.. // BlKd1394EnablePhysicalAccess(); BlKdSpin(); // // Check to see if the host has ACK'd our packet. // if (Kd1394Data->SendPacket.TransferStatus != PACKET_PENDING) { return TRUE; } // // While in this loop check if the host has submitted a new request. // If they did, ACK it, and retry. // if (*pStatus == PACKET_PENDING) { // // ACK the packet from the debugger so it will accept our packet. // *pStatus = PACKET_READY; } } } return FALSE; } BOOLEAN BlKd1394Connect( VOID ) //++ // // Routine Description: // // This function tries to connect to the KD through a COM port. // // Return Value: // // TRUE, if connection was successful. // FALSE, otherwise. // //-- { // // Abort if there is no 1394 hardware. // if (BlPciOhci1394BaseAddress == 0) { return FALSE; } // // Initialize the underlying hardware. // if (BlKd1394InitHardware(0, (PVOID)(ULONG_PTR) BlPciOhci1394BaseAddress)) { KD_DEBUG_IO Packet; // // Send a test packet to verify the debugger is attached. // BlRtlZeroMemory(&Packet, sizeof(Packet)); Packet.ApiNumber = KD_API_PRINT_STRING; Packet.u1.PrintString.LengthOfString = 0; if (BlKd1394SendPacket(KD_PACKET_TYPE_KD_DEBUG_IO, &Packet, sizeof(Packet), L"1394!\n", 7)) { return TRUE; } } BlPciOhci1394BaseAddress = 0; return FALSE; } #endif // !defined(BOOT_X64)