📄 gart.c
字号:
BOOLEAN Backwards;
PAGED_CODE();
ASSERT((Range->Type == MmNonCached) || (Range->Type == MmWriteCombined));
if (Range->NumberOfPages > (AgpContext->ApertureLength / PAGE_SIZE)) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// If we have not allocated our GART yet, now is the time to do so
//
if (AgpContext->Gart == NULL) {
ASSERT(AgpContext->GartLength == 0);
Status = Agp440CreateGart(AgpContext,Range->NumberOfPages);
if (!NT_SUCCESS(Status)) {
AGPLOG(AGP_CRITICAL,
("Agp440CreateGart failed %08lx to create GART of size %lx\n",
Status,
AgpContext->ApertureLength));
return(Status);
}
}
ASSERT(AgpContext->GartLength != 0);
//
// Now that we have a GART, try and find enough contiguous entries to satisfy
// the request. Requests for uncached memory will scan from high addresses to
// low addresses. Requests for write-combined memory will scan from low addresses
// to high addresses. We will use a first-fit algorithm to try and keep the allocations
// packed and contiguous.
//
Backwards = (Range->Type == MmNonCached) ? TRUE : FALSE;
FoundRange = Agp440FindRangeInGart(&AgpContext->Gart[0],
&AgpContext->Gart[(AgpContext->GartLength / sizeof(GART_PTE)) - 1],
Range->NumberOfPages,
Backwards,
GART_ENTRY_FREE);
if (FoundRange == NULL) {
//
// A big enough chunk was not found.
//
AGPLOG(AGP_CRITICAL,
("AgpReserveMemory - Could not find %d contiguous free pages of type %d in GART at %08lx\n",
Range->NumberOfPages,
Range->Type,
AgpContext->Gart));
//
// This is where we could try and grow the GART
//
return(STATUS_INSUFFICIENT_RESOURCES);
}
AGPLOG(AGP_NOISE,
("AgpReserveMemory - reserved %d pages at GART PTE %08lx\n",
Range->NumberOfPages,
FoundRange));
//
// Set these pages to reserved
//
if (Range->Type == MmNonCached) {
NewState = GART_ENTRY_RESERVED_UC;
} else {
NewState = GART_ENTRY_RESERVED_WC;
}
for (Index = 0;Index < Range->NumberOfPages; Index++) {
ASSERT(FoundRange[Index].Soft.State == GART_ENTRY_FREE);
FoundRange[Index].AsUlong = 0;
FoundRange[Index].Soft.State = NewState;
}
Range->MemoryBase.QuadPart = AgpContext->ApertureStart.QuadPart + (FoundRange - &AgpContext->Gart[0]) * PAGE_SIZE;
Range->Context = FoundRange;
ASSERT(Range->MemoryBase.HighPart == 0);
AGPLOG(AGP_NOISE,
("AgpReserveMemory - reserved memory handle %lx at PA %08lx\n",
FoundRange,
Range->MemoryBase.LowPart));
return(STATUS_SUCCESS);
}
NTSTATUS
AgpReleaseMemory(
IN PAGP440_EXTENSION AgpContext,
IN PAGP_RANGE Range
)
/*++
Routine Description:
Releases memory previously reserved with AgpReserveMemory
Arguments:
AgpContext - Supplies the AGP context
AgpRange - Supplies the range to be released.
Return Value:
NTSTATUS
--*/
{
PGART_PTE Pte;
ULONG Start;
PAGED_CODE();
//
// Go through and free all the PTEs. None of these should still
// be valid at this point.
//
for (Pte = Range->Context;
Pte < (PGART_PTE)Range->Context + Range->NumberOfPages;
Pte++) {
if (Range->Type == MmNonCached) {
ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_UC);
} else {
ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_WC);
}
Pte->Soft.State = GART_ENTRY_FREE;
}
Range->MemoryBase.QuadPart = 0;
return(STATUS_SUCCESS);
}
NTSTATUS
Agp440CreateGart(
IN PAGP440_EXTENSION AgpContext,
IN ULONG MinimumPages
)
/*++
Routine Description:
Allocates and initializes an empty GART. The current implementation
attempts to allocate the entire GART on the first reserve.
Arguments:
AgpContext - Supplies the AGP context
MinimumPages - Supplies the minimum size (in pages) of the GART to be
created.
Return Value:
NTSTATUS
--*/
{
PGART_PTE Gart;
ULONG GartLength;
PHYSICAL_ADDRESS HighestAcceptable;
PHYSICAL_ADDRESS LowestAcceptable;
PHYSICAL_ADDRESS BoundaryMultiple;
PHYSICAL_ADDRESS GartPhysical;
ULONG i;
PAGED_CODE();
//
// Try and get a chunk of contiguous memory big enough to map the
// entire aperture.
//
LowestAcceptable.QuadPart = 0;
BoundaryMultiple.QuadPart = 0;
HighestAcceptable.QuadPart = 0xFFFFFFFF;
GartLength = BYTES_TO_PAGES(AgpContext->ApertureLength) * sizeof(GART_PTE);
Gart = MmAllocateContiguousMemorySpecifyCache(GartLength,
LowestAcceptable,
HighestAcceptable,
BoundaryMultiple,
MmNonCached);
if (Gart == NULL) {
AGPLOG(AGP_CRITICAL,
("Agp440CreateGart - MmAllocateContiguousMemorySpecifyCache %lx failed\n",
GartLength));
return(STATUS_INSUFFICIENT_RESOURCES);
}
//
// We successfully allocated a contiguous chunk of memory.
// It should be page aligned already.
//
ASSERT(((ULONG_PTR)Gart & (PAGE_SIZE-1)) == 0);
//
// Get the physical address.
//
GartPhysical = MmGetPhysicalAddress(Gart);
AGPLOG(AGP_NOISE,
("Agp440CreateGart - GART of length %lx created at VA %08lx, PA %08lx\n",
GartLength,
Gart,
GartPhysical.LowPart));
ASSERT(GartPhysical.HighPart == 0);
ASSERT((GartPhysical.LowPart & (PAGE_SIZE-1)) == 0);
//
// Initialize all the PTEs to free
//
for (i=0; i<GartLength/sizeof(GART_PTE); i++) {
Gart[i].Soft.State = GART_ENTRY_FREE;
}
Write440Config(&GartPhysical.LowPart, ATTBASE_OFFSET, sizeof(GartPhysical.LowPart));
//
// Update our extension to reflect the current state.
//
AgpContext->Gart = Gart;
AgpContext->GartLength = GartLength;
AgpContext->GartPhysical = GartPhysical;
return(STATUS_SUCCESS);
}
NTSTATUS
AgpMapMemory(
IN PAGP440_EXTENSION AgpContext,
IN PAGP_RANGE Range,
IN PMDL Mdl,
IN ULONG OffsetInPages,
OUT PHYSICAL_ADDRESS *MemoryBase
)
/*++
Routine Description:
Maps physical memory into the GART somewhere in the specified range.
Arguments:
AgpContext - Supplies the AGP context
Range - Supplies the AGP range that the memory should be mapped into
Mdl - Supplies the MDL describing the physical pages to be mapped
OffsetInPages - Supplies the offset into the reserved range where the
mapping should begin.
MemoryBase - Returns the physical memory in the aperture where the pages
were mapped.
Return Value:
NTSTATUS
--*/
{
ULONG PageCount;
PGART_PTE Pte;
PGART_PTE StartPte;
ULONG Index;
ULONG TargetState;
PPFN_NUMBER Page;
BOOLEAN Backwards;
GART_PTE NewPte;
PACCFG PACConfig;
PAGED_CODE();
ASSERT(Mdl->Next == NULL);
StartPte = Range->Context;
PageCount = BYTES_TO_PAGES(Mdl->ByteCount);
ASSERT(PageCount <= Range->NumberOfPages);
ASSERT(OffsetInPages <= Range->NumberOfPages);
ASSERT(PageCount + OffsetInPages <= Range->NumberOfPages);
ASSERT(PageCount > 0);
TargetState = (Range->Type == MmNonCached) ? GART_ENTRY_RESERVED_UC : GART_ENTRY_RESERVED_WC;
Pte = StartPte + OffsetInPages;
//
// We have a suitable range, now fill it in with the supplied MDL.
//
ASSERT(Pte >= StartPte);
ASSERT(Pte + PageCount <= StartPte + Range->NumberOfPages);
NewPte.AsUlong = 0;
NewPte.Soft.State = (Range->Type == MmNonCached) ? GART_ENTRY_VALID_UC :
GART_ENTRY_VALID_WC;
Page = (PPFN_NUMBER)(Mdl + 1);
//
// Disable the TB as per the 440 spec. This is probably unnecessary
// as there should be no valid entries in this range, and there should
// be no invalid entries still in the TB. So flushing the TB seems
// a little gratuitous but that's what the 440 spec says to do.
//
Agp440DisableTB(AgpContext);
for (Index = 0; Index < PageCount; Index++) {
ASSERT(Pte[Index].Soft.State == TargetState);
NewPte.Hard.Page = (ULONG)(*Page++);
Pte[Index].AsUlong = NewPte.AsUlong;
ASSERT(Pte[Index].Hard.Valid == 1);
}
//
// We have filled in all the PTEs. Read back the last one we wrote
// in order to flush the write buffers.
//
NewPte.AsUlong = *(volatile ULONG *)&Pte[PageCount-1].AsUlong;
//
// Re-enable the TB
//
Agp440EnableTB(AgpContext);
//
// If we have not yet gotten around to enabling the GART aperture, do it now.
//
if (!AgpContext->GlobalEnable) {
AGPLOG(AGP_NOISE,
("AgpMapMemory - Enabling global aperture access\n"));
Read440Config(&PACConfig, PACCFG_OFFSET, sizeof(PACConfig));
PACConfig.GlobalEnable = 1;
Write440Config(&PACConfig, PACCFG_OFFSET, sizeof(PACConfig));
AgpContext->GlobalEnable = TRUE;
}
MemoryBase->QuadPart = Range->MemoryBase.QuadPart + (Pte - StartPte) * PAGE_SIZE;
return(STATUS_SUCCESS);
}
NTSTATUS
AgpUnMapMemory(
IN PAGP440_EXTENSION AgpContext,
IN PAGP_RANGE AgpRange,
IN ULONG NumberOfPages,
IN ULONG OffsetInPages
)
/*++
Routine Description:
Unmaps previously mapped memory in the GART.
Arguments:
AgpContext - Supplies the AGP context
AgpRange - Supplies the AGP range that the memory should be freed from
NumberOfPages - Supplies the number of pages in the range to be freed.
OffsetInPages - Supplies the offset into the range where the freeing should begin.
Return Value:
NTSTATUS
--*/
{
ULONG i;
PGART_PTE Pte;
PGART_PTE LastChanged=NULL;
PGART_PTE StartPte;
ULONG NewState;
PAGED_CODE();
ASSERT(OffsetInPages + NumberOfPages <= AgpRange->NumberOfPages);
StartPte = AgpRange->Context;
Pte = &StartPte[OffsetInPages];
if (AgpRange->Type == MmNonCached) {
NewState = GART_ENTRY_RESERVED_UC;
} else {
NewState = GART_ENTRY_RESERVED_WC;
}
//
// Disable the TB to flush it
//
Agp440DisableTB(AgpContext);
for (i=0; i<NumberOfPages; i++) {
if (Pte[i].Hard.Valid) {
Pte[i].Soft.State = NewState;
LastChanged = Pte;
} else {
//
// This page is not mapped, just skip it.
//
AGPLOG(AGP_NOISE,
("AgpUnMapMemory - PTE %08lx (%08lx) at offset %d not mapped\n",
&Pte[i],
Pte[i].AsUlong,
i));
ASSERT(Pte[i].Soft.State == NewState);
}
}
//
// We have invalidated all the PTEs. Read back the last one we wrote
// in order to flush the write buffers.
//
if (LastChanged != NULL) {
ULONG Temp;
Temp = *(volatile ULONG *)(&LastChanged->AsUlong);
}
//
// Reenable the TB
//
Agp440EnableTB(AgpContext);
return(STATUS_SUCCESS);
}
PGART_PTE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -