12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- arb.c
- Abstract:
- This module implements support for system resource arbiters.
- Author:
- Evan Green 2-Dec-2012
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include "iop.h"
- #include "arb.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Set this flag to make the arbiter print out all requirement and allocation
- // lists.
- //
- #define ARBITER_DEBUG_PRINT_RESOURCES 0x00000001
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- IopFinalizeResourceAllocation (
- PDEVICE Device
- );
- KSTATUS
- IopArbiterAddFreeSpace (
- PRESOURCE_ARBITER Arbiter,
- ULONGLONG FreeSpaceBegin,
- ULONGLONG FreeSpaceLength,
- ULONGLONG FreeSpaceCharacteristics,
- PRESOURCE_ALLOCATION SourcingAllocation,
- ULONGLONG TranslationOffset
- );
- KSTATUS
- IopArbiterAllocateSpace (
- PARBITER_ALLOCATION_CONTEXT Context,
- UINTN RequirementIndex,
- PRESOURCE_REQUIREMENT Alternative
- );
- KSTATUS
- IopArbiterInsertEntry (
- PRESOURCE_ARBITER Arbiter,
- ARBITER_SPACE_TYPE SpaceType,
- PDEVICE ClaimingDevice,
- ULONGLONG Allocation,
- ULONGLONG Length,
- ULONGLONG Characteristics,
- ULONG Flags,
- PRESOURCE_REQUIREMENT RootRequirement,
- PARBITER_ENTRY ExistingEntry,
- PARBITER_ENTRY *NewEntry
- );
- VOID
- IopArbiterFreeEntry (
- PRESOURCE_ARBITER Arbiter,
- PARBITER_ENTRY Entry
- );
- VOID
- IopArbiterDestroy (
- PRESOURCE_ARBITER Arbiter
- );
- PRESOURCE_ARBITER
- IopArbiterFindArbiter (
- PDEVICE Device,
- RESOURCE_TYPE ResourceType
- );
- PARBITER_ENTRY
- IopArbiterFindEntry (
- PRESOURCE_ARBITER Arbiter,
- ULONGLONG Allocation,
- BOOL DependentEntryPreferred
- );
- VOID
- IopArbiterAddRequirement (
- PARBITER_ALLOCATION_CONTEXT Context,
- PRESOURCE_REQUIREMENT Requirement,
- PDEVICE Device
- );
- KSTATUS
- IopArbiterInitializeAllocationContext (
- PDEVICE Device,
- PARBITER_ALLOCATION_CONTEXT *NewContext
- );
- VOID
- IopArbiterDestroyAllocationContext (
- PARBITER_ALLOCATION_CONTEXT Context
- );
- KSTATUS
- IopArbiterSatisfyAllocationContext (
- PARBITER_ALLOCATION_CONTEXT Context
- );
- VOID
- IopArbiterSortRequirements (
- PARBITER_ALLOCATION_CONTEXT Context
- );
- BOOL
- IopArbiterIsFirstRequirementHigherPriority (
- PRESOURCE_REQUIREMENT FirstRequirement,
- PRESOURCE_REQUIREMENT SecondRequirement
- );
- KSTATUS
- IopArbiterRipUpReservedAllocations (
- PARBITER_ALLOCATION_CONTEXT Context
- );
- KSTATUS
- IopArbiterExpandFailingArbiters (
- PARBITER_ALLOCATION_CONTEXT Context
- );
- KSTATUS
- IopArbiterExpandSpace (
- PRESOURCE_ARBITER Arbiter,
- ULONGLONG AmountNeeded
- );
- KSTATUS
- IopArbiterLimitResourceHog (
- PARBITER_ALLOCATION_CONTEXT Context
- );
- KSTATUS
- IopArbiterResizeAllocationContext (
- PARBITER_ALLOCATION_CONTEXT Context,
- ULONG NewDeviceCount,
- ULONG NewRequirementCount
- );
- VOID
- IopArbiterMarkSelectedConfigurations (
- PARBITER_ALLOCATION_CONTEXT Context
- );
- VOID
- IopArbiterMatchAllocationsToRequirements (
- PDEVICE Device,
- PULONG RequirementCount
- );
- VOID
- IopArbiterInitializeResourceAllocation (
- PARBITER_ENTRY ArbiterEntry,
- PRESOURCE_ALLOCATION ResourceAllocation
- );
- KSTATUS
- IopArbiterCopyAndTranslateResources (
- PRESOURCE_ALLOCATION_LIST BusLocalResources,
- PRESOURCE_ALLOCATION_LIST *ProcessorLocalResources
- );
- KSTATUS
- IopArbiterTryBootAllocations (
- PARBITER_ALLOCATION_CONTEXT Context
- );
- KSTATUS
- IopArbiterTryBootAllocation (
- PARBITER_ALLOCATION_CONTEXT Context,
- UINTN RequirementIndex
- );
- PRESOURCE_ALLOCATION
- IopArbiterFindBootAllocationForRequirement (
- PDEVICE Device,
- PRESOURCE_REQUIREMENT Requirement
- );
- VOID
- IopArbiterClearContextAllocations (
- PARBITER_ALLOCATION_CONTEXT Context
- );
- VOID
- IopArbiterLinkContextAllocations (
- PARBITER_ALLOCATION_CONTEXT Context
- );
- KSTATUS
- IopDeferResourceAllocation (
- PDEVICE Device
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Set this value to something nonzero in the debugger to enable arbiter debug
- // options. See ARBITER_DEBUG_* definitions.
- //
- ULONG IoArbiterDebugOptions = 0;
- //
- // ------------------------------------------------------------------ Functions
- //
- KERNEL_API
- KSTATUS
- IoCreateResourceArbiter (
- PDEVICE Device,
- RESOURCE_TYPE ResourceType
- )
- /*++
- Routine Description:
- This routine creates a resource arbiter for the given bus device between
- a system resource and the device's children. This function is needed for
- any device whose children access system resources (like physical address
- space) through a window set up by the parent.
- Arguments:
- Device - Supplies a pointer to the parent bus device that provides
- resources.
- ResourceType - Supplies the type of resource that the device provides.
- Return Value:
- STATUS_SUCCESS if the new arbiter was created.
- STATUS_INVALID_PARAMETER if an invalid resource type was specified.
- STATUS_INSUFFICIENT_RESOURCES on allocation failure.
- STATUS_ALREADY_INITIALIZED if the device has already has a resource arbiter
- of this type.
- --*/
- {
- PRESOURCE_ARBITER Arbiter;
- PLIST_ENTRY CurrentEntry;
- PRESOURCE_ARBITER Existing;
- KSTATUS Status;
- Arbiter = NULL;
- if ((ResourceType == ResourceTypeInvalid) ||
- (ResourceType >= ResourceTypeCount)) {
- Status = STATUS_INVALID_PARAMETER;
- goto CreateResourceArbiterEnd;
- }
- //
- // Look for an existing one.
- //
- CurrentEntry = Device->ArbiterListHead.Next;
- while (CurrentEntry != &(Device->ArbiterListHead)) {
- Existing = LIST_VALUE(CurrentEntry, RESOURCE_ARBITER, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Existing->ResourceType == ResourceType) {
- Status = STATUS_ALREADY_INITIALIZED;
- goto CreateResourceArbiterEnd;
- }
- }
- //
- // Create the arbiter.
- //
- Arbiter = MmAllocatePagedPool(sizeof(RESOURCE_ARBITER),
- ARBITER_ALLOCATION_TAG);
- if (Arbiter == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateResourceArbiterEnd;
- }
- //
- // Initialize and attach the arbiter.
- //
- RtlZeroMemory(Arbiter, sizeof(RESOURCE_ARBITER));
- Arbiter->OwningDevice = Device;
- Arbiter->ResourceType = ResourceType;
- INITIALIZE_LIST_HEAD(&(Arbiter->EntryListHead));
- INSERT_AFTER(&(Arbiter->ListEntry), &(Device->ArbiterListHead));
- Status = STATUS_SUCCESS;
- CreateResourceArbiterEnd:
- if (!KSUCCESS(Status)) {
- if (Arbiter != NULL) {
- MmFreePagedPool(Arbiter);
- }
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoDestroyResourceArbiter (
- PDEVICE Device,
- RESOURCE_TYPE ResourceType
- )
- /*++
- Routine Description:
- This routine destroys all resource arbiters for the given bus device that
- have the provided resource type.
- Arguments:
- Device - Supplies a pointer to the device that owns resource arbitration.
- ResourceType - Supplies the type of resource arbiter that is to be
- destroyed.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ARBITER Arbiter;
- //
- // Find the arbiter. If no arbiter is found, the device is trying to
- // destroy a region without creating an arbiter.
- //
- Arbiter = IopArbiterFindArbiter(Device, ResourceType);
- if (Arbiter == NULL) {
- return STATUS_INVALID_PARAMETER;
- }
- ASSERT(Arbiter->OwningDevice == Device);
- //
- // Destroy the arbiter. This will remove the arbiter from the device's
- // arbiter list.
- //
- IopArbiterDestroy(Arbiter);
- return STATUS_SUCCESS;
- }
- KERNEL_API
- KSTATUS
- IoAddFreeSpaceToArbiter (
- PDEVICE Device,
- RESOURCE_TYPE ResourceType,
- ULONGLONG FreeSpaceBegin,
- ULONGLONG FreeSpaceLength,
- ULONGLONG FreeSpaceCharacteristics,
- PRESOURCE_ALLOCATION SourcingAllocation,
- ULONGLONG TranslationOffset
- )
- /*++
- Routine Description:
- This routine adds a regions of allocatable space to a previously created
- resource arbiter.
- Arguments:
- Device - Supplies a pointer to the device that owns the arbiter (and the
- free space).
- ResourceType - Supplies the resource type that the arbiter can dole out.
- An arbiter of this type must have been created by the device.
- FreeSpaceBegin - Supplies the first address of the free region.
- FreeSpaceLength - Supplies the length of the free region.
- FreeSpaceCharacteristics - Supplies the characteristics of the free
- region.
- SourcingAllocation - Supplies a pointer to the parent resource allocation
- that makes this range possible. This pointer is optional. Supplying
- NULL here implies that the given resource is fixed in nature and
- cannot be expanded.
- TranslationOffset - Supplies the offset that has to be added to all
- doled out allocations on the secondary side to get an address in the
- source allocation space (primary side).
- To recap: SecondaryAddress + TranslationOffset = PrimaryAddress, where
- PrimaryAddress is closer to the CPU complex.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ARBITER Arbiter;
- KSTATUS Status;
- //
- // Find the arbiter. If no arbiter is found, the device is trying to add a
- // region without creating an arbiter.
- //
- Arbiter = IopArbiterFindArbiter(Device, ResourceType);
- if (Arbiter == NULL) {
- return STATUS_INVALID_PARAMETER;
- }
- if (FreeSpaceLength == 0) {
- return STATUS_SUCCESS;
- }
- Status = IopArbiterAddFreeSpace(Arbiter,
- FreeSpaceBegin,
- FreeSpaceLength,
- FreeSpaceCharacteristics,
- SourcingAllocation,
- TranslationOffset);
- return Status;
- }
- KERNEL_API
- PRESOURCE_ALLOCATION_LIST
- IoGetProcessorLocalResources (
- PDEVICE Device
- )
- /*++
- Routine Description:
- This routine returns the given device's processor local resources.
- Arguments:
- Device - Supplies a pointer to the device that owns the resources.
- Return Value:
- Returns a pointer to the processor local resource allocation list.
- --*/
- {
- return Device->ProcessorLocalResources;
- }
- KSTATUS
- IopProcessResourceRequirements (
- PDEVICE Device
- )
- /*++
- Routine Description:
- This routine attempts to find the best set of resources for a given device.
- Arguments:
- Device - Supplies a pointer to the device that will be receiving the
- resource allocation.
- Return Value:
- Status code.
- --*/
- {
- PARBITER_ALLOCATION_CONTEXT Context;
- BOOL Deferred;
- KSTATUS Status;
- Deferred = FALSE;
- if ((IoArbiterDebugOptions & ARBITER_DEBUG_PRINT_RESOURCES) != 0) {
- RtlDebugPrint("Resource Requirements for %s:\n", Device->Header.Name);
- if (Device->ResourceRequirements != NULL) {
- IoDebugPrintResourceConfigurationList(Device->ResourceRequirements);
- }
- RtlDebugPrint("Boot Resources for %s:\n", Device->Header.Name);
- if (Device->BootResources != NULL) {
- IoDebugPrintResourceAllocationList(0, Device->BootResources);
- }
- }
- //
- // Set up an allocation context based on the resource requirements for this
- // device.
- //
- Status = IopArbiterInitializeAllocationContext(Device, &Context);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- if ((Context->DeviceCount == 0) || (Context->RequirementCount == 0)) {
- goto ProcessResourceRequirementsEnd;
- }
- //
- // Try on the boot allocations for size first.
- //
- Status = IopArbiterTryBootAllocations(Context);
- if (KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- //
- // If the boot allocations did not work and this is the first time through
- // resource assignment, then delay resource assignment of this device until
- // all devices that have boot resources have enumerated. That way devices
- // that happen to come up earlier don't trod on fixed regions of
- // motherboard devices for instance.
- //
- if ((Device->Flags & DEVICE_FLAG_NOT_USING_BOOT_RESOURCES) == 0) {
- Device->Flags |= DEVICE_FLAG_NOT_USING_BOOT_RESOURCES;
- Status = IopDeferResourceAllocation(Device);
- if (KSUCCESS(Status)) {
- Status = STATUS_NOT_READY;
- Deferred = TRUE;
- }
- goto ProcessResourceRequirementsEnd;
- }
- //
- // Start by simply processing the device's requirement list.
- //
- Status = IopArbiterSatisfyAllocationContext(Context);
- if (KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- //
- // That didn't work out unfortunately. Gather up all reserved allocations
- // (allocations that worked but have not yet been handed out to drivers)
- // from the arbiters that failed.
- //
- Status = IopArbiterRipUpReservedAllocations(Context);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- Status = IopArbiterSatisfyAllocationContext(Context);
- if (KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- //
- // Unfortunately that wasn't enough either. Attempt to pause all devices
- // with committed resources on the sticky arbiters, rip up all reserved
- // allocations, and try again.
- //
- //
- // That didn't work either. Attempt to expand all failing arbiters.
- //
- Status = IopArbiterExpandFailingArbiters(Context);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- //
- // That did all it could, now start knocking devices out of their ideal
- // configuration, and potentially out of the running altogether until
- // there are simply no more devices left.
- // TODO: Also set a timer so that eventually this loop will give up if
- // there are simply too many combinations to try.
- //
- while (Context->DeviceCount != 0) {
- Status = IopArbiterSatisfyAllocationContext(Context);
- if (KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- Status = IopArbiterLimitResourceHog(Context);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- }
- if (Context->DeviceCount == 0) {
- Status = STATUS_UNSUCCESSFUL;
- goto ProcessResourceRequirementsEnd;
- }
- ProcessResourceRequirementsEnd:
- //
- // On success, mark which configuration was chosen for each device.
- //
- if (KSUCCESS(Status)) {
- IopArbiterMarkSelectedConfigurations(Context);
- Status = IopFinalizeResourceAllocation(Device);
- if ((IoArbiterDebugOptions & ARBITER_DEBUG_PRINT_RESOURCES) != 0) {
- RtlDebugPrint("Processor Local Resources for %s:\n",
- Device->Header.Name);
- if (Device->ProcessorLocalResources != NULL) {
- IoDebugPrintResourceAllocationList(
- 0,
- Device->ProcessorLocalResources);
- }
- RtlDebugPrint("Bus Local Resources for %s:\n", Device->Header.Name);
- if (Device->BusLocalResources != NULL) {
- IoDebugPrintResourceAllocationList(0,
- Device->BusLocalResources);
- }
- RtlDebugPrint("\n");
- }
- } else {
- if ((IoArbiterDebugOptions & ARBITER_DEBUG_PRINT_RESOURCES) != 0) {
- if (Deferred != FALSE) {
- RtlDebugPrint("Deferring resource allocation for %s (%x).\n",
- Device->Header.Name,
- Device);
- } else {
- RtlDebugPrint("Failed to allocate resource for %s (%x). "
- "Status = %x\n\n",
- Device->Header.Name,
- Device,
- Status);
- }
- }
- }
- if (Context != NULL) {
- IopArbiterDestroyAllocationContext(Context);
- }
- return Status;
- }
- VOID
- IopDestroyArbiterList (
- PDEVICE Device
- )
- /*++
- Routine Description:
- This routine destroys the arbiter list of the given device.
- Arguments:
- Device - Supplies a pointer to a device whose arbiter list is to be
- destroyed.
- Return Value:
- None.
- --*/
- {
- PRESOURCE_ARBITER CurrentArbiter;
- PLIST_ENTRY CurrentEntry;
- //
- // Loop throught the list of arbiters, destroying each one in turn.
- //
- CurrentEntry = Device->ArbiterListHead.Next;
- while (CurrentEntry != &(Device->ArbiterListHead)) {
- CurrentArbiter = LIST_VALUE(CurrentEntry, RESOURCE_ARBITER, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- IopArbiterDestroy(CurrentArbiter);
- }
- ASSERT(LIST_EMPTY(&(Device->ArbiterListHead)) != FALSE);
- ASSERT(LIST_EMPTY(&(Device->ArbiterAllocationListHead)) != FALSE);
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- IopFinalizeResourceAllocation (
- PDEVICE Device
- )
- /*++
- Routine Description:
- This routine cements the resources allocated to a device in preparation for
- starting the device. Once this operation is complete, the device will have
- to be paused to rip up or move its resource allocations.
- Arguments:
- Device - Supplies a pointer to the device that is about to be started.
- Return Value:
- Status code.
- --*/
- {
- RESOURCE_ALLOCATION Allocation;
- PRESOURCE_ALLOCATION_LIST AllocationList;
- PARBITER_ENTRY ArbiterEntry;
- ULONG ArbiterEntryIndex;
- PLIST_ENTRY CurrentAllocation;
- PLIST_ENTRY CurrentEntry;
- PLIST_ENTRY CurrentRelatedEntry;
- PRESOURCE_ALLOCATION DependentAllocation;
- PARBITER_ENTRY DependentEntry;
- ULONG DependentEntryIndex;
- ULONG Index;
- PRESOURCE_ALLOCATION OwningAllocation;
- PRESOURCE_ALLOCATION_LIST ProcessorLocalResources;
- ULONG RequirementCount;
- KSTATUS Status;
- AllocationList = NULL;
- ProcessorLocalResources = NULL;
- //
- // If the device didn't ask for resources, then life is easy.
- //
- if (Device->SelectedConfiguration == NULL) {
- Status = STATUS_SUCCESS;
- goto FinalizeResourceAllocationEnd;
- }
- //
- // Rearrange the arbiter allocations to match the order of the resource
- // requirements.
- //
- IopArbiterMatchAllocationsToRequirements(Device, &RequirementCount);
- if (RequirementCount == 0) {
- Status = STATUS_SUCCESS;
- goto FinalizeResourceAllocationEnd;
- }
- //
- // Create the resource allocation buffer, which will hold the array of
- // resource allocations.
- //
- AllocationList = IoCreateResourceAllocationList();
- if (AllocationList == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto FinalizeResourceAllocationEnd;
- }
- RtlZeroMemory(&Allocation, sizeof(RESOURCE_ALLOCATION));
- //
- // Loop through the arbiter entry list and convert each entry to a resource
- // allocation.
- //
- CurrentEntry = Device->ArbiterAllocationListHead.Next;
- while (CurrentEntry != &(Device->ArbiterAllocationListHead)) {
- ArbiterEntry = LIST_VALUE(CurrentEntry,
- ARBITER_ENTRY,
- ConfigurationListEntry);
- CurrentEntry = CurrentEntry->Next;
- //
- // Initialize the resource allocation based on the arbiter entry, and
- // insert it onto the back of the list (maintains the same order).
- //
- IopArbiterInitializeResourceAllocation(ArbiterEntry, &Allocation);
- Status = IoCreateAndAddResourceAllocation(&Allocation, AllocationList);
- if (!KSUCCESS(Status)) {
- goto FinalizeResourceAllocationEnd;
- }
- //
- // Also at this time mark the arbiter entry as permanent.
- //
- ArbiterEntry->Type = ArbiterSpaceAllocated;
- }
- //
- // Copy and translate the bus local resources into processor local
- // resources.
- //
- Status = IopArbiterCopyAndTranslateResources(AllocationList,
- &ProcessorLocalResources);
- if (!KSUCCESS(Status)) {
- goto FinalizeResourceAllocationEnd;
- }
- //
- // Finish up by patching both the allocated bus and processor resources to
- // refer to any owning entries. The relationship goes in the reverse
- // direction of the arbiter relationship (i.e. the same direction as
- // related requirements).
- //
- ArbiterEntryIndex = 0;
- CurrentEntry = Device->ArbiterAllocationListHead.Next;
- while (CurrentEntry != &(Device->ArbiterAllocationListHead)) {
- ArbiterEntry = LIST_VALUE(CurrentEntry,
- ARBITER_ENTRY,
- ConfigurationListEntry);
- CurrentEntry = CurrentEntry->Next;
- //
- // Skip arbiter entries that have no dependent entries.
- //
- if (ArbiterEntry->DependentEntry == NULL) {
- ArbiterEntryIndex += 1;
- continue;
- }
- //
- // Find the index of the dependent entry.
- //
- DependentEntryIndex = 0;
- CurrentRelatedEntry = Device->ArbiterAllocationListHead.Next;
- while (CurrentRelatedEntry != &(Device->ArbiterAllocationListHead)) {
- DependentEntry = LIST_VALUE(CurrentRelatedEntry,
- ARBITER_ENTRY,
- ConfigurationListEntry);
- if (ArbiterEntry->DependentEntry == DependentEntry) {
- break;
- }
- CurrentRelatedEntry = CurrentRelatedEntry->Next;
- DependentEntryIndex += 1;
- }
- //
- // The dependent entry isn't in the list of allocated arbiter entries
- // for this device. It is likely that the dependent entry was for an
- // alternate requirement for this device. Or that a different device
- // sharing the resource filled in the dependent entry just in case this
- // device was going to allocate a similarly dependent resource. NULL it
- // out.
- //
- if (CurrentRelatedEntry == &(Device->ArbiterAllocationListHead)) {
- ArbiterEntry->DependentEntry = NULL;
- ArbiterEntryIndex += 1;
- continue;
- }
- //
- // Find the bus and processor allocations for the arbiter entry and
- // dependent entry. If both are found (and they should be), then link
- // the dependent entry's allocation back to the owning arbiter entry's
- // allocation.
- //
- Index = 0;
- OwningAllocation = NULL;
- DependentAllocation = NULL;
- CurrentAllocation = AllocationList->AllocationListHead.Next;
- while (CurrentAllocation != &(AllocationList->AllocationListHead)) {
- if (Index == ArbiterEntryIndex) {
- OwningAllocation = LIST_VALUE(CurrentAllocation,
- RESOURCE_ALLOCATION,
- ListEntry);
- }
- if (Index == DependentEntryIndex) {
- DependentAllocation = LIST_VALUE(CurrentAllocation,
- RESOURCE_ALLOCATION,
- ListEntry);
- }
- if ((OwningAllocation != NULL) && (DependentAllocation != NULL)) {
- DependentAllocation->OwningAllocation = OwningAllocation;
- break;
- }
- CurrentAllocation = CurrentAllocation->Next;
- Index += 1;
- }
- Index = 0;
- OwningAllocation = NULL;
- DependentAllocation = NULL;
- CurrentAllocation = ProcessorLocalResources->AllocationListHead.Next;
- while (CurrentAllocation !=
- &(ProcessorLocalResources->AllocationListHead)) {
- if (Index == ArbiterEntryIndex) {
- OwningAllocation = LIST_VALUE(CurrentAllocation,
- RESOURCE_ALLOCATION,
- ListEntry);
- }
- if (Index == DependentEntryIndex) {
- DependentAllocation = LIST_VALUE(CurrentAllocation,
- RESOURCE_ALLOCATION,
- ListEntry);
- }
- if ((OwningAllocation != NULL) && (DependentAllocation != NULL)) {
- DependentAllocation->OwningAllocation = OwningAllocation;
- break;
- }
- CurrentAllocation = CurrentAllocation->Next;
- Index += 1;
- }
- ArbiterEntryIndex += 1;
- }
- Status = STATUS_SUCCESS;
- FinalizeResourceAllocationEnd:
- if (!KSUCCESS(Status)) {
- if (AllocationList != NULL) {
- IoDestroyResourceAllocationList(AllocationList);
- AllocationList = NULL;
- }
- if (ProcessorLocalResources != NULL) {
- IoDestroyResourceAllocationList(ProcessorLocalResources);
- ProcessorLocalResources = NULL;
- }
- }
- Device->BusLocalResources = AllocationList;
- Device->ProcessorLocalResources = ProcessorLocalResources;
- return Status;
- }
- KSTATUS
- IopArbiterAddFreeSpace (
- PRESOURCE_ARBITER Arbiter,
- ULONGLONG FreeSpaceBegin,
- ULONGLONG FreeSpaceLength,
- ULONGLONG FreeSpaceCharacteristics,
- PRESOURCE_ALLOCATION SourcingAllocation,
- ULONGLONG TranslationOffset
- )
- /*++
- Routine Description:
- This routine adds a range of free space to the arbiter, allowing it to dole
- out these resources to child devices.
- Arguments:
- Arbiter - Supplies a pointer to the arbiter to add the resources to.
- FreeSpaceBegin - Supplies the beginning value of the free range.
- FreeSpaceLength - Supplies the length of the free space.
- FreeSpaceCharacteristics - Supplies the characteristics of this new free
- space.
- SourcingAllocation - Supplies a pointer to the parent resource allocation
- that makes this range possible. This pointer is optional. Supplying
- NULL here implies that the given resource is fixed in nature and
- cannot be expanded.
- TranslationOffset - Supplies the offset that has to be added to all
- doled out allocations on the secondary side to get an address in the
- source allocation space (primary side).
- To recap: SecondaryAddress + TranslationOffset = PrimaryAddress, where
- PrimaryAddress is closer to the CPU complex.
- Return Value:
- Status code.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PARBITER_ENTRY ExistingEntry;
- PARBITER_ENTRY NewEntry;
- PARBITER_ENTRY PreviousEntry;
- KSTATUS Status;
- //
- // Allocate that new entry.
- //
- NewEntry = MmAllocatePagedPool(sizeof(ARBITER_ENTRY),
- ARBITER_ALLOCATION_TAG);
- if (NewEntry == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ArbiterAddFreeSpaceEnd;
- }
- RtlZeroMemory(NewEntry, sizeof(ARBITER_ENTRY));
- NewEntry->Type = ArbiterSpaceFree;
- NewEntry->Allocation = FreeSpaceBegin;
- NewEntry->Length = FreeSpaceLength;
- NewEntry->Characteristics = FreeSpaceCharacteristics;
- NewEntry->FreeCharacteristics = FreeSpaceCharacteristics;
- NewEntry->SourceAllocation = SourcingAllocation;
- NewEntry->TranslationOffset = TranslationOffset;
- //
- // Find the proper place for this entry in the list.
- //
- ExistingEntry = NULL;
- CurrentEntry = Arbiter->EntryListHead.Next;
- while (CurrentEntry != &(Arbiter->EntryListHead)) {
- ExistingEntry = LIST_VALUE(CurrentEntry, ARBITER_ENTRY, ListEntry);
- if (ExistingEntry->Allocation >= NewEntry->Allocation) {
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // Check for overlaps.
- //
- if (CurrentEntry == &(Arbiter->EntryListHead)) {
- INSERT_BEFORE(&(NewEntry->ListEntry), &(Arbiter->EntryListHead));
- } else {
- //
- // Check to see if this should be merged with the previous entry. If so,
- // free the previous entry and expand this new one to cover it.
- //
- if (ExistingEntry->ListEntry.Previous != &(Arbiter->EntryListHead)) {
- PreviousEntry = LIST_VALUE(ExistingEntry->ListEntry.Previous,
- ARBITER_ENTRY,
- ListEntry);
- if ((PreviousEntry->Type == ArbiterSpaceFree) &&
- (PreviousEntry->Characteristics == NewEntry->Characteristics) &&
- (PreviousEntry->SourceAllocation ==
- NewEntry->SourceAllocation) &&
- (PreviousEntry->TranslationOffset ==
- NewEntry->TranslationOffset) &&
- (PreviousEntry->Allocation + PreviousEntry->Length >=
- NewEntry->Allocation)) {
- NewEntry->Length += NewEntry->Allocation -
- PreviousEntry->Allocation;
- if (PreviousEntry->Length > NewEntry->Length) {
- NewEntry->Length = PreviousEntry->Length;
- }
- NewEntry->Allocation = PreviousEntry->Allocation;
- LIST_REMOVE(&(PreviousEntry->ListEntry));
- ASSERT(PreviousEntry->ConfigurationListEntry.Next == NULL);
- MmFreePagedPool(PreviousEntry);
- }
- }
- //
- // Check to see if this should be merged with the next entry. If so,
- // free up the new entry and expand the existing one to cover it.
- //
- if ((ExistingEntry->Type == ArbiterSpaceFree) &&
- (ExistingEntry->Characteristics == NewEntry->Characteristics) &&
- (ExistingEntry->SourceAllocation == NewEntry->SourceAllocation) &&
- (ExistingEntry->TranslationOffset == NewEntry->TranslationOffset) &&
- (NewEntry->Allocation + NewEntry->Length >=
- ExistingEntry->Allocation)) {
- ExistingEntry->Length += ExistingEntry->Allocation -
- NewEntry->Allocation;
- if (NewEntry->Length > ExistingEntry->Length) {
- ExistingEntry->Length = NewEntry->Length;
- }
- ExistingEntry->Allocation = NewEntry->Allocation;
- MmFreePagedPool(NewEntry);
- NewEntry = NULL;
- }
- //
- // If the new entry is still around, add it to the list before the
- // existing one.
- //
- if (NewEntry != NULL) {
- //
- // Check to see if it should be shrunk.
- //
- if (NewEntry->Allocation + NewEntry->Length >
- ExistingEntry->Allocation) {
- NewEntry->Length = ExistingEntry->Allocation -
- NewEntry->Allocation;
- ASSERT(NewEntry->Length != 0);
- }
- INSERT_BEFORE(&(NewEntry->ListEntry), CurrentEntry);
- }
- }
- Status = STATUS_SUCCESS;
- ArbiterAddFreeSpaceEnd:
- return Status;
- }
- KSTATUS
- IopArbiterAllocateSpace (
- PARBITER_ALLOCATION_CONTEXT Context,
- UINTN RequirementIndex,
- PRESOURCE_REQUIREMENT Alternative
- )
- /*++
- Routine Description:
- This routine attempts to allocate space from an arbiter.
- Arguments:
- Context - Supplies a pointer to the arbiter allocation context.
- RequirementIndex - Supplies the index of the requirement. If an alternative
- requirement is provided, then the routine will attempt to satisfy said
- alternative, but will set the corresponding requirement field of the
- arbiter entry to that of the requirement index. Thus, the allocation
- always points at the first requirement, not the potentially alternative
- requirement being satisfied.
- Alternative - Supplies an optional pointer to an alternative resource
- requirement to satisfy.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG AllocationEnd;
- BOOL AllowOverlaps;
- PRESOURCE_ARBITER Arbiter;
- PARBITER_ENTRY ArbiterEntry;
- PARBITER_ENTRY CompatibleSpace;
- PLIST_ENTRY CurrentEntry;
- PDEVICE Device;
- ULONG Index;
- PARBITER_ENTRY NewAllocation;
- PARBITER_ENTRY OwningRequirementEntry;
- ULONGLONG PotentialAllocation;
- PARBITER_ENTRY RequiredSpace;
- PRESOURCE_REQUIREMENT Requirement;
- PARBITER_ALLOCATION_REQUIREMENT RequirementData;
- PRESOURCE_REQUIREMENT RootRequirement;
- KSTATUS Status;
- NewAllocation = NULL;
- //
- // If an alternative requirement was supplied, then use it.
- //
- RootRequirement = Context->Requirements[RequirementIndex].Requirement;
- if (Alternative != NULL) {
- ASSERT(Alternative->Type == RootRequirement->Type);
- Requirement = Alternative;
- } else {
- Requirement = RootRequirement;
- }
- RequirementData = &(Context->Requirements[RequirementIndex]);
- Device = IOP_ARBITER_GET_DEVICE(Context, RequirementData);
- Arbiter = IOP_ARBITER_GET_ARBITER(Context, RequirementData);
- ASSERT(Arbiter != NULL);
- //
- // If this requirement has a owning requirement, then search for the
- // allocated arbiter entry associated with it.
- //
- OwningRequirementEntry = NULL;
- if (Requirement->OwningRequirement != NULL) {
- for (Index = 0; Index < Context->RequirementCount; Index += 1) {
- ArbiterEntry = Context->Requirements[Index].Allocation;
- if ((ArbiterEntry != NULL) &&
- (ArbiterEntry->CorrespondingRequirement ==
- Requirement->OwningRequirement)) {
- OwningRequirementEntry = ArbiterEntry;
- break;
- }
- }
- //
- // If the owning requirement has an allocated arbiter entry and that
- // arbiter entry has a dependent arbiter allocation, then this
- // requirement needs to use those exact resources. The owning arbiter
- // entry picked up the dependent entry from another device's use of the
- // same region.
- //
- if ((OwningRequirementEntry != NULL) &&
- (OwningRequirementEntry->DependentEntry != NULL)) {
- RequiredSpace = OwningRequirementEntry->DependentEntry;
- ASSERT(RequiredSpace->Type != ArbiterSpaceFree);
- ASSERT(RequiredSpace->CorrespondingRequirement->Type ==
- Requirement->Type);
- //
- // If the space does not match the requirement, then it cannot be
- // used and something is wrong.
- //
- if ((RequiredSpace->Characteristics !=
- Requirement->Characteristics) ||
- ((Requirement->Flags & RESOURCE_FLAG_NOT_SHAREABLE) != 0) ||
- ((RequiredSpace->Flags & RESOURCE_FLAG_NOT_SHAREABLE) != 0) ||
- (Requirement->Length != RequiredSpace->Length)) {
- Status = STATUS_RESOURCE_IN_USE;
- goto ArbiterAllocateSpaceEnd;
- }
- //
- // The required allocation must have the correct alignment.
- //
- if (IS_ALIGNED(RequiredSpace->Allocation,
- Requirement->Alignment) == FALSE) {
- Status = STATUS_RESOURCE_IN_USE;
- goto ArbiterAllocateSpaceEnd;
- }
- //
- // The allocation must also fit within the required bounds.
- //
- PotentialAllocation = RequiredSpace->Allocation;
- AllocationEnd = PotentialAllocation + Requirement->Length;
- if ((PotentialAllocation < Requirement->Minimum) ||
- (AllocationEnd > Requirement->Maximum)) {
- Status = STATUS_RESOURCE_IN_USE;
- goto ArbiterAllocateSpaceEnd;
- }
- //
- // The required space works! Create a new arbiter entry.
- //
- Status = IopArbiterInsertEntry(Arbiter,
- ArbiterSpaceReserved,
- Device,
- PotentialAllocation,
- Requirement->Length,
- Requirement->Characteristics,
- Requirement->Flags,
- RootRequirement,
- RequiredSpace,
- &NewAllocation);
- goto ArbiterAllocateSpaceEnd;
- }
- }
- //
- // Zero-length requirements have no issue with overlap. Just allocate an
- // arbiter entry.
- //
- if (Requirement->Length == 0) {
- Status = IopArbiterInsertEntry(Arbiter,
- ArbiterSpaceReserved,
- Device,
- Requirement->Minimum,
- 0,
- Requirement->Characteristics,
- Requirement->Flags,
- RootRequirement,
- NULL,
- &NewAllocation);
- goto ArbiterAllocateSpaceEnd;
- }
- //
- // Loop through every entry in the arbiter twice, first looking for only
- // free space and then allowing overlaps.
- //
- AllowOverlaps = FALSE;
- while (TRUE) {
- CurrentEntry = Arbiter->EntryListHead.Next;
- while (CurrentEntry != &(Arbiter->EntryListHead)) {
- CompatibleSpace = LIST_VALUE(CurrentEntry,
- ARBITER_ENTRY,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- //
- // If the entry isn't free, then it probably won't work. The only
- // supported overlaps are two entries that both satisfy the given
- // criteria:
- //
- // 1) Same characteristics.
- // 2) Same base works for both.
- // 3) Same length.
- //
- if (CompatibleSpace->Type != ArbiterSpaceFree) {
- if (AllowOverlaps == FALSE) {
- continue;
- }
- if ((CompatibleSpace->Length != Requirement->Length) ||
- (CompatibleSpace->Characteristics !=
- Requirement->Characteristics) ||
- ((Requirement->Flags & RESOURCE_FLAG_NOT_SHAREABLE) != 0) ||
- ((CompatibleSpace->Flags & RESOURCE_FLAG_NOT_SHAREABLE) !=
- 0)) {
- continue;
- }
- if (IS_ALIGNED(CompatibleSpace->Allocation,
- Requirement->Alignment) == FALSE) {
- continue;
- }
- }
- //
- // Skip it if it's below the minimum.
- //
- if ((CompatibleSpace->Allocation + CompatibleSpace->Length) <=
- Requirement->Minimum) {
- continue;
- }
- //
- // If characteristics are set in the free space, then those
- // characteristics are assumed to be serious and need to be matched.
- //
- if ((CompatibleSpace->Characteristics &
- Requirement->Characteristics) !=
- CompatibleSpace->Characteristics) {
- continue;
- }
- //
- // Attempt to fit an allocation in here.
- //
- if (CompatibleSpace->Allocation > Requirement->Minimum) {
- PotentialAllocation = CompatibleSpace->Allocation;
- } else {
- PotentialAllocation = Requirement->Minimum;
- }
- PotentialAllocation = ALIGN_RANGE_UP(PotentialAllocation,
- Requirement->Alignment);
- //
- // If this is not a free entry, the allocations had better be equal
- // (or else releasing the allocation won't work properly.
- //
- ASSERT((CompatibleSpace->Type == ArbiterSpaceFree) ||
- (PotentialAllocation == CompatibleSpace->Allocation));
- AllocationEnd = PotentialAllocation + Requirement->Length;
- //
- // If the end here is beyond the maximum, then no allocation in the
- // arbiter will work.
- //
- if (AllocationEnd > Requirement->Maximum) {
- Status = STATUS_UNSUCCESSFUL;
- goto ArbiterAllocateSpaceEnd;
- }
- //
- // If the allocation doesn't fit, move on to the next arbiter entry.
- //
- if (AllocationEnd >
- (CompatibleSpace->Allocation + CompatibleSpace->Length)) {
- continue;
- }
- //
- // The allocation fits! Create a new arbiter entry.
- //
- Status = IopArbiterInsertEntry(Arbiter,
- ArbiterSpaceReserved,
- Device,
- PotentialAllocation,
- Requirement->Length,
- Requirement->Characteristics,
- Requirement->Flags,
- RootRequirement,
- CompatibleSpace,
- &NewAllocation);
- goto ArbiterAllocateSpaceEnd;
- }
- //
- // If the list has already been searched allowing overlaps, then it's
- // time to bail out. No arbiter space was found to be satisfactory.
- //
- if (AllowOverlaps != FALSE) {
- break;
- }
- //
- // Next time around, allow this allocation to overlap with existing
- // resources.
- //
- AllowOverlaps = TRUE;
- }
- Status = STATUS_RESOURCE_IN_USE;
- ArbiterAllocateSpaceEnd:
- if (KSUCCESS(Status)) {
- if (OwningRequirementEntry != NULL) {
- OwningRequirementEntry->DependentEntry = NewAllocation;
- }
- Context->Requirements[RequirementIndex].Allocation = NewAllocation;
- }
- return Status;
- }
- KSTATUS
- IopArbiterInsertEntry (
- PRESOURCE_ARBITER Arbiter,
- ARBITER_SPACE_TYPE SpaceType,
- PDEVICE ClaimingDevice,
- ULONGLONG Allocation,
- ULONGLONG Length,
- ULONGLONG Characteristics,
- ULONG Flags,
- PRESOURCE_REQUIREMENT RootRequirement,
- PARBITER_ENTRY ExistingEntry,
- PARBITER_ENTRY *NewEntry
- )
- /*++
- Routine Description:
- This routine inserts an entry into the arbiter. It does not perform any
- checks for resource conflicts, so it is only for use by the arbiter. An
- external function would want to do much more involved conflict checking.
- Arguments:
- Arbiter - Supplies a pointer to the arbiter to add the new entry to.
- SpaceType - Supplies the type of arbiter space this entry should be set
- to.
- ClaimingDevice - Supplies a pointer to the device that will be using this
- region.
- Allocation - Supplies the allocation base.
- Length - Supplies the length of the allocation.
- Characteristics - Supplies the allocation characteristics.
- Flags - Supplies the flags for the allocation.
- RootRequirement - Supplies the requirment to set as the "corresponding
- requirement" of this arbiter entry, used to connect arbiter allocations
- with resource requirements.
- ExistingEntry - Supplies an optional pointer to the entry that currently
- exists for the range that is to be given to the new entry. This may be
- a free entry or an allocated, yet shareable, entry.
- NewEntry - Supplies a pointer where a pointer to the new entry will be
- returned. This memory is managed by the arbiter.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG AllocationEnd;
- PLIST_ENTRY CurrentEntry;
- PARBITER_ENTRY Leftovers;
- PARBITER_ENTRY NewAllocation;
- PARBITER_ENTRY NextEntry;
- KSTATUS Status;
- AllocationEnd = Allocation + Length;
- //
- // Create and initialize a new arbiter entry.
- //
- NewAllocation = MmAllocatePagedPool(sizeof(ARBITER_ENTRY),
- ARBITER_ALLOCATION_TAG);
- if (NewAllocation == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ArbiterInsertEntryEnd;
- }
- RtlZeroMemory(NewAllocation, sizeof(ARBITER_ENTRY));
- NewAllocation->Type = ArbiterSpaceReserved;
- NewAllocation->Device = ClaimingDevice;
- NewAllocation->Allocation = Allocation;
- NewAllocation->Length = Length;
- NewAllocation->Characteristics = Characteristics;
- NewAllocation->Flags = Flags;
- NewAllocation->CorrespondingRequirement = RootRequirement;
- if (ExistingEntry != NULL) {
- NewAllocation->FreeCharacteristics = ExistingEntry->FreeCharacteristics;
- NewAllocation->SourceAllocation = ExistingEntry->SourceAllocation;
- NewAllocation->TranslationOffset = ExistingEntry->TranslationOffset;
- ASSERT((ExistingEntry->Type != ArbiterSpaceFree) ||
- (ExistingEntry->DependentEntry == NULL));
- NewAllocation->DependentEntry = ExistingEntry->DependentEntry;
- }
- if (ExistingEntry != NULL) {
- //
- // If there is leftover space, allocate an entry for that.
- //
- if ((ExistingEntry->Type == ArbiterSpaceFree) &&
- (AllocationEnd <
- (ExistingEntry->Allocation + ExistingEntry->Length))) {
- Leftovers = MmAllocatePagedPool(sizeof(ARBITER_ENTRY),
- ARBITER_ALLOCATION_TAG);
- if (Leftovers == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ArbiterInsertEntryEnd;
- }
- RtlCopyMemory(Leftovers, ExistingEntry, sizeof(ARBITER_ENTRY));
- Leftovers->Allocation = AllocationEnd;
- Leftovers->Length = ExistingEntry->Allocation +
- ExistingEntry->Length -
- AllocationEnd;
- INSERT_AFTER(&(Leftovers->ListEntry), &(ExistingEntry->ListEntry));
- }
- INSERT_AFTER(&(NewAllocation->ListEntry), &(ExistingEntry->ListEntry));
- //
- // Shrink the old free entry, and remove it if it shrinks all the way
- // to zero.
- //
- if (ExistingEntry->Type == ArbiterSpaceFree) {
- ExistingEntry->Length = Allocation - ExistingEntry->Allocation;
- if (ExistingEntry->Length == 0) {
- LIST_REMOVE(&(ExistingEntry->ListEntry));
- MmFreePagedPool(ExistingEntry);
- }
- }
- //
- // Find the right spot to insert this new entry.
- //
- } else {
- CurrentEntry = Arbiter->EntryListHead.Next;
- while (CurrentEntry != &(Arbiter->EntryListHead)) {
- NextEntry = LIST_VALUE(CurrentEntry, ARBITER_ENTRY, ListEntry);
- if (NextEntry->Allocation >= Allocation) {
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if (CurrentEntry == &(Arbiter->EntryListHead)) {
- INSERT_BEFORE(&(NewAllocation->ListEntry),
- &(Arbiter->EntryListHead));
- } else {
- INSERT_BEFORE(&(NewAllocation->ListEntry), &(NextEntry->ListEntry));
- }
- }
- Status = STATUS_SUCCESS;
- ArbiterInsertEntryEnd:
- if (!KSUCCESS(Status)) {
- if (NewAllocation != NULL) {
- MmFreePagedPool(NewAllocation);
- NewAllocation = NULL;
- }
- }
- *NewEntry = NewAllocation;
- return Status;
- }
- VOID
- IopArbiterFreeEntry (
- PRESOURCE_ARBITER Arbiter,
- PARBITER_ENTRY Entry
- )
- /*++
- Routine Description:
- This routine frees an arbiter entry.
- Arguments:
- Arbiter - Supplies a pointer to the arbiter where the allocation belongs.
- Entry - Supplies a pointer to the arbiter allocation.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG AllocationBegin;
- ULONGLONG Characteristics;
- PARBITER_ENTRY NextEntry;
- PARBITER_ENTRY OverlappingEntry;
- PARBITER_ENTRY PreviousEntry;
- ASSERT(Entry->Type != ArbiterSpaceFree);
- AllocationBegin = Entry->Allocation;
- Characteristics = Entry->FreeCharacteristics;
- PreviousEntry = LIST_VALUE(Entry->ListEntry.Previous,
- ARBITER_ENTRY,
- ListEntry);
- NextEntry = LIST_VALUE(Entry->ListEntry.Next, ARBITER_ENTRY, ListEntry);
- LIST_REMOVE(&(Entry->ListEntry));
- if (Entry->Length == 0) {
- return;
- }
- //
- // Attempt to find an entry that overlapped with this one. If such an entry
- // exists, don't patch up free space into this region, since some other
- // allocation is still there. Just make this allocation disappear.
- //
- OverlappingEntry = IopArbiterFindEntry(Arbiter, AllocationBegin, FALSE);
- if (OverlappingEntry != NULL) {
- ASSERT(OverlappingEntry->Type != ArbiterSpaceFree);
- MmFreePagedPool(Entry);
- return;
- }
- //
- // Put the entry back on the list, as it makes it easier for the
- // coalescing code.
- //
- INSERT_AFTER(&(Entry->ListEntry), &(PreviousEntry->ListEntry));
- //
- // If the previous entry is free and comes up to meet this allocation, then
- // expand that allocation. Remove and free this allocation.
- //
- if ((Entry->ListEntry.Previous != &(Arbiter->EntryListHead)) &&
- (PreviousEntry->Type == ArbiterSpaceFree) &&
- (PreviousEntry->SourceAllocation == Entry->SourceAllocation) &&
- (PreviousEntry->TranslationOffset == Entry->TranslationOffset) &&
- (PreviousEntry->Characteristics == Characteristics) &&
- (PreviousEntry->Allocation + PreviousEntry->Length ==
- Entry->Allocation)) {
- PreviousEntry->Length += Entry->Length;
- LIST_REMOVE(&(Entry->ListEntry));
- MmFreePagedPool(Entry);
- //
- // Set the current entry to that previous entry that expanded out.
- //
- Entry = PreviousEntry;
- }
- //
- // See if the next allocation can swallow up this one.
- //
- if ((Entry->ListEntry.Next != &(Arbiter->EntryListHead)) &&
- (NextEntry->Type == ArbiterSpaceFree) &&
- (NextEntry->SourceAllocation == Entry->SourceAllocation) &&
- (NextEntry->TranslationOffset == Entry->TranslationOffset) &&
- (NextEntry->Characteristics == Characteristics) &&
- (Entry->Allocation + Entry->Length == NextEntry->Allocation)) {
- NextEntry->Length += Entry->Length;
- NextEntry->Allocation = Entry->Allocation;
- LIST_REMOVE(&(Entry->ListEntry));
- MmFreePagedPool(Entry);
- Entry = NULL;
- }
- //
- // If the entry is not already marked as free, mark it as such now.
- //
- if ((Entry != NULL) && (Entry->Type != ArbiterSpaceFree)) {
- Entry->Device = NULL;
- Entry->CorrespondingRequirement = NULL;
- Entry->Characteristics = Characteristics;
- Entry->Flags = 0;
- Entry->Type = ArbiterSpaceFree;
- Entry->DependentEntry = NULL;
- }
- return;
- }
- VOID
- IopArbiterDestroy (
- PRESOURCE_ARBITER Arbiter
- )
- /*++
- Routine Description:
- This routine destroys an individual resource arbiter, removing it from its
- list of arbiters.
- Arguments:
- Arbiter - Supplies a pointer to the arbiter that is to be destroyed.
- Return Value:
- None.
- --*/
- {
- PARBITER_ENTRY ArbiterEntry;
- PLIST_ENTRY CurrentEntry;
- //
- // In the destruction path, there is no point to free any of the arbiter
- // entries, just loop here and nuke them.
- //
- CurrentEntry = Arbiter->EntryListHead.Next;
- while (CurrentEntry != &(Arbiter->EntryListHead)) {
- ArbiterEntry = LIST_VALUE(CurrentEntry, ARBITER_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- LIST_REMOVE(&(ArbiterEntry->ConfigurationListEntry));
- LIST_REMOVE(&(ArbiterEntry->ListEntry));
- MmFreePagedPool(ArbiterEntry);
- }
- //
- // Destroy the arbiter itself.
- //
- LIST_REMOVE(&(Arbiter->ListEntry));
- MmFreePagedPool(Arbiter);
- return;
- }
- PRESOURCE_ARBITER
- IopArbiterFindArbiter (
- PDEVICE Device,
- RESOURCE_TYPE ResourceType
- )
- /*++
- Routine Description:
- This routine searches for the arbiter of the given resouce type that is
- attached to the given device.
- Arguments:
- Device - Supplies a pointer to the device whose arbiter list is to be
- searched.
- ResourceType - Supplies the resource type of the requested arbiter.
- Return Value:
- A pointer to a resource arbiter on success. NULL on failure.
- --*/
- {
- PRESOURCE_ARBITER Arbiter;
- PRESOURCE_ARBITER CurrentArbiter;
- PLIST_ENTRY CurrentEntry;
- //
- // Find the arbiter with the provided resource type.
- //
- Arbiter = NULL;
- CurrentEntry = Device->ArbiterListHead.Next;
- while (CurrentEntry != &(Device->ArbiterListHead)) {
- CurrentArbiter = LIST_VALUE(CurrentEntry, RESOURCE_ARBITER, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (CurrentArbiter->ResourceType == ResourceType) {
- Arbiter = CurrentArbiter;
- break;
- }
- }
- return Arbiter;
- }
- PARBITER_ENTRY
- IopArbiterFindEntry (
- PRESOURCE_ARBITER Arbiter,
- ULONGLONG Allocation,
- BOOL DependentEntryPreferred
- )
- /*++
- Routine Description:
- This routine attempts to find an arbiter entry for the given allocation.
- If there are more than one arbiter entries covering the same range, this
- routine will simply find the first one it comes across. If the dependent
- entry parameter is set to TRUE, then it will find the first one with a
- dependent entry filled in. If no such entry exists, then it will return the
- first one.
- Arguments:
- Arbiter - Supplies a pointer to the arbiter to search.
- Allocation - Supplies a pointer to the allocation value to check.
- DependentEntryPreferred - Supplies a boolean indicating whether or not the
- search should prioritize finding any entry that has a valid dependent
- entry field.
- Return Value:
- Returns a pointer to the first arbiter entry that covers the given
- allocation value.
- NULL if no arbiter entry covers the given value.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PARBITER_ENTRY Entry;
- PARBITER_ENTRY FirstEntry;
- FirstEntry = NULL;
- CurrentEntry = Arbiter->EntryListHead.Next;
- while (CurrentEntry != &(Arbiter->EntryListHead)) {
- Entry = LIST_VALUE(CurrentEntry, ARBITER_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if ((Entry->Allocation <= Allocation) &&
- (Entry->Allocation + Entry->Length > Allocation)) {
- //
- // Return this entry if it doesn't need to have a dependent entry
- // or it has a dependent entry.
- //
- if ((DependentEntryPreferred == FALSE) ||
- (Entry->DependentEntry != NULL)) {
- return Entry;
- }
- if (FirstEntry == NULL) {
- FirstEntry = Entry;
- }
- //
- // If a non-satisfying entry was found after the satisfying entries
- // have been checked, return the first entry found.
- //
- } else if (FirstEntry != NULL) {
- break;
- }
- }
- return FirstEntry;
- }
- VOID
- IopArbiterAddRequirement (
- PARBITER_ALLOCATION_CONTEXT Context,
- PRESOURCE_REQUIREMENT Requirement,
- PDEVICE Device
- )
- /*++
- Routine Description:
- This routine adds a requirement to the arbiter allocation context. The
- caller must have previously called resize arbiter context so that the
- arrays are large enough.
- Arguments:
- Context - Supplies a pointer to the initialized allocation context.
- Requirement - Supplies a pointer to the requirement to add.
- Device - Supplies a pointer to the device that generated the requirement.
- Return Value:
- None. An arbiter is always found since the root device has empty ones for
- each type.
- --*/
- {
- PRESOURCE_ARBITER Arbiter;
- UINTN ArbiterIndex;
- UINTN DeviceIndex;
- ULONG EmptySlot;
- PLIST_ENTRY FirstConfigurationListEntry;
- PDEVICE Provider;
- PARBITER_ALLOCATION_REQUIREMENT RequirementData;
- ULONG RequirementIndex;
- RequirementIndex = Context->RequirementCount;
- RequirementData = &(Context->Requirements[RequirementIndex]);
- RequirementData->Requirement = Requirement;
- RequirementData->Allocation = NULL;
- ASSERT((ARBITER_TYPE)Requirement->Type < ArbiterTypeCount);
- //
- // The arbiter comes from the device's parent unless a different provider
- // was explicitly given.
- //
- Provider = Device->ParentDevice;
- if (Requirement->Provider != NULL) {
- Provider = Requirement->Provider;
- }
- //
- // Walk up the chain of parents to find the arbiter for this requirement.
- //
- while (TRUE) {
- Arbiter = IopArbiterFindArbiter(Provider, Requirement->Type);
- //
- // If an arbiter was found, see if it's already in the arbiter array.
- // Insert if not, or just set the index if it is.
- //
- if (Arbiter != NULL) {
- for (ArbiterIndex = 0;
- ArbiterIndex < Context->ArbiterCount;
- ArbiterIndex += 1) {
- if (Context->ArbiterData[ArbiterIndex].Arbiter == Arbiter) {
- break;
- }
- }
- if (ArbiterIndex == Context->ArbiterCount) {
- Context->ArbiterData[ArbiterIndex].Arbiter = Arbiter;
- Context->ArbiterCount = ArbiterIndex + 1;
- }
- RequirementData->ArbiterIndex = ArbiterIndex;
- break;
- }
- Provider = Provider->ParentDevice;
- ASSERT(Provider != NULL);
- }
- //
- // Also find the device index for this requirement, or add the device if
- // it's new. Try to reuse empty slots from removed devices.
- //
- EmptySlot = Context->DeviceCount;
- for (DeviceIndex = 0;
- DeviceIndex < Context->DeviceCount;
- DeviceIndex += 1) {
- if (Context->Device[DeviceIndex] == Device) {
- break;
- }
- if (Context->Device[DeviceIndex] == NULL) {
- EmptySlot = DeviceIndex;
- }
- }
- if (DeviceIndex == Context->DeviceCount) {
- DeviceIndex = EmptySlot;
- Context->Device[EmptySlot] = Device;
- FirstConfigurationListEntry =
- Device->ResourceRequirements->RequirementListListHead.Next;
- Context->CurrentDeviceConfiguration[EmptySlot] =
- LIST_VALUE(FirstConfigurationListEntry,
- RESOURCE_REQUIREMENT_LIST,
- ListEntry);
- if (EmptySlot == Context->DeviceCount) {
- Context->DeviceCount += 1;
- }
- }
- RequirementData->DeviceIndex = DeviceIndex;
- RequirementData->Allocation = NULL;
- Context->RequirementCount += 1;
- return;
- }
- KSTATUS
- IopArbiterInitializeAllocationContext (
- PDEVICE Device,
- PARBITER_ALLOCATION_CONTEXT *NewContext
- )
- /*++
- Routine Description:
- This routine creates and initializes an arbiter allocation context, and
- seeds it with the resource requirements for the most optimal configuration
- for the given device.
- Arguments:
- Device - Supplies a pointer to the new kid on the block, the device trying
- to get resources.
- NewContext - Supplies a pointer that on success will receive a pointer to
- the arbiter allocation context. The caller is responsible for
- destroying this context.
- Return Value:
- Status code.
- --*/
- {
- PARBITER_ALLOCATION_CONTEXT Context;
- PLIST_ENTRY CurrentEntry;
- PRESOURCE_REQUIREMENT_LIST FirstConfiguration;
- PLIST_ENTRY FirstConfigurationListEntry;
- PRESOURCE_REQUIREMENT Requirement;
- ULONG RequirementCount;
- KSTATUS Status;
- //
- // Create an arbiter allocation context.
- //
- Context = MmAllocatePagedPool(sizeof(ARBITER_ALLOCATION_CONTEXT),
- ARBITER_ALLOCATION_TAG);
- if (Context == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ArbiterInitializeAllocationContextEnd;
- }
- RtlZeroMemory(Context, sizeof(ARBITER_ALLOCATION_CONTEXT));
- if ((Device->ResourceRequirements == NULL) ||
- (LIST_EMPTY(&(Device->ResourceRequirements->RequirementListListHead)) !=
- FALSE)) {
- Status = STATUS_SUCCESS;
- goto ArbiterInitializeAllocationContextEnd;
- }
- FirstConfigurationListEntry =
- Device->ResourceRequirements->RequirementListListHead.Next;
- FirstConfiguration = LIST_VALUE(FirstConfigurationListEntry,
- RESOURCE_REQUIREMENT_LIST,
- ListEntry);
- //
- // Loop through once to find out how many requirements are in this list.
- //
- RequirementCount = 0;
- CurrentEntry = FirstConfiguration->RequirementListHead.Next;
- while (CurrentEntry != &(FirstConfiguration->RequirementListHead)) {
- RequirementCount += 1;
- CurrentEntry = CurrentEntry->Next;
- }
- if (RequirementCount == 0) {
- Status = STATUS_SUCCESS;
- goto ArbiterInitializeAllocationContextEnd;
- }
- //
- // Create the arrays.
- //
- Status = IopArbiterResizeAllocationContext(Context, 1, RequirementCount);
- if (!KSUCCESS(Status)) {
- goto ArbiterInitializeAllocationContextEnd;
- }
- //
- // Initialize the requirement list.
- //
- CurrentEntry = FirstConfiguration->RequirementListHead.Next;
- while (CurrentEntry != &(FirstConfiguration->RequirementListHead)) {
- Requirement = LIST_VALUE(CurrentEntry, RESOURCE_REQUIREMENT, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- IopArbiterAddRequirement(Context, Requirement, Device);
- }
- Status = STATUS_SUCCESS;
- ArbiterInitializeAllocationContextEnd:
- if (!KSUCCESS(Status)) {
- if (Context != NULL) {
- if (Context->Device != NULL) {
- MmFreePagedPool(Context->Device);
- }
- if (Context->Requirements != NULL) {
- MmFreePagedPool(Context->Requirements);
- }
- MmFreePagedPool(Context);
- Context = NULL;
- }
- }
- *NewContext = Context;
- return Status;
- }
- VOID
- IopArbiterDestroyAllocationContext (
- PARBITER_ALLOCATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine destroys an arbiter allocation context.
- Arguments:
- Context - Supplies a pointer to the arbiter allocation context to release.
- Return Value:
- None.
- --*/
- {
- if (Context->Device != NULL) {
- MmFreePagedPool(Context->Device);
- }
- if (Context->Requirements != NULL) {
- MmFreePagedPool(Context->Requirements);
- }
- MmFreePagedPool(Context);
- return;
- }
- KSTATUS
- IopArbiterSatisfyAllocationContext (
- PARBITER_ALLOCATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine attempts to allocate all the resource requirements currently
- in the allocation context.
- Arguments:
- Context - Supplies a pointer to the arbiter allocation context to attempt
- to satisfy.
- Return Value:
- STATUS_SUCCESS if all resource requirements were satisfied.
- STATUS_UNSUCCESSFUL if not all resource requirements could be satisfied.
- Other error codes on other failures.
- --*/
- {
- BOOL AllocationFailed;
- PRESOURCE_ARBITER Arbiter;
- PARBITER_ALLOCATION_ARBITER_DATA ArbiterData;
- ULONG ArbiterIndex;
- PRESOURCE_REQUIREMENT CurrentAlternative;
- PRESOURCE_REQUIREMENT Requirement;
- PARBITER_ALLOCATION_REQUIREMENT RequirementData;
- ULONG RequirementIndex;
- KSTATUS Status;
- AllocationFailed = FALSE;
- for (ArbiterIndex = 0;
- ArbiterIndex < Context->ArbiterCount;
- ArbiterIndex += 1) {
- Context->ArbiterData[ArbiterIndex].AmountNotAllocated = 0;
- }
- //
- // Prioritize the requirements.
- //
- IopArbiterSortRequirements(Context);
- //
- // Loop through every requirement in the array and attempt to create an
- // allocation for it.
- //
- for (RequirementIndex = 0;
- RequirementIndex < Context->RequirementCount;
- RequirementIndex += 1) {
- //
- // Prefer the boot allocations.
- //
- Status = IopArbiterTryBootAllocation(Context, RequirementIndex);
- if (KSUCCESS(Status)) {
- continue;
- }
- RequirementData = &(Context->Requirements[RequirementIndex]);
- Requirement = RequirementData->Requirement;
- ArbiterData = IOP_GET_ARBITER_DATA(Context, RequirementData);
- Arbiter = ArbiterData->Arbiter;
- ASSERT(Arbiter != NULL);
- //
- // Loop through every possible alternative in the list trying to make
- // one stick.
- //
- Status = STATUS_UNSUCCESSFUL;
- CurrentAlternative = Requirement;
- while (CurrentAlternative != NULL) {
- Status = IopArbiterAllocateSpace(Context,
- RequirementIndex,
- CurrentAlternative);
- if (KSUCCESS(Status)) {
- break;
- }
- CurrentAlternative = IoGetNextResourceRequirementAlternative(
- Requirement,
- CurrentAlternative);
- }
- //
- // If nothing stuck, remember that something failed, and by how much.
- //
- if (!KSUCCESS(Status)) {
- AllocationFailed = TRUE;
- ArbiterData->AmountNotAllocated += Requirement->Length;
- }
- }
- //
- // If not all allocations were made, free them all.
- //
- if (AllocationFailed != FALSE) {
- IopArbiterClearContextAllocations(Context);
- Status = STATUS_UNSUCCESSFUL;
- //
- // If the allocations were successful, link them into the device's arbiter
- // entry list. Don't worry about the order for now.
- //
- } else {
- IopArbiterLinkContextAllocations(Context);
- Status = STATUS_SUCCESS;
- }
- return Status;
- }
- VOID
- IopArbiterSortRequirements (
- PARBITER_ALLOCATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine sorts all the resource requirements in an allocation context,
- prioritizing them by their ratio of requirement to possible spots.
- Arguments:
- Context - Supplies a pointer to the arbiter allocation context to sort.
- Return Value:
- None.
- --*/
- {
- ULONG FastIndex;
- PARBITER_ALLOCATION_REQUIREMENT FirstRequirement;
- BOOL InWrongOrder;
- PARBITER_ALLOCATION_REQUIREMENT SecondRequirement;
- ULONG SlowIndex;
- ARBITER_ALLOCATION_REQUIREMENT Swap;
- if (Context->RequirementCount == 0) {
- return;
- }
- //
- // Surely you can implement a better sort than this ridiculously lame one.
- //
- for (SlowIndex = 0;
- SlowIndex < Context->RequirementCount - 1;
- SlowIndex += 1) {
- FirstRequirement = &(Context->Requirements[SlowIndex]);
- for (FastIndex = SlowIndex + 1;
- FastIndex < Context->RequirementCount;
- FastIndex += 1) {
- SecondRequirement = &(Context->Requirements[FastIndex]);
- //
- // The two are in the wrong order if the second requirement is
- // greater than the first.
- //
- InWrongOrder = IopArbiterIsFirstRequirementHigherPriority(
- SecondRequirement->Requirement,
- FirstRequirement->Requirement);
- //
- // Swap the entries if they're in the wrong order.
- //
- if (InWrongOrder != FALSE) {
- RtlCopyMemory(&Swap,
- FirstRequirement,
- sizeof(ARBITER_ALLOCATION_REQUIREMENT));
- RtlCopyMemory(FirstRequirement,
- SecondRequirement,
- sizeof(ARBITER_ALLOCATION_REQUIREMENT));
- RtlCopyMemory(SecondRequirement,
- &Swap,
- sizeof(ARBITER_ALLOCATION_REQUIREMENT));
- FirstRequirement = SecondRequirement;
- }
- }
- }
- return;
- }
- BOOL
- IopArbiterIsFirstRequirementHigherPriority (
- PRESOURCE_REQUIREMENT FirstRequirement,
- PRESOURCE_REQUIREMENT SecondRequirement
- )
- /*++
- Routine Description:
- This routine compares two resource requirements and determines if the first
- requirement is a higher priority allocation to satisfy than the second.
- Arguments:
- FirstRequirement - Supplies a pointer to the requirement to be compared.
- SecondRequirement - Supplies a pointer to the requirement to compare with.
- Return Value:
- TRUE if the first requirement is of higher priority than the second.
- FALSE if the first requirement is of equal or lesser priority than the
- second.
- --*/
- {
- ULONGLONG Alignment;
- ULONGLONG FirstRequirementPossibilities;
- ULONGLONG SecondRequirementPossibilities;
- //
- // Sort first by requirement type. The lower the type value the higher the
- // priority.
- //
- if (FirstRequirement->Type != SecondRequirement->Type) {
- if (FirstRequirement->Type < SecondRequirement->Type) {
- return TRUE;
- }
- return FALSE;
- }
- //
- // Get each requirement's priority. The priority is based on the number of
- // different positions this requirement could take in it's range of
- // possibilities.
- // TODO: Add alternatives into the mix here.
- //
- Alignment = FirstRequirement->Alignment;
- if (Alignment == 0) {
- Alignment = 1;
- }
- FirstRequirementPossibilities =
- (FirstRequirement->Maximum - FirstRequirement->Minimum -
- FirstRequirement->Length) / Alignment;
- Alignment = SecondRequirement->Alignment;
- if (Alignment == 0) {
- Alignment = 1;
- }
- SecondRequirementPossibilities =
- (SecondRequirement->Maximum - SecondRequirement->Minimum -
- SecondRequirement->Length) / Alignment;
- if (FirstRequirementPossibilities < SecondRequirementPossibilities) {
- return TRUE;
- }
- return FALSE;
- }
- KSTATUS
- IopArbiterRipUpReservedAllocations (
- PARBITER_ALLOCATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine surveys all the arbiters in the given context that have failed.
- It rips up all reserved allocations in those arbiters (removing them from
- the device's arbiter entry list), and adds the corresponding resource
- requirements to the context. The hope is that by completely rearranging
- all the furniture in the room there will be space for that one more chair.
- Arguments:
- Context - Supplies a pointer to the arbiter allocation context to attempt
- to satisfy.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ARBITER Arbiter;
- ULONG ArbiterIndex;
- PLIST_ENTRY CurrentEntry;
- ULONG DeviceCount;
- PARBITER_ENTRY Entry;
- ULONG RequirementCount;
- KSTATUS Status;
- //
- // Loop through all arbiters once to figure out the new total number of
- // requirements and devices involved. One might think that a nice
- // optimization might be to avoid ripping up arbiters that aren't failing.
- // Unfortunately this is not possible, since if a previously uninvolved
- // device's allocations get ripped up, ALL of its allocations need to be
- // ripped up (since it might get adjusted down a configuration).
- //
- RequirementCount = Context->RequirementCount;
- DeviceCount = Context->DeviceCount;
- for (ArbiterIndex = 0;
- ArbiterIndex < Context->ArbiterCount;
- ArbiterIndex += 1) {
- Arbiter = Context->ArbiterData[ArbiterIndex].Arbiter;
- if (Arbiter == NULL) {
- continue;
- }
- //
- // Loop through every entry in the arbiter.
- //
- CurrentEntry = Arbiter->EntryListHead.Next;
- while (CurrentEntry != &(Arbiter->EntryListHead)) {
- Entry = LIST_VALUE(CurrentEntry, ARBITER_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Entry->Type != ArbiterSpaceReserved) {
- continue;
- }
- RequirementCount += 1;
- //
- // Assume that every new requirement belongs to a unique device.
- // This is almost certainly too much, but will simply result in an
- // array that is allocated to be a bit too big.
- //
- DeviceCount += 1;
- }
- }
- //
- // Resize the arrays to fit the new stuff.
- //
- Status = IopArbiterResizeAllocationContext(Context,
- DeviceCount,
- RequirementCount);
- if (!KSUCCESS(Status)) {
- goto ArbiterRipUpReservedAllocationsEnd;
- }
- //
- // Loop through the arbiters again now that everything is prepared for the
- // new allocations. Release anything in the arbiters that hasn't yet been
- // given to a device driver.
- //
- for (ArbiterIndex = 0;
- ArbiterIndex < Context->ArbiterCount;
- ArbiterIndex += 1) {
- Arbiter = Context->ArbiterData[ArbiterIndex].Arbiter;
- if (Arbiter == NULL) {
- continue;
- }
- //
- // Loop through every entry in the arbiter.
- //
- CurrentEntry = Arbiter->EntryListHead.Next;
- while (CurrentEntry != &(Arbiter->EntryListHead)) {
- Entry = LIST_VALUE(CurrentEntry, ARBITER_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Entry->Type != ArbiterSpaceReserved) {
- continue;
- }
- IopArbiterAddRequirement(Context,
- Entry->CorrespondingRequirement,
- Entry->Device);
- //
- // Remove the entry.
- //
- LIST_REMOVE(&(Entry->ConfigurationListEntry));
- IopArbiterFreeEntry(Arbiter, Entry);
- }
- }
- Status = STATUS_SUCCESS;
- ArbiterRipUpReservedAllocationsEnd:
- return Status;
- }
- KSTATUS
- IopArbiterExpandFailingArbiters (
- PARBITER_ALLOCATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine attempts to create more space in every arbiter that does not
- have enough space.
- Arguments:
- Context - Supplies a pointer to the allocation context to work with.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG AmountNeeded;
- PRESOURCE_ARBITER Arbiter;
- PARBITER_ALLOCATION_ARBITER_DATA ArbiterData;
- ULONG ArbiterIndex;
- ULONGLONG ArbiterSize;
- PLIST_ENTRY CurrentEntry;
- PARBITER_ENTRY Entry;
- for (ArbiterIndex = 0;
- ArbiterIndex < Context->ArbiterCount;
- ArbiterIndex += 1) {
- ArbiterData = &(Context->ArbiterData[ArbiterIndex]);
- //
- // If the arbiter doesn't have a problem, don't touch it.
- //
- if (ArbiterData->AmountNotAllocated == 0) {
- continue;
- }
- Arbiter = ArbiterData->Arbiter;
- ASSERT(Arbiter != NULL);
- //
- // Loop through every entry in the arbiter.
- //
- ArbiterSize = 0;
- CurrentEntry = Arbiter->EntryListHead.Next;
- while (CurrentEntry != &(Arbiter->EntryListHead)) {
- Entry = LIST_VALUE(CurrentEntry, ARBITER_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Entry->Type == ArbiterSpaceFree) {
- ArbiterSize += Entry->Length;
- continue;
- }
- break;
- }
- //
- // If there were allocations in the arbiter, then it cannot be
- // resized.
- //
- if (CurrentEntry != &(Arbiter->EntryListHead)) {
- continue;
- }
- //
- // Ask for more space, the old size plus double the amount not
- // allocated.
- //
- AmountNeeded = ArbiterSize + (ArbiterData->AmountNotAllocated * 2);
- IopArbiterExpandSpace(Arbiter, AmountNeeded);
- }
- return STATUS_SUCCESS;
- }
- KSTATUS
- IopArbiterExpandSpace (
- PRESOURCE_ARBITER Arbiter,
- ULONGLONG AmountNeeded
- )
- /*++
- Routine Description:
- This routine asks the arbiter's device for more space to put into the
- arbiter. On success, the arbiter will have more free space.
- Arguments:
- Arbiter - Supplies a pointer to the arbiter in need.
- AmountNeeded - Supplies the amount of additional space needed.
- Return Value:
- Status code.
- --*/
- {
- return STATUS_NOT_IMPLEMENTED;
- }
- KSTATUS
- IopArbiterLimitResourceHog (
- PARBITER_ALLOCATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine starts making compromises for the sake of device resource
- allocation. It finds the most congested resource, looks for the biggest
- potential consumer of that resource, and knocks that device down a
- configuration.
- Arguments:
- Context - Supplies a pointer to the context causing the resource squeeze.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ARBITER Arbiter;
- PARBITER_ALLOCATION_ARBITER_DATA ArbiterData;
- ULONG ArbiterIndex;
- ULONGLONG BiggestRequirementAmount;
- ULONG BiggestRequirementIndex;
- PRESOURCE_REQUIREMENT_LIST Configuration;
- PLIST_ENTRY CurrentEntry;
- PDEVICE Device;
- ULONG DeviceIndex;
- ULONG EndRequirementIndex;
- PLIST_ENTRY NextConfigurationListEntry;
- BOOL RemoveDevice;
- PRESOURCE_REQUIREMENT Requirement;
- ULONG RequirementCount;
- PARBITER_ALLOCATION_REQUIREMENT RequirementData;
- ULONG RequirementIndex;
- KSTATUS Status;
- PRESOURCE_ARBITER TightestArbiter;
- ULONGLONG TightestArbiterAmount;
- //
- // Find the tightest arbiter.
- //
- TightestArbiter = NULL;
- TightestArbiterAmount = 0;
- for (ArbiterIndex = 0;
- ArbiterIndex < Context->ArbiterCount;
- ArbiterIndex += 1) {
- ArbiterData = &(Context->ArbiterData[ArbiterIndex]);
- Arbiter = ArbiterData->Arbiter;
- if (ArbiterData->AmountNotAllocated > TightestArbiterAmount) {
- TightestArbiterAmount = ArbiterData->AmountNotAllocated;
- TightestArbiter = Arbiter;
- ASSERT(Arbiter != NULL);
- }
- }
- ASSERT(TightestArbiter != NULL);
- //
- // Find the biggest requirement for that arbiter that's not already in the
- // last configuration.
- //
- RemoveDevice = FALSE;
- BiggestRequirementAmount = 0;
- BiggestRequirementIndex = -1;
- for (RequirementIndex = 0;
- RequirementIndex < Context->RequirementCount;
- RequirementIndex += 1) {
- RequirementData = &(Context->Requirements[RequirementIndex]);
- Device = IOP_ARBITER_GET_DEVICE(Context, RequirementData);
- Requirement = RequirementData->Requirement;
- DeviceIndex = RequirementData->DeviceIndex;
- ASSERT(DeviceIndex < Context->DeviceCount);
- //
- // Skip if it's the last configuration.
- //
- if (Context->CurrentDeviceConfiguration[DeviceIndex]->ListEntry.Next ==
- &(Device->ResourceRequirements->RequirementListListHead)) {
- continue;
- }
- //
- // Remember if it's the new big guy.
- //
- if (Requirement->Length > BiggestRequirementAmount) {
- BiggestRequirementAmount = Requirement->Length;
- BiggestRequirementIndex = RequirementIndex;
- }
- }
- //
- // If there is no big guy, then everyone is at their worst configuration.
- // Find a device to knock out of the race.
- //
- if (BiggestRequirementIndex == -1) {
- RemoveDevice = TRUE;
- BiggestRequirementAmount = 0;
- BiggestRequirementIndex = -1;
- for (RequirementIndex = 0;
- RequirementIndex < Context->RequirementCount;
- RequirementIndex += 1) {
- RequirementData = &(Context->Requirements[RequirementIndex]);
- Device = IOP_ARBITER_GET_DEVICE(Context, RequirementData);
- Requirement = RequirementData->Requirement;
- DeviceIndex = RequirementData->DeviceIndex;
- ASSERT(DeviceIndex < Context->DeviceCount);
- //
- // Remember if it's the new big guy.
- //
- if (Requirement->Length > BiggestRequirementAmount) {
- BiggestRequirementAmount = Requirement->Length;
- BiggestRequirementIndex = RequirementIndex;
- }
- }
- }
- ASSERT(BiggestRequirementIndex != -1);
- //
- // Remove all requirements associated with the device at its old
- // configuration.
- //
- RequirementData = &(Context->Requirements[BiggestRequirementIndex]);
- Device = IOP_ARBITER_GET_DEVICE(Context, RequirementData);
- DeviceIndex = RequirementData->DeviceIndex;
- for (RequirementIndex = 0;
- RequirementIndex < Context->RequirementCount;
- NOTHING) {
- //
- // If this is the magic device's requirement, move the requirement from
- // the end of the array on top of this one.
- //
- RequirementData = &(Context->Requirements[RequirementIndex]);
- if (IOP_ARBITER_GET_DEVICE(Context, RequirementData) == Device) {
- ASSERT(RequirementData->Allocation == NULL);
- EndRequirementIndex = Context->RequirementCount - 1;
- if (EndRequirementIndex != RequirementIndex) {
- RtlCopyMemory(RequirementData,
- &(Context->Requirements[EndRequirementIndex]),
- sizeof(ARBITER_ALLOCATION_REQUIREMENT));
- }
- Context->RequirementCount -= 1;
- //
- // Only advance to the next index if that requirement wasn't just
- // replaced.
- //
- } else {
- RequirementIndex += 1;
- }
- }
- ASSERT(DeviceIndex < Context->DeviceCount);
- //
- // If it's getting desperate, remove the device itself.
- //
- if (RemoveDevice != FALSE) {
- Context->Device[DeviceIndex] = NULL;
- Context->CurrentDeviceConfiguration[DeviceIndex] = NULL;
- //
- // Notch the configuration down a tick, and add all those requirements.
- //
- } else {
- Configuration = Context->CurrentDeviceConfiguration[DeviceIndex];
- NextConfigurationListEntry = Configuration->ListEntry.Next;
- ASSERT(NextConfigurationListEntry !=
- &(Device->ResourceRequirements->RequirementListListHead));
- Configuration = LIST_VALUE(NextConfigurationListEntry,
- RESOURCE_REQUIREMENT_LIST,
- ListEntry);
- Context->CurrentDeviceConfiguration[DeviceIndex] = Configuration;
- //
- // Loop through the configuration once to determine how many
- // requirements there are.
- //
- RequirementCount = 0;
- CurrentEntry = Configuration->RequirementListHead.Next;
- while (CurrentEntry != &(Configuration->RequirementListHead)) {
- RequirementCount += 1;
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // Resize the arrays.
- //
- Status = IopArbiterResizeAllocationContext(
- Context,
- Context->DeviceCount,
- Context->RequirementCount + RequirementCount);
- if (!KSUCCESS(Status)) {
- goto ArbiterLimitResourceHogEnd;
- }
- //
- // Loop through again and add the resource requirements.
- //
- CurrentEntry = Configuration->RequirementListHead.Next;
- while (CurrentEntry != &(Configuration->RequirementListHead)) {
- Requirement = LIST_VALUE(CurrentEntry,
- RESOURCE_REQUIREMENT,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- IopArbiterAddRequirement(Context, Requirement, Device);
- }
- }
- Status = STATUS_SUCCESS;
- ArbiterLimitResourceHogEnd:
- return Status;
- }
- KSTATUS
- IopArbiterResizeAllocationContext (
- PARBITER_ALLOCATION_CONTEXT Context,
- ULONG NewDeviceCount,
- ULONG NewRequirementCount
- )
- /*++
- Routine Description:
- This routine resizes the appropriate arrays in the given arbiter allocation
- context. This routine allocates new arrays of the given size, copies the
- old contents over, and frees the old arrays. It does not modify the
- device or requirement count variables.
- Arguments:
- Context - Supplies a pointer to the context to adjust.
- NewDeviceCount - Supplies the new device count.
- NewRequirementCount - Supplies the new resource requirement count.
- Return Value:
- Status code.
- --*/
- {
- ULONG AllocationSize;
- UINTN CopySize;
- PARBITER_ALLOCATION_ARBITER_DATA NewArbiterDataArray;
- PRESOURCE_REQUIREMENT_LIST *NewCurrentDeviceConfigurationArray;
- PDEVICE *NewDeviceArray;
- PARBITER_ALLOCATION_REQUIREMENT NewRequirementArray;
- ULONG OldRequirementCount;
- KSTATUS Status;
- NewDeviceArray = NULL;
- NewRequirementArray = NULL;
- //
- // Allocate the new arrays in the context.
- //
- AllocationSize = (sizeof(PDEVICE) * NewDeviceCount) +
- (sizeof(PRESOURCE_REQUIREMENT_LIST) * NewDeviceCount);
- NewDeviceArray = MmAllocatePagedPool(AllocationSize,
- ARBITER_ALLOCATION_TAG);
- if (NewDeviceArray == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ArbiterResizeAllocationContextEnd;
- }
- RtlZeroMemory(NewDeviceArray, AllocationSize);
- NewCurrentDeviceConfigurationArray =
- (PRESOURCE_REQUIREMENT_LIST *)(NewDeviceArray + NewDeviceCount);
- AllocationSize = (sizeof(ARBITER_ALLOCATION_REQUIREMENT) *
- NewRequirementCount) +
- (sizeof(ARBITER_ALLOCATION_ARBITER_DATA) *
- NewRequirementCount);
- NewRequirementArray = MmAllocatePagedPool(AllocationSize,
- ARBITER_ALLOCATION_TAG);
- if (NewRequirementArray == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ArbiterResizeAllocationContextEnd;
- }
- RtlZeroMemory(NewRequirementArray, AllocationSize);
- NewArbiterDataArray =
- (PARBITER_ALLOCATION_ARBITER_DATA)(NewRequirementArray +
- NewRequirementCount);
- //
- // Copy the old arrays into the new arrays. The allocations are not
- // copied because they're all NULL at this point.
- //
- if (Context->Device != NULL) {
- RtlCopyMemory(NewDeviceArray,
- Context->Device,
- Context->DeviceCount * sizeof(PDEVICE));
- RtlCopyMemory(
- NewCurrentDeviceConfigurationArray,
- Context->CurrentDeviceConfiguration,
- Context->DeviceCount * sizeof(PRESOURCE_REQUIREMENT_LIST));
- MmFreePagedPool(Context->Device);
- }
- if (Context->Requirements != NULL) {
- OldRequirementCount = Context->RequirementCount;
- CopySize = OldRequirementCount * sizeof(ARBITER_ALLOCATION_REQUIREMENT);
- RtlCopyMemory(NewRequirementArray, Context->Requirements, CopySize);
- CopySize = Context->ArbiterCount *
- sizeof(ARBITER_ALLOCATION_ARBITER_DATA);
- RtlCopyMemory(NewArbiterDataArray, Context->ArbiterData, CopySize);
- MmFreePagedPool(Context->Requirements);
- }
- //
- // Replace the old arrays with the newly improved bigger arrays. Leave
- // the sizes alone as they will be expanded as they go.
- //
- Context->Device = NewDeviceArray;
- Context->CurrentDeviceConfiguration = NewCurrentDeviceConfigurationArray;
- Context->Requirements = NewRequirementArray;
- Context->ArbiterData = NewArbiterDataArray;
- Status = STATUS_SUCCESS;
- ArbiterResizeAllocationContextEnd:
- if (!KSUCCESS(Status)) {
- if (NewDeviceArray != NULL) {
- MmFreePagedPool(NewDeviceArray);
- }
- if (NewRequirementArray != NULL) {
- MmFreePagedPool(NewRequirementArray);
- }
- }
- return Status;
- }
- VOID
- IopArbiterMarkSelectedConfigurations (
- PARBITER_ALLOCATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine marks which resource configuration was chosen in each device
- involved.
- Note: By adjusting resource configurations of devices that had gotten ripped
- up, there is an assumption that a device and all of its siblings
- share the same set of arbiters. If this is not true, then the arbiters
- will return invalid configurations. For example, a first device is
- reserved resources from its first configuration, then a second device
- with a different set of arbiters comes in, the first device's
- allocations are ripped up (but only those in the same set of
- arbiters that the second device is working with), and then the
- resource configuration of the first device is adjusted down. This
- would result in the first device being given some resources from its
- first configuration (from the arbiters that didn't overlap with the
- second device) and other resource from a lower configuration.
- Arguments:
- Context - Supplies a pointer to the allocation context that was just
- satisfied.
- Return Value:
- None.
- --*/
- {
- PDEVICE Device;
- ULONG DeviceIndex;
- for (DeviceIndex = 0;
- DeviceIndex < Context->DeviceCount;
- DeviceIndex += 1) {
- Device = Context->Device[DeviceIndex];
- if (Device == NULL) {
- continue;
- }
- Device->SelectedConfiguration =
- Context->CurrentDeviceConfiguration[DeviceIndex];
- }
- return;
- }
- VOID
- IopArbiterMatchAllocationsToRequirements (
- PDEVICE Device,
- PULONG RequirementCount
- )
- /*++
- Routine Description:
- This routine rearranges the list of the device's arbiter entries so that
- they are in the same order as the device's resource requirement list.
- It can also optionally return the number of resource requirements the
- device has.
- Arguments:
- Device - Supplies a pointer to the device.
- RequirementCount - Supplies a pointer where the number of requirements
- will be returned.
- Return Value:
- Status code.
- --*/
- {
- PARBITER_ENTRY CurrentAllocation;
- PLIST_ENTRY CurrentAllocationEntry;
- PRESOURCE_REQUIREMENT CurrentRequirement;
- PLIST_ENTRY CurrentRequirementEntry;
- ULONG NumberOfRequirements;
- PLIST_ENTRY PreviousAllocationEntry;
- PRESOURCE_REQUIREMENT_LIST RequirementList;
- RequirementList = Device->SelectedConfiguration;
- NumberOfRequirements = 0;
- //
- // Loop through every requirement in the requirement list.
- //
- PreviousAllocationEntry = &(Device->ArbiterAllocationListHead);
- CurrentRequirementEntry = RequirementList->RequirementListHead.Next;
- while (CurrentRequirementEntry != &(RequirementList->RequirementListHead)) {
- CurrentRequirement = LIST_VALUE(CurrentRequirementEntry,
- RESOURCE_REQUIREMENT,
- ListEntry);
- CurrentRequirementEntry = CurrentRequirementEntry->Next;
- NumberOfRequirements += 1;
- //
- // Loop through the remaining arbiter allocations to find the one that
- // corresponds to this requirement.
- //
- CurrentAllocationEntry = PreviousAllocationEntry->Next;
- while (CurrentAllocationEntry != &(Device->ArbiterAllocationListHead)) {
- CurrentAllocation = LIST_VALUE(CurrentAllocationEntry,
- ARBITER_ENTRY,
- ConfigurationListEntry);
- if (CurrentAllocation->CorrespondingRequirement ==
- CurrentRequirement) {
- LIST_REMOVE(CurrentAllocationEntry);
- INSERT_AFTER(CurrentAllocationEntry, PreviousAllocationEntry);
- break;
- }
- CurrentAllocationEntry = CurrentAllocationEntry->Next;
- }
- ASSERT(CurrentAllocationEntry != &(Device->ArbiterAllocationListHead));
- PreviousAllocationEntry = PreviousAllocationEntry->Next;
- }
- if (RequirementCount != NULL) {
- *RequirementCount = NumberOfRequirements;
- }
- return;
- }
- VOID
- IopArbiterInitializeResourceAllocation (
- PARBITER_ENTRY ArbiterEntry,
- PRESOURCE_ALLOCATION ResourceAllocation
- )
- /*++
- Routine Description:
- This routine initializes a resource allocation based on an arbiter entry.
- Arguments:
- ResourceType - Supplies the resource type of the allocation to initialize.
- ArbiterEntry - Supplies a pointer to the arbiter entry to use as a template
- for the resource allocation.
- ResourceAllocation - Supplies a pointer where the resource allocation
- corresponding to the given arbiter entry will be returned.
- Return Value:
- None.
- --*/
- {
- PRESOURCE_REQUIREMENT Requirement;
- Requirement = ArbiterEntry->CorrespondingRequirement;
- ResourceAllocation->Type = Requirement->Type;
- ResourceAllocation->Allocation = ArbiterEntry->Allocation;
- ResourceAllocation->Length = ArbiterEntry->Length;
- ResourceAllocation->Characteristics = ArbiterEntry->Characteristics;
- ResourceAllocation->Flags = Requirement->Flags;
- ResourceAllocation->Data = Requirement->Data;
- ResourceAllocation->DataSize = Requirement->DataSize;
- ResourceAllocation->Provider = Requirement->Provider;
- return;
- }
- KSTATUS
- IopArbiterCopyAndTranslateResources (
- PRESOURCE_ALLOCATION_LIST BusLocalResources,
- PRESOURCE_ALLOCATION_LIST *ProcessorLocalResources
- )
- /*++
- Routine Description:
- This routine translates a set of resources from bus local resources to
- processor local resources.
- Arguments:
- BusLocalResources - Supplies a pointer to the bus local resources to
- translate from.
- ProcessorLocalResources - Supplies a pointer where a newly allocated list
- of processor local resources will be returned. The caller is
- responsible for destroying this resource list once it is returned.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ALLOCATION Allocation;
- KSTATUS Status;
- RESOURCE_ALLOCATION TranslatedResource;
- PRESOURCE_ALLOCATION_LIST TranslatedResources;
- TranslatedResources = NULL;
- if (BusLocalResources == NULL) {
- Status = STATUS_SUCCESS;
- goto ArbiterCopyAndTranslateResourcesEnd;
- }
- //
- // Create a new resource allocation list.
- //
- TranslatedResources = IoCreateResourceAllocationList();
- if (TranslatedResources == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ArbiterCopyAndTranslateResourcesEnd;
- }
- Allocation = IoGetNextResourceAllocation(BusLocalResources, NULL);
- while (Allocation != NULL) {
- //
- // Create a local copy of the resource and translate it.
- //
- RtlCopyMemory(&TranslatedResource,
- Allocation,
- sizeof(RESOURCE_ALLOCATION));
- //
- // TODO: Find the arbiter entry associated with this resource and
- // apply the translation.
- //
- //
- // Create a copy of the resource.
- //
- Status = IoCreateAndAddResourceAllocation(&TranslatedResource,
- TranslatedResources);
- if (!KSUCCESS(Status)) {
- goto ArbiterCopyAndTranslateResourcesEnd;
- }
- //
- // Get the next allocation.
- //
- Allocation = IoGetNextResourceAllocation(BusLocalResources, Allocation);
- }
- Status = STATUS_SUCCESS;
- ArbiterCopyAndTranslateResourcesEnd:
- if (!KSUCCESS(Status)) {
- if (TranslatedResources != NULL) {
- IoDestroyResourceAllocationList(TranslatedResources);
- TranslatedResources = NULL;
- }
- }
- *ProcessorLocalResources = TranslatedResources;
- return Status;
- }
- KSTATUS
- IopArbiterTryBootAllocations (
- PARBITER_ALLOCATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine attempts to use the boot allocations for a device.
- Arguments:
- Context - Supplies a pointer to the arbiter allocation context.
- Return Value:
- STATUS_SUCCESS if all the boot allocations were successfully reserved in
- the arbiters.
- Other errors on failure.
- --*/
- {
- ULONG RequirementIndex;
- KSTATUS Status;
- //
- // Loop through all the requirements.
- //
- for (RequirementIndex = 0;
- RequirementIndex < Context->RequirementCount;
- RequirementIndex += 1) {
- Status = IopArbiterTryBootAllocation(Context, RequirementIndex);
- if (!KSUCCESS(Status)) {
- goto ArbiterTryBootAllocationsEnd;
- }
- }
- //
- // Everything worked, link the context allocations to their requirement's
- // devices.
- //
- IopArbiterLinkContextAllocations(Context);
- Status = STATUS_SUCCESS;
- ArbiterTryBootAllocationsEnd:
- if (!KSUCCESS(Status)) {
- IopArbiterClearContextAllocations(Context);
- }
- return Status;
- }
- KSTATUS
- IopArbiterTryBootAllocation (
- PARBITER_ALLOCATION_CONTEXT Context,
- UINTN RequirementIndex
- )
- /*++
- Routine Description:
- This routine attempts to use the boot allocation for a particular
- requirement.
- Arguments:
- Context - Supplies a pointer to the arbiter allocation context.
- RequirementIndex - Supplies the index of the requirement to try and
- satisfy with a boot allocation.
- Return Value:
- STATUS_SUCCESS if all the boot allocations were successfully reserved in
- the arbiters.
- Other errors on failure.
- --*/
- {
- PRESOURCE_ARBITER Arbiter;
- PARBITER_ENTRY ArbiterEntry;
- PRESOURCE_ALLOCATION BootAllocation;
- BOOL Conflict;
- PDEVICE Device;
- PARBITER_ENTRY NewEntry;
- PRESOURCE_REQUIREMENT Requirement;
- PARBITER_ALLOCATION_REQUIREMENT RequirementData;
- KSTATUS Status;
- RequirementData = &(Context->Requirements[RequirementIndex]);
- Requirement = RequirementData->Requirement;
- Device = IOP_ARBITER_GET_DEVICE(Context, RequirementData);
- Arbiter = IOP_ARBITER_GET_ARBITER(Context, RequirementData);
- ASSERT(Arbiter != NULL);
- BootAllocation = IopArbiterFindBootAllocationForRequirement(Device,
- Requirement);
- //
- // If there's no boot allocation for this requirement or the boot
- // allocation doesn't satisfy the requirement, attempt to satisfy it
- // with something else.
- //
- if ((BootAllocation == NULL) ||
- (BootAllocation->Length < Requirement->Length)) {
- Status = IopArbiterAllocateSpace(Context, RequirementIndex, NULL);
- goto ArbiterTryBootAllocationEnd;
- }
- //
- // Requirements satisfied by boot allocations should not have related
- // requirements.
- //
- ASSERT(Requirement->OwningRequirement == NULL);
- //
- // Find out what's in the arbiter at this location.
- //
- ArbiterEntry = NULL;
- if (BootAllocation->Length != 0) {
- ArbiterEntry = IopArbiterFindEntry(Arbiter,
- BootAllocation->Allocation,
- TRUE);
- }
- //
- // If there's something there, make sure it agrees.
- //
- if (ArbiterEntry != NULL) {
- //
- // If the entry isn't free, then it had better exactly work with the
- // entry there, and be shareable.
- //
- Conflict = FALSE;
- if (ArbiterEntry->Type != ArbiterSpaceFree) {
- if ((ArbiterEntry->Characteristics !=
- Requirement->Characteristics) ||
- ((Requirement->Flags &
- RESOURCE_FLAG_NOT_SHAREABLE) != 0) ||
- ((ArbiterEntry->Flags &
- RESOURCE_FLAG_NOT_SHAREABLE) != 0) ||
- (Requirement->Length != ArbiterEntry->Length)) {
- Conflict = TRUE;
- }
- if ((ArbiterEntry->Allocation & (Requirement->Alignment - 1)) !=
- 0) {
- Conflict = TRUE;
- }
- //
- // If different boot resources of the same device conflict with
- // each other, then assume the BIOS knows what it's doing there
- // and allow it.
- //
- if ((Conflict != FALSE) && (ArbiterEntry->Device == Device) &&
- ((ArbiterEntry->Flags & RESOURCE_FLAG_BOOT) != 0)) {
- Conflict = FALSE;
- }
- if (Conflict != FALSE) {
- Status = STATUS_RANGE_CONFLICT;
- goto ArbiterTryBootAllocationEnd;
- }
- }
- //
- // There is no entry, so add some free space and then allocate it. This
- // gives the BIOS the benefit of the doubt. For zero length
- // allocations, don't create free space, just insert.
- //
- } else if (BootAllocation->Length != 0) {
- Status = IopArbiterAddFreeSpace(Arbiter,
- BootAllocation->Allocation,
- BootAllocation->Length,
- 0,
- NULL,
- 0);
- if (!KSUCCESS(Status)) {
- goto ArbiterTryBootAllocationEnd;
- }
- ArbiterEntry = IopArbiterFindEntry(Arbiter,
- BootAllocation->Allocation,
- FALSE);
- ASSERT(ArbiterEntry != NULL);
- }
- //
- // Insert the boot allocation.
- //
- Status = IopArbiterInsertEntry(Arbiter,
- ArbiterSpaceReserved,
- Device,
- BootAllocation->Allocation,
- BootAllocation->Length,
- BootAllocation->Characteristics,
- Requirement->Flags | RESOURCE_FLAG_BOOT,
- Requirement,
- ArbiterEntry,
- &NewEntry);
- if (!KSUCCESS(Status)) {
- goto ArbiterTryBootAllocationEnd;
- }
- //
- // The space was successfully reserved, save it.
- //
- Context->Requirements[RequirementIndex].Allocation = NewEntry;
- Status = STATUS_SUCCESS;
- ArbiterTryBootAllocationEnd:
- return Status;
- }
- PRESOURCE_ALLOCATION
- IopArbiterFindBootAllocationForRequirement (
- PDEVICE Device,
- PRESOURCE_REQUIREMENT Requirement
- )
- /*++
- Routine Description:
- This routine attempts to find the boot resource allocation that matches
- with the given device's resource requirement.
- Arguments:
- Device - Supplies a pointer to the device being queried.
- Requirement - Supplies a pointer to the resource requirement whose boot
- allocation counterpart should be found.
- Return Value:
- Returns a pointer to the boot time allocation that satisfies the given
- requirement.
- NULL if the allocation could not be found.
- --*/
- {
- PRESOURCE_ALLOCATION Allocation;
- PRESOURCE_ALLOCATION_LIST AllocationList;
- PRESOURCE_REQUIREMENT CurrentRequirement;
- PRESOURCE_REQUIREMENT_LIST RequirementList;
- ULONG ResourceIndex;
- //
- // Only the first requirement list is searched.
- //
- RequirementList =
- IoGetNextResourceConfiguration(Device->ResourceRequirements, NULL);
- ASSERT(RequirementList != NULL);
- //
- // Determine the index of the given requirement in the list of requirements.
- //
- ResourceIndex = 0;
- CurrentRequirement = IoGetNextResourceRequirement(RequirementList, NULL);
- while (CurrentRequirement != NULL) {
- if (CurrentRequirement == Requirement) {
- break;
- }
- ResourceIndex += 1;
- CurrentRequirement = IoGetNextResourceRequirement(RequirementList,
- CurrentRequirement);
- }
- if (CurrentRequirement == NULL) {
- return NULL;
- }
- //
- // Now go that many entries into the boot allocation list.
- //
- AllocationList = Device->BootResources;
- if (AllocationList == NULL) {
- return NULL;
- }
- Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
- while ((ResourceIndex != 0) && (Allocation != NULL)) {
- ResourceIndex -= 1;
- Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
- }
- if (Allocation == NULL) {
- return NULL;
- }
- //
- // Throw it out if the types don't match. Other checking is not done
- // because the allocation may satisfy an alternative instead of this exact
- // requirement.
- //
- if (Allocation->Type != Requirement->Type) {
- return NULL;
- }
- return Allocation;
- }
- VOID
- IopArbiterClearContextAllocations (
- PARBITER_ALLOCATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine frees any reserved allocations made on behalf of the given
- allocation context.
- Arguments:
- Context - Supplies a pointer to the context whose allocations should be
- cleared and freed.
- Return Value:
- None.
- --*/
- {
- PRESOURCE_ARBITER Arbiter;
- PARBITER_ENTRY Entry;
- PARBITER_ALLOCATION_REQUIREMENT RequirementData;
- ULONG RequirementIndex;
- for (RequirementIndex = 0;
- RequirementIndex < Context->RequirementCount;
- RequirementIndex += 1) {
- RequirementData = &(Context->Requirements[RequirementIndex]);
- Arbiter = IOP_ARBITER_GET_ARBITER(Context, RequirementData);
- ASSERT(Arbiter != NULL);
- Entry = RequirementData->Allocation;
- if (Entry != NULL) {
- IopArbiterFreeEntry(Arbiter, Entry);
- }
- RequirementData->Allocation = NULL;
- }
- return;
- }
- VOID
- IopArbiterLinkContextAllocations (
- PARBITER_ALLOCATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine links each allocation made in an allocation context to its
- corresponding requirement and device.
- Arguments:
- Context - Supplies a pointer to the context whose allocations should be
- cleared and freed.
- Return Value:
- None.
- --*/
- {
- PDEVICE AllocationDevice;
- PARBITER_ENTRY Entry;
- ULONG RequirementIndex;
- for (RequirementIndex = 0;
- RequirementIndex < Context->RequirementCount;
- RequirementIndex += 1) {
- Entry = Context->Requirements[RequirementIndex].Allocation;
- if (Entry == NULL) {
- continue;
- }
- AllocationDevice = Entry->Device;
- INSERT_AFTER(&(Entry->ConfigurationListEntry),
- &(AllocationDevice->ArbiterAllocationListHead));
- }
- return;
- }
- KSTATUS
- IopDeferResourceAllocation (
- PDEVICE Device
- )
- /*++
- Routine Description:
- This routine adds the given device to the array of devices whose resource
- allocation is being deferred until after all devices with boot allocations
- have been enumerated.
- Arguments:
- Device - Supplies a pointer to the device to add.
- Return Value:
- Status code.
- --*/
- {
- PDEVICE *NewArray;
- UINTN NewSize;
- NewSize = IoDelayedDeviceCount + 1;
- NewArray = MmAllocatePagedPool(NewSize * sizeof(PDEVICE),
- ARBITER_ALLOCATION_TAG);
- if (NewArray == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- if (IoDelayedDevices != NULL) {
- RtlCopyMemory(NewArray,
- IoDelayedDevices,
- (NewSize - 1) * sizeof(PDEVICE));
- MmFreePagedPool(IoDelayedDevices);
- }
- NewArray[NewSize - 1] = Device;
- IoDelayedDevices = NewArray;
- IoDelayedDeviceCount = NewSize;
- return STATUS_SUCCESS;
- }
|