diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-EB2566BD-8F65-5A81-B215-E8B05CFE21C3.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-EB2566BD-8F65-5A81-B215-E8B05CFE21C3.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,281 @@ + + + + + +Migration +Tutorial: Demand Paging and Media DriversDescribes how to change media drivers when demand paging is used. +

Demand paging is a change made from Symbian platform v9.3 to how the Kernel +uses RAM and storage media. This topic

+
Introduction

If the ROM has been built with paging +enabled, the image is divided into two sections: an unpaged section and a +paged section. In addition to this, code that is not part of the ROM can be +loaded on demand into RAM from other non-XIP partitions and/or media, for +example FAT or ROFS partitions.

Two types of paging are currently +supported:

    +
  • ROM paging - paging +from the paged section of the ROM image

  • +
  • code paging - paging +from non-removable media, for example, a FAT partition on an internal Multi +Media Card (MMC) drive or an internal NAND ROFS/FAT partition.

    See +also Paging from an +internal MMC.

  • +

: A difference between ROM paging and code paging is that +all ROM pages are contiguous, whereas code that is paged from other drives +may be split over several potentially non-contiguous clusters. This puts an +extra burden on the paging subsystem as it needs to identify the layout of +the DLL on the media before it is deemed pageable. This is achieved by using +the file servers blockmap API.

Media drivers are typically +PDDs with a filename of med.pdd. Normally they are declared +in the rombuild.oby file with the keyword extension or device and +are therefore flagged as unpaged. That is, once loaded their code and read-only +data sections are not paged out.

A media driver that is capable of +servicing page requests from the paging subsystem must ensure that the thread +in which the media driver runs takes the page fault itself otherwise a deadlock +could occur. In theory, the only time this can happen is when a media driver +accepts a write request from a user side client that points to data in the +paged section of the ROM or to code that has been loaded into RAM from code +paging enabled media. To remedy this, the local media subsystem has been modified +to lock write requests to paging media drivers before they are dispatched +and to split large write requests into a series of smaller ones to avoid exhausting +available RAM.

The two initial stages relevant to this discussion +are:

    +
  • the kernel extension +entry point - identified by the DECLARE_STANDARD_EXTENSION macro

  • +
  • the PDD entry point +- identified by the DECLARE_EXTENSION_PDD macro.

  • +

To enable demand paging as soon as possible in the boot sequence +it is desirable to instantiate and install the PDD factory object earlier, +for example in the kernel extension entry point.

Some media +drivers have no kernel extension entry point defined, the MMC media driver +is an example. These drivers have a DECLARE_STANDARD_PDD macro +defined rather than DECLARE_EXTENSION_PDD. They require +modification to have a DECLARE_EXTENSION_PDD and a DECLARE_STANDARD_EXTENSION.

The +steps needed to support ROM and/or code paging are as follows:

    +
  1. determine whether code +paging is supported, and if so, identify the relevant local drive number or +numbers

  2. +
  3. modify variantmediadef.h

  4. +
  5. modify the media drivers kernel extension entry point to register +the media driver with the paging subsystem and to instantiate and install +the DPhysicalDevice derived factory object

  6. +
  7. modify the DLocalDrive::Ecaps() handling

  8. +
  9. modify the media drivers DMediaDriver::Request function +to accept the four new paging +request types

  10. +
  11. Handling fragmented write requests.

  12. +
+
Changes to +variantmediadef.h

The following should be defined using appropriate +names in the variant's variantmediadef.h file:

    +
  • PAGING_TYPE - +flags that indicate whether code paging and/or ROM paging is supported

  • +
  • NAND_PAGEDRIVELIST - +a list of the paging drives

  • +
  • NAND_PAGEDRIVECOUNT - +the total number of paging drives

  • +
  • NUM_PAGES - +if a write request points to data that resides in paged ROM, the request is +split up into separate fragments of the specified size. This value needs to +be chosen with care, as if it is too small writes can take too long to finish.

  • +

Normal write requests which point to data that is not in paged +ROM are not fragmented. However, large requests are split up into smaller +requests by the file server, providing clients with a more responsive system.

