/* Portions adapted with reference to RXDK-Libs (2026 Team Resurgent), * GPL-3.0-or-later. See libs/d3d8/PROVENANCE.md and libs/d3d8/LICENSE.GPL-3.0. * Original January target bytes and PDB remain the matching authority. */ /* January miniport helpers. Contracts and register accesses come from the * supplied target/PDB, not from a later miniport implementation. */ #include "hardware_internal.h" #include "miniport_constants.h" #include "display_internal.h" #include "kernel_interrupt.h" #include "kernel_clock.h" #include #pragma intrinsic(_outp) #pragma code_seg("D3D") namespace D3D { DWORD CMiniport::ReserveInstMem( DWORD paragraphs) { DWORD address = m_FreeInstAddr; m_FreeInstAddr += paragraphs; return address; } int CMiniport::MapRegisters( void) { /* NV2A fixed kernel MMIO mapping in this Xbox build. These are hardware * registers: volatility is required for the actual device transaction. */ _HWREG *base = (_HWREG *)0xfd000000UL; m_RegisterBase = base; REG_WR32(base, 0x1804, REG_RD32(base, 0x1804) | 4); REG_WR32(base, 0x600140, 0); REG_WR32(base, 0x9140, 0); return TRUE; } void CMiniport::TmrDelay( DWORD nanoseconds) { _HWREG *base = (_HWREG *)m_RegisterBase; DWORD start = REG_RD32(base, 0x9400); while (REG_RD32(base, 0x9400) - start < nanoseconds) { } return; } void CMiniport::InitGammaRamp( DWORD bank) { D3DGAMMARAMP *ramp = &m_GammaRamp[bank]; for (DWORD value = 0; value < 256; ++value) { ramp->red[value] = (BYTE)value; ramp->green[value] = (BYTE)value; ramp->blue[value] = (BYTE)value; } return; } } namespace D3D { int CMiniport::GetGeneralInfo( void) { _HWREG *base = (_HWREG *)m_RegisterBase; m_GenInfo.ChipId = (REG_RD32(base, 0x1800) >> 16) & 0xfffc; m_GenInfo.MaskRevision = REG_RD32(base, 0x1808) & 0xff; m_GenInfo.VideoRamSize = REG_RD32(base, 0x10020c); m_GenInfo.CrystalFreq = 16666666; return TRUE; } void CMiniport::GetAddressInfo( void *linearAddress, void **address, DWORD *addressSpace, int isAlias) { if (isAlias) { *address = (void *)(((DWORD)linearAddress & 0x0fffffffUL) | 0x40000000UL); *addressSpace = ADDR_AGPMEM; } else if (((DWORD)linearAddress & 0xf0000000UL) != 0x80000000UL) { *address = linearAddress; *addressSpace = ADDR_FBMEM; } else { *address = (void *)((DWORD)linearAddress & 0x03ffffffUL); *addressSpace = ADDR_SYSMEM; } return; } int CMiniport::BindToChannel( OBJECTINFO *object) { DWORD handle = object->Handle; DWORD hash = (((handle >> 11) ^ handle) >> 11) ^ handle; HalFifoHashAdd(hash & 0x7ff, handle, m_HalInfo.FifoChID, object->Instance, object->Engine); return TRUE; } int CMiniport::InitDMAChannel( DWORD classNumber, OBJECTINFO *errorContext, OBJECTINFO *dataContext, DWORD offset, void **channel) { /* The January routine uses fixed channel/class/offset values. The public * parameters remain because they are part of the recorded interface. */ m_HalInfo.FifoChID = 0; m_HalInfo.FifoMode = 0; m_HalInfo.FifoAllocCount = 0; m_HalInfo.FifoObjectCount = 0; m_HalInfo.FifoInstance = ReserveInstMem(0x37f); HalFifoAllocDMA(0x80, 0x80, 8, dataContext); *channel = (BYTE *)m_RegisterBase + ((m_HalInfo.FifoChID + 0x80) << 16); return TRUE; } int CMiniport::CreateGrObject( DWORD handle, DWORD classNumber, OBJECTINFO *object) { BOOL is3d = FALSE; DWORD instanceSize; switch (classNumber) { case NV03_NULL: case NV03_MEMORY_TO_MEMORY_FORMAT: case NV10_CONTEXT_SURFACES_2D: case NV12_IMAGE_BLIT: instanceSize = 16; break; case NV20_KELVIN_PRIMITIVE: instanceSize = 0x330; is3d = TRUE; break; default: instanceSize = classNumber; break; } DWORD instance = ReserveInstMem(instanceSize >> 4); if (is3d) { m_HalInfo.GrCurrentObjects3d[m_HalInfo.FifoChID] = instance; HalGrInit3d(); } HalGrInitObjectContext(instance, classNumber); object->Init(); object->Handle = handle; object->ClassNum = classNumber; object->Instance = instance; object->Engine = 1; BindToChannel(object); return TRUE; } int CMiniport::CreateCtxDmaObject( DWORD handle, DWORD classNumber, void *baseAddress, DWORD limit, OBJECTINFO *object) { _HWREG *base = (_HWREG *)m_RegisterBase; void *address = NULL; DWORD addressSpace = 0; GetAddressInfo(baseAddress, &address, &addressSpace, FALSE); DWORD instance = ReserveInstMem(1); DWORD page = (DWORD)address | 3; DWORD flags = 0; switch (classNumber) { case NV01_CONTEXT_DMA_FROM_MEMORY: flags = NV01_CONTEXT_DMA_FROM_MEMORY; break; case NV01_CONTEXT_DMA_TO_MEMORY: flags = NV01_CONTEXT_DMA_TO_MEMORY; break; case NV01_CONTEXT_DMA_IN_MEMORY: flags = NV01_CONTEXT_DMA_IN_MEMORY; break; } flags |= ((DWORD)address << 20) | 0x3000; switch (addressSpace) { case ADDR_FBMEM: break; case ADDR_AGPMEM: flags |= 0x30000; break; case ADDR_SYSMEM: flags |= 0x20000; break; } REG_WR32(base, 0x700008 + (instance << 4), page); REG_WR32(base, 0x70000c + (instance << 4), page); flags |= 0x8000; REG_WR32(base, (0x70000 + instance) << 4, flags); REG_WR32(base, 0x700004 + (instance << 4), limit); object->Init(); object->Engine = 0; object->Handle = handle; object->ClassNum = classNumber; object->Instance = instance; return TRUE; } } namespace D3D { int CMiniport::InitEngines( void) { _HWREG *base = (_HWREG *)m_RegisterBase; REG_WR32(base, 0x1830, 0); REG_WR32(base, 0x180c, 0xf800); HalMcControlInit(); m_GenInfo.ChipIntrEn0 = 1; // Reduce the clock ratio before encoding the 16-bit timer fractions. // The original calculation uses signed clock intermediates and unsigned // range comparisons; real device clock rates are positive. long numerator = (long)m_DacInfo.NVClk; long denominator = 31250000; while (numerator % 2 == 0 && denominator % 2 == 0) { numerator /= 2; denominator /= 2; } while (numerator % 5 == 0 && denominator % 5 == 0) { numerator /= 5; denominator /= 5; } while ((DWORD)numerator > 0x1fffe || (DWORD)denominator > 0x1fffe) { numerator /= 2; denominator /= 2; } REG_WR32(base, 0x9200, (numerator + 1) / 2); REG_WR32(base, 0x9210, (denominator + 1) / 2); REG_WR32(base, 0x9420, 0xffffffffUL); HalFbControlInit(); HalDacControlInit(); InitGammaRamp(0); HalVideoControlInit(); m_HalInfo.GrChID = 2; HalGrControlInit(); HalFifoControlInit(); return TRUE; } } namespace D3D { /* Drain the actual FIFO/graphics pipeline before modifying tile/context state. * Hardware status bits may change asynchronously; all polls are MMIO accesses. */ void CMiniport::TilingUpdateIdle( DWORD *savedPush) { _HWREG *base = (_HWREG *)m_RegisterBase; while (!(REG_RD32(base, 0x3214) & 0x10) || !(REG_RD32(base, 0x2400) & 0x10) || (REG_RD32(base, 0x3220) & 0x10)) { ServiceFifoInterrupt(); if (REG_RD32(base, 0x400100)) { ServiceGrInterrupt(); } if (REG_RD32(base, 0x100) & 0x1000000) { VBlank(); } } *savedPush = REG_RD32(base, 0x3220); REG_WR32(base, 0x3220, 0); while (REG_RD32(base, 0x3220) & 0x10) { } return; } void CMiniport::ShutdownEngines( void) { _HWREG *base = (_HWREG *)m_RegisterBase; if (!AvGetSavedDataAddress()) { AvSendTVEncoderOption(base, AV_OPTION_BLANK_SCREEN, TRUE, NULL); } for (int tile = 0; tile < 8; ++tile) { DestroyTile(tile, TRUE); } REG_WR32(base, 0x2044, 0); // Shutdown has its own drain sequence: unlike TilingUpdateIdle it does not // retain the DMA push register for resuming later. This separation is also // present in the pinned mpcore reference, not manual helper expansion. while (!(REG_RD32(base, 0x3214) & 0x10) || !(REG_RD32(base, 0x2400) & 0x10) || (REG_RD32(base, 0x3220) & 0x10)) { ServiceFifoInterrupt(); if (REG_RD32(base, 0x400100)) { ServiceGrInterrupt(); } if (REG_RD32(base, 0x100) & 0x1000000) { VBlank(); } } REG_WR32(base, 0x3220, 0); while (REG_RD32(base, 0x3220) & 0x10) { } REG_WR32(base, 0x2500, 0); REG_WR32(base, 0x3000, 0); REG_WR32(base, 0x3050, 0); REG_WR32(base, 0x3200, 0); REG_WR32(base, 0x3250, 0); HalFifoContextSwitch(1); REG_WR32(base, 0x3210, 0); REG_WR32(base, 0x3270, 0); DWORD fifoReassign = REG_RD32(base, 0x2500); DWORD fifoPush = REG_RD32(base, 0x3200); DWORD fifoPull = REG_RD32(base, 0x3250); REG_WR32(base, 0x2500, 0); REG_WR32(base, 0x3200, 0); REG_WR32(base, 0x3250, 0); for (DWORD channel = 0; channel < 2; ++channel) { if (m_HalInfo.FifoInUse) { REG_WR32(base, m_HalInfo.FifoContextAddr1 + channel * 64 + 4, REG_RD32(base, m_HalInfo.FifoContextAddr1 + channel * 64)); REG_WR32(base, m_HalInfo.FifoContextAddr1 + channel * 64 + 16, 0); } } REG_WR32(base, 0x3250, fifoPull); REG_WR32(base, 0x3200, fifoPush); REG_WR32(base, 0x2500, fifoReassign); REG_WR32(base, 0x2508, 0); REG_WR32(base, 0x2140, 0); HalGrLoadChannelContext(2); REG_WR32(base, 0x100200, m_HalInfo.FbSave0); REG_WR32(base, 0x100204, m_HalInfo.FbSave1); REG_WR32(base, 0x200, m_HalInfo.McSave); REG_WR32(base, 0x140, m_HalInfo.McSaveIntrEn0); HalRegisterShutdownNotification( &m_ShutdownRegistration, FALSE); KeDisconnectInterrupt(&m_InterruptObject); return; } } namespace D3D { /* Tile lifecycle reconstructed from January target accesses and corroborated * by pinned RXDK mpcore. Valid callers provide tile indices below eight and * aligned, GPU-addressable regions. Device readbacks can require retrying. */ int CMiniport::CreateTile( DWORD tile, DWORD offset, DWORD size, DWORD pitch, DWORD memoryType, DWORD zTag, DWORD zOffset) { _HWREG *base = (_HWREG *)m_RegisterBase; DWORD dmaPush; TilingUpdateIdle(&dmaPush); do { HalGrIdle(); REG_WR32(base, 0x100244 + tile * 16, offset + size - 1); REG_WR32(base, 0x100248 + tile * 16, pitch); REG_WR32(base, 0x400904 + tile * 16, offset + size - 1); REG_WR32(base, 0x400908 + tile * 16, pitch); if (memoryType & D3DTILE_FLAGS_ZBUFFER) { REG_WR32(base, 0x400900 + tile * 16, offset | 3); REG_WR32(base, 0x100240 + tile * 16, offset | 3); REG_WR32(base, 0x400750, 0xea0000 | ((tile * 4 + 0x10) & 0x1ffc)); REG_WR32(base, 0x400754, offset | 3); } else { REG_WR32(base, 0x400900 + tile * 16, offset | 1); REG_WR32(base, 0x100240 + tile * 16, offset | 1); REG_WR32(base, 0x400750, 0xea0000 | ((tile * 4 + 0x10) & 0x1ffc)); REG_WR32(base, 0x400754, offset | 1); } REG_WR32(base, 0x400750, 0xea0000 | ((tile * 4 + 0x30) & 0x1ffc)); REG_WR32(base, 0x400754, offset + size - 1); REG_WR32(base, 0x400750, 0xea0000 | ((tile * 4 + 0x50) & 0x1ffc)); REG_WR32(base, 0x400754, pitch); } while (REG_RD32(base, 0x100240 + tile * 16) != REG_RD32(base, 0x400900 + tile * 16) || REG_RD32(base, 0x100248 + tile * 16) != REG_RD32(base, 0x400908 + tile * 16) || (REG_RD32(base, 0x100244 + tile * 16) & ~0x3fffUL) != (REG_RD32(base, 0x400904 + tile * 16) & ~0x3fffUL)); if (memoryType & D3DTILE_FLAGS_ZCOMPRESS) { DWORD zData = (zTag / 4) | 0x80000000UL; if (memoryType & D3DTILE_FLAGS_Z32BITS) { zData |= 0x04000000; } do { HalGrIdle(); REG_WR32(base, 0x100300 + tile * 4, zData); REG_WR32(base, 0x400980 + tile * 4, zData); REG_WR32(base, 0x400750, 0xea0000 | ((tile * 4 + 0x90) & 0x1ffc)); REG_WR32(base, 0x400754, zData); } while (REG_RD32(base, 0x100300 + tile * 4) != REG_RD32(base, 0x400980 + tile * 4)); if (zOffset != 0) { do { DWORD zOffsetValue = zOffset | tile | 0x80000000UL; HalGrIdle(); REG_WR32(base, 0x100324, zOffsetValue); REG_WR32(base, 0x4009a0, zOffsetValue); } while (REG_RD32(base, 0x100324) != REG_RD32(base, 0x4009a0)); } } REG_WR32(base, 0x3220, dmaPush); return TRUE; } int CMiniport::DestroyTile( DWORD tile, DWORD zOffset) { _HWREG *base = (_HWREG *)m_RegisterBase; DWORD dmaPush; TilingUpdateIdle(&dmaPush); do { HalGrIdle(); REG_WR32(base, 0x100240 + tile * 16, 0); REG_WR32(base, 0x400900 + tile * 16, 0); REG_WR32(base, 0x400750, 0xea0000 | ((tile * 4 + 0x10) & 0x1ffc)); REG_WR32(base, 0x400754, 0); } while (REG_RD32(base, 0x100240 + tile * 16) != REG_RD32(base, 0x400900 + tile * 16)); REG_WR32(base, 0x100300 + tile * 4, 0); REG_WR32(base, 0x400980 + tile * 4, 0); REG_WR32(base, 0x400750, 0xea0000 | ((tile * 4 + 0x90) & 0x1ffc)); REG_WR32(base, 0x400754, 0); if (zOffset != 0) { REG_WR32(base, 0x100324, 0); REG_WR32(base, 0x4009a0, 0); } REG_WR32(base, 0x3220, dmaPush); return TRUE; } } namespace D3D { int CMiniport::LoadEngines( void) { _HWREG *base = (_HWREG *)m_RegisterBase; DWORD command = REG_RD32(base, 0x184c); REG_WR32(base, 0x184c, command & ~0x300UL); REG_WR32(base, 0x184c, command); REG_WR32(base, 0x200, 0xffffffffUL); EnableInterrupts(); HalDacLoad(); LARGE_INTEGER systemTime; _TIME_FIELDS fields; static const BYTE tmrMonthDays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; KeQuerySystemTime(&systemTime); RtlTimeToTimeFields(&systemTime, &fields); if (fields.Year > 1990) { fields.Year -= 1990; } DWORD days = fields.Year * 365 + (fields.Year + 1) / 4; if (!((fields.Year + 2) & 3) && fields.Month > 2) { ++days; } // Preserve the original timer's month indexing, rather than substituting // a corrected calendar conversion. Kernel TIME_FIELDS months are 1..12. while (--fields.Month) { days += tmrMonthDays[fields.Month]; } days += fields.Day; DWORD highTime = days * 20117 + fields.Hour * 838 + (fields.Minute * 257698 + fields.Second * 4295) / 1000; highTime += 146951526; REG_WR32(base, 0x9400, 0); REG_WR32(base, 0x9410, highTime); REG_WR32(base, 0x400720, 0); HalGrControlLoad(); REG_WR32(base, 0x400100, 0xffffffffUL); REG_WR32(base, 0x400140, 0xffffffffUL); HalFifoControlLoad(); REG_WR32(base, 0x2100, 0xffffffffUL); REG_WR32(base, 0x2140, m_HalInfo.FifoIntrEn0); return TRUE; } int CMiniport::InitHardware( void) { KeInitializeDpc(&m_Dpc, CMiniport::Dpc, this); KeInitializeEvent(&m_BusyBlockEvent, NotificationEvent, TRUE); KeInitializeEvent(&m_VerticalBlankEvent, NotificationEvent, TRUE); if (!MapRegisters()) { return FALSE; } if (!GetGeneralInfo()) { return FALSE; } BYTE interruptIrql; DWORD vector = HalGetInterruptVector(3, &interruptIrql); KeInitializeInterrupt(&m_InterruptObject, CMiniport::Isr, this, vector, interruptIrql, LevelSensitive, TRUE); if (!KeConnectInterrupt(&m_InterruptObject)) { return FALSE; } m_ShutdownRegistration.NotificationRoutine = CMiniport::ShutdownNotification; m_ShutdownRegistration.Priority = 0; HalRegisterShutdownNotification(&m_ShutdownRegistration, TRUE); if (!InitEngines()) { return FALSE; } for (DWORD bank = 0; bank < 2; ++bank) { D3DGAMMARAMP *ramp = &m_GammaRamp[bank]; for (DWORD value = 0; value < 256; ++value) { ramp->red[value] = (BYTE)value; ramp->green[value] = (BYTE)value; ramp->blue[value] = (BYTE)value; } } _outp(0x80c0, 1); m_InterruptsEnabled = TRUE; if (!LoadEngines()) { return FALSE; } return TRUE; } }