Dela via


Låsa sidladdningsbar kod eller data

Vissa drivrutiner i kernelläge, till exempel serie- och parallella drivrutiner, behöver inte vara minnesbaserade om inte de enheter som de hanterar är öppna. Så länge det finns en aktiv anslutning eller port måste någon del av drivrutinskoden som hanterar den porten vara närvarande för att betjäna enheten. När porten eller anslutningen inte används krävs inte drivrutinskoden. Däremot måste en drivrutin för en disk som innehåller systemkod, programkod eller systemväxlingsfilen alltid vara minnesbaserad eftersom drivrutinen ständigt överför data mellan enheten och systemet.

En drivrutin för en sporadiskt använd enhet (till exempel ett modem) kan frigöra systemutrymme när enheten den hanterar inte är aktiv. Om du placerar koden i en enda sektion som måste vara residerande för att kunna exekvera en aktiv enhet, och om drivrutinen låser koden i minnet medan enheten används, kan du ange den här sektionen som sidosättbar. När drivrutinens enhet öppnas, läser operativsystemet in det paginerbara avsnittet i minnet, och drivrutinen låser det där tills det inte längre behövs.

System-CD-ljuddrivrutinskoden använder den här tekniken. Koden för drivrutinen grupperas i sidiga avsnitt enligt tillverkaren av CD-enheten. Vissa märken kanske aldrig finns i ett visst system. Även om det finns en CD-ROM i ett system kan den kommas åt sällan, så om du grupperar kod i växlingsbara avsnitt efter CD-typ ser du till att koden för enheter som inte finns på en viss dator aldrig läses in. Men när enheten används läser systemet in koden för lämplig CD-enhet. Then the driver calls the MmLockPagableCodeSection routine, as described later in this article, to lock its code into memory while its device is being used.

För att isolera pagebar kod i ett namngivet avsnitt, markera den med följande kompilatordirektiv:

#pragma alloc_text(PAGE*Xxx***, *RoutineName***)

The name of a pageable code section must start with the four letters "PAGE" and can be followed by up to four characters (represented here as Xxx) to uniquely identify the section. De första fyra bokstäverna i avsnittsnamnet (dvs. "PAGE") måste vara versaler. The RoutineName identifies an entry point to be included in the pageable section.

Det kortaste giltiga namnet för ett sidbart kodavsnitt i en drivrutinsfil är helt enkelt PAGE. Pragma-direktivet i följande kodexempel identifierar RdrCreateConnection till exempel som en startpunkt i ett sidbart kodavsnitt med namnet PAGE.

#ifdef  ALLOC_PRAGMA 
#pragma alloc_text(PAGE, RdrCreateConnection) 
#endif 

MmLockPagableCodeSection locks in the whole contents of the section that contains the routine referenced in the call. In other words, this call makes every routine associated with the same PAGEXxx identifier resident and locked in memory. In other words, this call makes every routine associated with the same PAGEXxx identifier resident and locked in memory.

MmLockPagableCodeSection returns a handle to be used when unlocking the section (by calling the MmUnlockPagableImageSection routine) or when the driver must lock the section from additional locations in its code.

En drivrutin kan också behandla sällan använda data som växlingsbara så att även de kan bläddras ut tills den enhet som den stöder är aktiv. Systemmixerdrivrutinen använder till exempel sidosättningsbar data. Mixer-enheten har ingen asynkron I/O associerad med sig, så den här drivrutinen kan göra dess data sidbar.

Namnet på ett sidbart dataavsnitt måste börja med de fyra bokstäverna "PAGE" och kan följas av upp till fyra tecken för att unikt identifiera avsnittet. De första fyra bokstäverna i avsnittsnamnet (dvs. "PAGE") måste vara versaler.

Undvik att tilldela identiska namn till kod- och dataavsnitt. För att göra källkoden mer läsbar tilldelar drivrutinsutvecklare vanligtvis namnet PAGE till det sidbara kodavsnittet eftersom det här namnet är kort och det kan visas i många alloc_text pragma-direktiv. Längre namn tilldelas sedan till alla sidbara dataavsnitt (till exempel PAGEDATA för data_seg, PAGEBSS för bss_seg och så vidare) som drivrutinen kan kräva.

De två första pragma-direktiven i följande kodexempel definierar till exempel två sidbara dataavsnitt, PAGEDATA och PAGEBSS. PAGEDATA deklareras med hjälp av data_seg pragma-direktivet och innehåller initierade data. PAGEBSS deklareras med hjälp av bss_seg pragma-direktivet och innehåller onitialiserade data.