The +macros defined in the file variantmediadef.h are passed to LocDrv::RegisterPagingDevice(). +This function is similar to LocDrv::RegisterMediaDevice() in +that it takes a drive list as a parameter, but it identifies the drive or +drives to be used for code paging. If code only ROM paging is needed, set +the drive count to zero.

Changes made to support paging on NAND:

// Variant parameters for NAND flash media driver (mednand.pdd) +#define NAND_DRIVECOUNT 8 +#define NAND_DRIVELIST 2,3,5,6,7,9,10,11 +#define NAND_NUMMEDIA 1 +#define NAND_DRIVENAME "Nand" + +#define PAGING_TYPE DPagingDevice::ERom | DPagingDevice::ECode + +// code paging from writeable FAT, Composite FAT and first ROFS +#define NAND_PAGEDRIVELIST 2,5,6 +#define NAND_PAGEDRIVECOUNT 3 + +// defines the size of fragment +#define NUM_PAGES 8
+
Changes to +the media driver kernel extension point

The kernel-extension entry +point must create a DFC queue to satisfy any page fault that occurs in the +drive thread. Failure to do so results in a kernel fault. The entry point +must then create a DPrimaryMediaBase object and register +it with the local media subsystem. To support paging, the entry point needs +altering to register the paging device with the demand paging subsystem and +instantiate and install the factory object.

DECLARE_STANDARD_EXTENSION() + { + TInt r=Kern::DfcQInit(&TestMediaDfcQ,KTestThreadPriority,&KTestMediaThreadName); + if (r|=KErrNone) + return r; + + DPrimaryMediaBase* pM=new DPrimaryMediaBase; + if (!pM) + return r; + + pM->iDfcQ=&TestMediaDfcQ; + r=LocDrv::RegisterMediaDevice( + MEDIA_DEVICE_NAND, + NAND_DRIVECOUNT, + NAND_DRIVELIST, + pM, + NAND_NUMMEDIA, + NAND_DRIVENAME); + if (r != KErrNone) + return r; + + r = LocDrv::RegisterPagingDevice( + pM, + NAND_PAGEDRIVELIST, + NAND_PAGEDRIVECOUNT, + PAGING_TYPE, + SECTOR_SHIFT, + NUM_PAGES); + if (r == KErrNone) + { + device = new DPhysicalDeviceMediaTest; + if (device == NULL) + return KErrNoMemory; + r = Kern::InstallPhysicalDevice(device); + } + // Ignore error if demand paging not supported by kernel + else if (r == KErrNotSupported) + r = KErrNone; + else + return r; + + pM->iMsgQ.Receive(); + return KErrNone; + }

The fifth parameter passed to the function LocDrv::RegisterPagingDevice() named SECTOR_SHIFT is the log2 of the sector size for the given media. For example, passing +a value of 9 corresponds to a sector size of 512 for most media.

The DECLARE_EXTENSION_PDD entry +point is called some time later when the file server tries to load all the +media drivers in the system. When this happens a second factory object is +created by the media driver, but this is deleted by the kernel when it discovers +that another factory object bearing the same name is already in its internal +list.

+
Changes to +DLocalDrive::ECaps handling

The TLocalDriveCaps structure +needs to be modified so that:

    +
  • the KMediaAttPageable flag +is set in iMediaAtt

  • +
  • the KDriveAttPageable flag +is set if a particular drive has been registered as code paging. This is determined +by testing TLocDrvRequest::Drive() ->iPagingDrv.

  • +

Additionally, the TLocalDriveCaps ::iDriveAtt must +have the KDriveAttLocal and KDriveAttInternal bits +set and the KDriveAttRemovable bit cleared.

TInt DMediaDriverTest::Request(TLocDrvRequest& aRequest) + { + TInt r=KErrNotSupported; + TInt id=aRequest.Id(); + + if (id == DLocalDrive::ECaps) + { + TLocDrv* drive = aRequest.Drive(); + TLocalDriveCapsV4& c = *(TLocalDriveCapsV4*)aRequest.RemoteDes(); + r=Caps(*drive,c); + } + // etc… + } + +TInt DMediaDriverTest::Caps(TLocDrv& aDrive, TLocalDriveCapsV4& caps) + { + // fill in rest of caps structure as usual… + + if(aDrive.iPrimaryMedia->iPagingMedia) + caps.iMediaAtt|=KMediaAttPageable; + if(aDrive.iPagingDrv) + caps.iDriveAtt|=KDriveAttPageable; + }
+
Handling page +requests

Four new request types need to be handled to support paging:

    +
  • EWriteRequestFragment marks +the start and middle of a sequence of writes.

  • +
  • Each sequence is terminated +by a EWriteRequestFragmentLast request as long as none +of the prior requests completed with an error.

  • +
  • ERomPageInRequest is +treated as a normal read except that:

      +
    1. the list of partitions +reported by DMediaDriver::PartitionInfo does not normally +include the partition containing the ROM image. Therefore, the local media +subsystem does not know the absolute position from the start of the media +of a particular ROM page. The position stored in ERomPageInRequest is +offset from the start of the ROM image, rather than the start of the media. +Therefore, the media driver must add the offset of the start of the ROM image +to the position stored in ERomPageInRequest to obtain the +absolute position before issuing a read request.

    2. +
    3. when the read is complete +the media driver needs to call TLocDrvRequest::WriteToPageHandler to +write the data back to the client, rather than TLocDrvRequest::WriteRemote as +for a normal read,

    4. +
  • +
  • ECodePageInRequest is +treated as a normal read, except that the function TLocDrvRequest::WriteToPageHandler should +be used to write the data back to the demand paging subsystem. However, the +position in the request is offset from the start of the media as for a normal +read.

  • +

These request types are enumerated in the DMediaPagingDevice class:

NONSHARABLE_CLASS(DMediaPagingDevice) : public DPagingDevice + { +public: + enum TPagingRequestId + { + /** + Identifies any middle fragment of a Write request on a partition of a media that supports paging. + */ + EWriteRequestFragment = + DLocalDrive::EFirstReqNumberReservedForPaging, + + /** + Identifies the last fragment of a Write request on a partition of a media that supports paging. + */ + EWriteRequestFragmentLast = + DLocalDrive::EFirstReqNumberReservedForPaging+1, + + /** + Request for paging in (read) data from the ROM store area. + */ + ERomPageInRequest = + DLocalDrive::EFirstReqNumberReservedForPaging+2, + + /** + Request for paging in (read) data from the code store area. + */ + ECodePageInRequest = + DLocalDrive::ELastReqNumberReservedForPaging + }; + //etc… + }
+
Handling fragmented +write requests

In many respects, EWriteRequestFragment and EWriteRequestFragmentLast can +be treated as normal write requests. It should be noted however, that these +write requests can be interleaved with requests from other file server threads +if the media supports more than one partition, the resulting operations may +be perceived as a functional break in behaviour.

If it is important +to maintain backwards compatibility and to prevent write requests from being +interleaved, the media driver must keep track of the current write-request +chain and defer requests from other drive threads while a write-fragment chain +is in progress by:

    +
  • ensuring the local media +subsystem LDD has been built with the __ALLOW_CONCURRENT_FRAGMENTATION__ macro +undefined. This ensures that the local media subsystem never issues more than +one write fragment at a time

  • +
  • modifying the paging-media +driver so that it keeps track of write-request chains and defers any read +or format requests received after the first fragment and before the last in +a sequence. When undefined, the macro subsystem does not issue more than one +write-request chain at a time.

  • +

Write fragments should never be deferred, only read or format +requests may be deferred.

To achieve this the media driver +can maintain a bit mask, each bit of which represents a write in progress +flag for a particular drive:

iFragmenting|=(0x1<<iCurrentReq->Drive()->iDriveNumber);

If a read or format request is received while any of the bits in iFragmenting are +set, that request may be deferred.

+
\ No newline at end of file