#pragma data_seg("PAGEDATA")
#pragma bss_seg("PAGEBSS")

INT Variable1 = 1;
INT Variable2;

CHAR Array1[64*1024] = { 0 };
CHAR Array2[64*1024];

#pragma data_seg()
#pragma bss_seg()

I det här kodexemplet initieras Variable1 och Array1 uttryckligen och placeras därför i avsnittet PAGEDATA. Variable2 och Array2 är implicit nollinitierade och placeras i AVSNITTET PAGEBSS.

Implicit initiering av globala variabler till noll minskar storleken på den körbara filen på disk och föredras framför explicit initiering till noll. Explicit nollinitiering bör undvikas förutom i de fall där det krävs för att placera en variabel i ett specifikt dataavsnitt.

To make a data section memory-resident and lock it in memory, a driver calls MmLockPagableDataSection, passing a data item that appears in the pageable data section. MmLockPagableDataSection returns a handle to be used in subsequent locking or unlocking requests.

To restore a locked section's pageable status, call MmUnlockPagableImageSection, passing the handle value returned by MmLockPagableCodeSection or MmLockPagableDataSection, as appropriate. A driver's Unload routine must call MmUnlockPagableImageSection to release each handle it obtains for lockable code and data sections.

Att låsa ett avsnitt är en dyr åtgärd eftersom minneshanteraren måste söka i sin inlästa modullista innan sidorna låses i minnet. If a driver locks a section from many locations in its code, it should use the more efficient MmLockPagableSectionByHandle after its initial call to MmLockPagableXxxSection.

The handle passed to MmLockPagableSectionByHandle is the handle returned by the earlier call to MmLockPagableCodeSection or MmLockPagableDataSection.

The memory manager maintains a count for each section handle and increments this count every time that a driver calls MmLockPagableXxx for that section. A call to MmUnlockPagableImageSection decrements the count. Så länge räknaren för någon avsnittshanterare är större än noll förblir avsnittet låst i minnet.

Referensen till ett avsnitt är giltig så länge drivrutinen läses in. Therefore, a driver should call MmLockPagableXxxSection only one time. If the driver requires more locking calls, it should use MmLockPagableSectionByHandle.

Om avsnittet är utstängt när låsrutinen anropas, sidor minneshanteraren i avsnittet och anger dess referensantal till en. If the section is paged out when the lock routine is called, the memory manager pages in the section and sets its reference count to one.

Med den här tekniken minimeras förarens effekt på systemresurserna. När drivrutinen körs kan den låsa koden och data som måste finnas i minnet. När det inte finns några utestående I/O-begäranden för enheten (dvs. när enheten stängs eller om enheten aldrig öppnades) kan drivrutinen låsa upp samma kod eller data, vilket gör den tillgänglig för utsidesning.

När en drivrutin ansluter avbrott måste alla drivrutinskoder som kan anropas under avbrottsbearbetningen alltid vara bosatt i minnet. Även om vissa enhetsdrivrutiner kan göras växlingsbara eller låsta i minnet på begäran, måste vissa kärnuppsättningar av en sådan drivrutinskod och data vara permanent bosatta i systemutrymmet.

Överväg följande implementeringsriktlinjer för att låsa en kod eller ett dataavsnitt.

  • The primary use of the Mm(Un)LockXxx routines is to enable normally nonpaged code or data to be made pageable and brought in as nonpaged code or data. Drivrutiner som seriedrivrutinen och den parallella drivrutinen är bra exempel: om det inte finns några öppna referenser till en enhet som en sådan drivrutin hanterar, behövs inte delar av koden och kan förbli utsidesade. Omdirigeringen och servern är också bra exempel på drivrutiner som kan använda den här tekniken. När det inte finns några aktiva anslutningar kan båda dessa komponenter pageas ut.

  • Hela det sidbara avsnittet är låst i minnet.

  • Ett avsnitt för kod och ett för data per drivrutin är effektivt. Många namngivna, paginerbara avsnitt är i allmänhet ineffektiva.

  • Håll enbart paginerbara sektioner och sektioner som kan pagineras men är låsta på begäran åtskilda.

  • Dessa rutiner kan orsaka tung I/O-aktivitet när minneshanteraren läser in avsnittet. If a driver must lock a section from several locations in its code, it should use MmLockPagableSectionByHandle. If a driver must lock a section from several locations in its code, it should use MmLockPagableSectionByHandle.