Truy nhập bộ nhớ trực tiếp (direct memory access )

27 560 3
Truy nhập bộ nhớ trực tiếp (direct memory access )

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Truy nhập nhớ trực tiếp (Direct Memory Access ) Truy nhập nhớ trực tiếp (Direct Memory Access ) Bởi: Khoa CNTT ĐHSP KT Hưng Yên Windows XP hỗ trợ việc truy cập trực tiếp nhớ thong qua mơ hình máy tính trừu tượng mơ tả hình 7.6 Trong hình này, máy tính coi có tập hợp sơ đồ ghi mà chuyển đổi địa vật lý CPU địa bus Mỗi sơ đồ địa ghi lưu giữ địa trang vật lý Phần cứng truy cập nhớ để đọc hay ghi cách địa bus hay địa logic Sơ đồ ghi thực vai trò tiếp nhận bảng trang cho phần mềm cách cho phép phần cứng sử dụng giá trị số khác cho địa CPU hiểu Hình 7-6 Mơ hình máy tính trừu tượng chuyển MDA Một số CUP Alpha chẳng hạn có sơ đồ ghi phần cứng thực tế Một bước khởi đầu cho chuyển DMA dự trữ số ghi cho trình sử dụng bạn- tơi thảo luận vấn đề phần sơ đồ chuyển Một số loại CPU khác, x86 chẳng hạn khơng có sơ đồ ghi, bạn viết trình điều khiển bạn tương 1/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) tự họ làm Sơ đồ chuyển thực bước dảo ngược từ lên vùng đệm nhớ vật lý, mà phụ thuộc vào hệ thống Trong số trường hợp hoạt động DMA xử lý sử dụng vùng đệm đảo ngược Rõ rang số người copy liệu đến từ vùng đệm DMA trước sau dịch Trong trường hợp cụ thể, ví dụ lien hệ đường bus thiết bị chủ, mà noi tụ họp cáp- giai đoạn sơ đồ chuyển khơng làm cấu trúc mà khơng có sơ đồ ghi Nhân Windows XP sử dụng cấu trúc liệu biết đến đối tượng điều hợp để mô tả đặc tính DMA thiết bị để điều khiển truy cập đến nguồn chia sẻ, hệ thống kênh DMA sơ đồ ghi Bạn lấy trỏ trỏ tới đối tượng điều hợp lời gọi IOGetDmAAdapter suốt trình StartDevice bạn Đối tượng điều hợp có trỏ để trỏ tới cấu trúc gọi DmaOperations mà bật chứa trỏ để trỏ tới hàm mà bạn muốn gọi Hãy xem bảng 7.4 Các hàm vị trí đích hàm (ví dụ … ) mà bạn phải sử dụng phiên trước Windown NT Thực tế, tên đích có Macro mà khai báo hàm DmaOperations Table 7-4 DmaOperations Function Pointers for DMA Helper Routines DmaOperations Function Pointer Description PutDmaAdapter Destroys adapter object AllocateCommonBuffer Allocates a common buffer FreeCommonBuffer Releases a common buffer AllocateAdapterChannel Reserves adapter and map registers FlushAdapterBuffers Flushes intermediate data buffers after transfer FreeAdapterChannel Releases adapter object and map registers FreeMapRegisters Releases map registers only MapTransfer Programs one stage of a transfer GetDmaAlignment Gets address alignment required for adapter ReadDmaCounter Determines residual count 2/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) GetScatterGatherList Reserves adapter and constructs scatter/gather list PutScatterGatherList Releases scatter/gather list Chiến lược chuyển đổi (Transfer Strategies): Cách bạn thựchiện chuyển đổi DMa phụ thuộc vào nmột số nhân tố sau: Nếu thiết bị bạn có Bus-Mastering capability, tất nhiên cần có điện để truy cập vào nhớ bạn yêu cầu số chức có nơi bắt đầu, đơn vị liệu chuyển, bạn thực việc vào hay liệu nhiều điều khác Bạn phải hội ý với người thiết kế phần cứng bạn để lọc chi tiết bạn phải làm việc với bảng hướng dẫn để biết bạn cần phải làm với mức phần cứng Một thiết bị với khả tập hợp/trải chuyển khối lớn liệu đến vùng khơng cấu hình nhớ vật lý Sử dụng scatter/gather lợi thể phần mềmbởi giới hạn u cầu với khối liệu lớn trang Frame cấu hình CÁc trang đơn giản bị khố mà chúng tìm thấy nhớ vật lý thiết bị bị mô tả chúng Nếu thiết bị bạn khơng có Bus chủ, bạn sử dụng hệ thống điều khiển DMa bo mạch chủ máy tính Kiểu DMA đơi gọi DMA nô lệ (Slave) Hệ thống điều khiển DMA lien kết với bus ISA có số giới hạn nhớ truy cập độ rộng chuyển thực mà khơng có chương trình định trước Trình điều khiển cí dụ IESA thiếu giới hạn Ít Windows XP, bạn khơng cần phải biết kiểu bus phần cứng cảu bạn cắm vào hệ thống lấy hạn chế cách tự động Thông thường, hệ thống DMA bao gồm chương trình sơ đồ ghi phần cứng copy liệu trước hay sau hệ thống thiết bịcủa bạn cần đọc hay ghi liệu lien tục, bạn không cần phải thực bước với yêu cầu vào.ra, làm chậm q trình chấp nhận trường hợp cụ thể nhiều Vì bạn định biết vùng đệm chung, nơi mà thiết bị trình điều khiển bạn đơng thời truy cập nhiều thời điểm Tuy nhiên thực tế nhiều chi tiết bị phụ thuộc khác vào cách mà tác nhân ảnh hưởng lẫn nhau, bước mà bạn thực có đặc tính chung Hình 7.7 minh hoạc qua tổ chức chuyển đổi Bạn bắt đầu chuyển đổi từ công việc StartIo cách yêu cầu quyền sở hữu đối tượng điều hợp.Quyền sở hữu có giá trị bạn chia sẻ kênh DMA hệ thống với thiết bị khác, mà mơ hình DMA Windows XP u cầu bạn cần phải thực bước 3/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) Khi trình quản lý vào/ra cung cấp cho bạn quyền này, định cho bạn số sơ đồ ghi cho trình sử dụng tạm thời cảu bạnvà gọi lại hành động điều khiển điều hợp bạn cung cấp TRong hành động điều khiển điều hợp bạn, bạn thực sơ đồ chuyển đổi bước đế xếp phạm vi chuyển đổi (cũng có một) Một số phạm vi cần thiết khả sơ đồ ghi Thiết bị bạn phải cản trở điều khiển điều xáy phạm vi Figure 7-7 Flow of ownership during DMA Một thủ tục điều khiển điều hợp bạn khởi tạo sơ đồ ghi cho phạm vi đầu tiên, bạn báo hiệu cho thiết bị băt đầu hoạt động Thiết bị bạn thúc đẩy ngắt mà trình chuyển đổi ban đầu hồn tất VÀ sau bạn liệt kê DPC Thủ tục DPC khởi đầu phạm vi chuyển đổi khácnếu cần thiết khơng hồn thành yêu cầu Đôi theo cách này, bạn giải phóng sơ đồ ghi đối tượng điều hợp Sự tính tốn thời gian hai kiện số chi tiết khác mà phục thuộc vào tác nhân nêu đầu phần Thực chuyển đổi DM (Performing DMA Transfers): Bây vào chi tiết máy học mà gọi gói sở DMA chuyển đổi, khía cạnh bạn chuyển đổi số liệu riêng biệt cách sử dụng vùng đệm liệu mà với gói yêu cầu vào/ra Hãy bắt đầu cách đơn giản giả sử bạn đối diện với trường hợp chung ngày nay: Thiết bị bạn bus PCI master khơng có khả phân giải/ tụ tập 4/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) Khi bạn tạo đối tượng thiết bị mình, để bắt đầu bạn thong thường biểu thị điều bạn muốn để sử dụng phương thức truy cập trực tiếp vùng đệm liệu việc thiết lập cờ DO_DIRECT_IO Bạn chọn phương thức trực tiếp bạn chí phải thong qua địa kí hiệu nhớ lập danh sách số tham số hàm MapTransfẻ bạn gọi Sự lựa chọn đưa số vấn đề đáng quan tâm hang vùng đệm Trừ phi mà ứng dụng sử dụng cờ FILE_FLAG_NO_BUFFERING lời gọi tới hàm CreatFile, trình quản lý vào khơng bắt buộc u cầu xếp hang đối tượng thiết bị vùng đệm liệu chế độ người dùng (nó không bắt buộc yêu cầu cho nhân chế độ lời gọi ……) Nếu Hal thiết bị bạn yêu cầu vùng đệm DMA để bắt đầu ranh giới cụ thể, bạn copy từ duới lên phần nhỏ liệu người dùng tới hang xác bên vùng đệm để có hang đợi yêu cầu- điều nguyên nhân để làm sai u cầu điều có vùng đệm khơng hàng TRong hàm StartDevice, bạn tạo đối tượng điềuhợp cách sử dụng đoạn code sau: DEVICE_DESCRIPTION dd; RtlZeroMemory(&dd, sizeof(dd)); dd.Version = DEVICE_DESCRIPTION_VERSION; dd.Master = TRUE; dd.InterfaceType = InterfaceTypeUndefined; dd.MaximumLength = MAXTRANSFER; dd.Dma32BitAddresses = TRUE; pdx->AdapterObject = IoGetDmaAdapter(pdx->Pdo, &dd, &pdx->nMapRegisters); Câu lệnh cuối đoạn code quan trọng bậc IoGetDmaAdapter giao tiếp với bus điều khiển Hal để tạo đối tượng điều hợp, mà địa trả cho bạn Tham số (pdx→Pdo) định nghĩa đối tượng thiết bị vật lý cho đối tượng bạn Tham số thứ hai tới cấu trúc DEVICE_DESCRIPTION mà bạn khởi tạo để mô tả DMA tiêu biếu cho thiết bị bạn Tham số cuối nơi mà hệ thống nên lưu giữ số lượng lớn số sơ đồ ghi mà bạn phép cố gắng lưu trữ để dự trữ suốt trình chuyển đơn Bạn 5/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) cần phải lưu ý lưu trữ hai trường thiết bị mở rộng để nhận lấy hai liệu từ hàm Để khởi đầu cho hoạt động vào/ra, thủ tục StartIo cần phải dự trữ đối tượng lời gọi thủ tục AllocateAdapterChannel đối tượng Một tham số truyền tới hàm AllocateAdapterChannel địa thủ tục điều khiển điều hợp, mà trình quản lý vào gọi lưu trữ xong xuôi Đây đoạn code mẫu mà bạn sử dụng để chuẩn bị thực lời gọi tới AllocateAdapterChannel: typedef struct _DEVICE_EXTENSION { PADAPTER_OBJECT AdapterObject; // device's adapter object ULONG nMapRegisters; // max # map registers ULONG nMapRegistersAllocated; // # allocated for this xfer ULONG numxfer; ULONG xfer; ULONG nbytes; // # bytes transferred so far // # bytes to transfer during this stage // # bytes remaining to transfer PVOID vaddr; // virtual address for current stage PVOID regbase; // map register base for this stage } DEVICE_EXTENSION, *PDEVICE_EXTENSION; VOID StartIo(PDEVICE_OBJECT fdo, PIRP Irp) { PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 6/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) PMDL mdl = Irp->MdlAddress; pdx->numxfer = 0; pdx->xfer = pdx->nbytes = MmGetMdlByteCount(mdl); pdx->vaddr = MmGetMdlVirtualAddress(mdl); ULONG nregs = ADDRESS_AND_SIZE_TO_SPAN_PAGES(pdx->vaddr, pdx->nbytes); if (nregs > pdx->nMapRegisters) { nregs = pdx->nMapRegisters; pdx->xfer = nregs * PAGE_SIZE - MmGetMdlByteOffset(mdl); } pdx->nMapRegistersAllocated = nregs; NTSTATUS status = (*pdx->AdapterObject->DmaOperations ->AllocateAdapterChannel)(pdx->AdapterObject, fdo, nregs, (PDRIVER_CONTROL) AdapterControl, pdx); if (!NT_SUCCESS(status)) { CompleteRequest(Irp, status, 0); StartNextPacket(&pdx->dqReadWrite, fdo); 7/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) } } thiết bị mở rộng bạn cần phải lưu trữ số trường có lien quan đến chuyển đổi DMA Phần thích trường hợp cho trường Đây số câu lệnh khởi tạo cho trường thiết bị mở rộng cho phạm vi chuyển đổi Ở tính tốn số lượng sơ đồ ghi yêu cầu hệ thống lưu trữ cho suốt trình chuyển đổi Chúng ta bắt đầu việc tính tốn số lượng yêu cầu cho toàn chuyển đổi Macro ADDRESS_AND_SIZE_TO_SPAN_PAGES đưa vào kê khai vùng đệm kéo dài qua ranh giới trang Tuy nhiên số mà ngược từ lên với khả vượt qua số lớn mà cho phépbởi lời gọi thong thường tới hàm IoGetDmAAdapter TRong trường hợp cần thực chuyển đổi nhiều phạm vi Do đảo ngược tỉlệ trang để sử dụng số chấp nhận sơ đồ ghi Chúng ta cấn phải nhớ có sơ đồ ghi mà cho phép để huỷ xác số sau TRong lời gọi tới hàm AllocateAdapterChannel, địa đ ối tượng Adapter, địa đối tượng thiết bị chúng ta, số lượng tính tốn sơ đồ ghi, địa thủ tục điều khiển điều hợ Tham số cuối pdx tham số ngữ cảnh cho thủ tục điều khiển điều hợp Thơng thường vài thiết bị chia sẻ chung đối tượng điều hợp đơn, đối tượng điều hợp chia sẻ sống thực tế bạn tin tưởng vào hệ thống điều khiển DMA Các thiết bị Bus-Master tận dụng đối tượng điều hợp thuộc quyền sở hữu.Nhưng bạn khơng cần phải biết hệ thống thiết bị bạn tạo đối tượng điều hợp, nên bạn không cần phải đưa chứng minhnào vềnó Khi thong thường đối tượng điều hợp bận rộn bạn gọi tới AllocateAdapterChannel, yêu cầu bạn bị đặt vào hang đợi đối tượng điềuhợp trở nên xử lý (rảnh rỗi) Tất khoảng trễ xảy bên AllocateAdapterChannel mà gọi thủ tục điều khiển điều hợp bạn đối tượng điều hợp tất sơ đồ ghi mà bạn yêu cầu rảng rỗi Nhiệm vụ bạn thực mà thiết bị phụ thuộc bạn yêu cầu để nói cho thiết bị bạn biết địa vật lý để bắt đầu hoạt động phần cứng bạn IO_ALLOCATION_ACTION AdapterControl(PDEVICE_OBJECT fdo, 8/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) PIRP junk, PVOID regbase, PDEVICE_EXTENSION pdx) { PIRP Irp = GetCurrentIrp(&pdx->dqReadWrite); PMDL mdl = Irp->MdlAddress; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); BOOLEAN isread = stack->MajorFunction == IRP_MJ_READ; pdx->regbase = regbase; KeFlushIoBuffers(mdl, isread, TRUE); PHYSICAL_ADDRESS address = (*pdx->AdapterObject->DmaOperations->MapTransfer) (pdx->AdapterObject, mdl, regbase, pdx->vaddr, pdx->xfer, !isread); return DeallocateObjectKeepRegisters; } 9/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) Tham số thứ mà đặt tên junk to AdapterControl is whatever(bất nào) was in the CurrentIrp field of the device object mà bạn gọi hàm AllocateAdapterChannel Khi bạn sử dụng DEVQUEUE cho hang đợi IRP, bạn cần phải yêu cầu đối tượng DEVQUEUE mà IRP Nếu bạn sử dụng hang đợi thủ tục Microsoft IoStartPacker & IoStartNextPacket để quảnlý hang đợi bạn junk IRP Trong trường hợp gọi tên Irp để thay Có số điều khác biệt đoạn code điều khiển hoạt động vào sử dụng DMA, thuận tiện cho việc điều khiển hai hoạt động thủ tục đơn Dòng code kiểm tra code cho hàm cho Irp để định hành động đọc ghĩe xảy Tham số regbase tới hàm điều khiển không rõ ràngtrong việc định tập hợp ghi lưu trữ suốt trình sử dụng bạn Sau bạn cần tới giá trị này, bạn cần lưu trữ thiết bị mở rộng KeFlushIoBuffers chắn nội dung toàn xửlý nhớ Cache cho vùng đệm nhớ bạn sử dụng làm nhớ Tham số thứ (TRUE)chỉ bạn làm nhớ Cache chuẩn bị cho hoạt động DMA Kiểu kiến trúc CPU yêu cầu bước này, thong thường hoạt động DMA hướng trực tiếp đến từ nhớ mà không thiết phải kéo theo nhớ Cache Thủ tục Map Transfer thực phần cứng DMA cho phạm vi chuyển đổi trả địa vật lý mà việc chuyển đổi bắt đầu Chú ý bạn cung cấp địa MDL tham số thứ hai hàm Bởi bạn cần MDL điểm này, nên thong thường bạn cần phải lựa chọn phương thức DO_DIRECT_IOkhi lần bạn tạo đối tượng thiết bị mình, trình quản lý vào tự động tạo MDL cho bạn Bạn cần thong qua với sơ đồ ghi địa sở (regbase) Bạn phần MDL bị dính líu đến phạm vi hoạt động cách cung cấp địa ảo (pxd→vaddr) bute đếm (pxd→xfer) Sơ đồ chuyển đổi sử dụng tham số địa ảo để tính tốn điạ offset vùng đệm Từ xác định trang vật lý chứa đựng liệu bạn Đó điểm mà bạn lập trình phần cứng thiết bị theo cách đặc biệt u cầu Ví dụ bạn sử dụng số thủ tục WRITE_Xxx Hal để gửi địa vật lý giá trị byte đếm đến ghi card bạn, từ sau bạn điều khiển ghi nhấp nháy để bắt đầu chuyển đổi liệu Chúng ta trả số DeAllocateKeepObjectRegister để không sử dụng đối tượng điều hợp sử dụng sơ đồ ghi Trong m\ví dụ cụ thể (bus chủ PCI), ganh đua với đối tượng điều hợp vị trí khó khăn vấn đề giải phóng đối tượng điều hợp Trong số trường hợp bus làm chủ khác (bus-mastering) chia sẻ điều khiển DMA 10/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) ULONG numxfer = pdx->numxfer; (*pdx->AdapterObject->DmaOperations->FreeMapRegisters) (pdx->AdapterObject, pdx->regbase, pdx->nMapRegistersAllocated); StartNextPacket(&pdx->dqReadWrite, fdo); CompleteRequest(Irp, status, numxfer); } } Khi bạn sử dụng DEVQUEUE cho hàng đợi IRP, bạn tin tưởng vào đối tượng hàng đợi giữ đường IRP thời Thủ tục FlushAdapterBuffer điều khiển vị trí chuyển đổi u cầu sử dụng vùng đệm trung gian sở hữu hệ thống Nếu bạn thực hành động input mà kéo dài qua ranh giới trang liệu vào nằm vùng đệm trung gian cần phải copy vào vùng đệm chế độ người dùng Ở cập nhật số dư số liệu lại sau mà phạm vi chuyển đổi hoàn tất Tại vị trí này, bạn xác định phạm vi thời chuyển đổi hồn tất thành cơng có lỗi xảy Ví dụ bạn đọc trạng thái cổng xem xét kỹ kết hoạt động tương tự thực thủ tục ngắt bạn Ở ví dụ này, tơi thiết lập thuộc tính variable cho trạng thái thành công (STATUSSUCCESS) với mong đợi bạn thay đổi tìm lỗi Nếu chuyển đổi không dừng lại, bạn cần phải lập trình cho phạm vi khác Bước tiến trình tính tốn địa ảo vị trí đệm chế độ người dùng Theo tơi việc tính tốn đơn làm việc với số- thực tế chưa cố gắng để truy cập vào nhớ cách sử dụng địa ảo Tất nhiên, truy cập nhớ ý kiến tồi thực luồng ngữ cảnh tuỳ biến 13/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) Các câu lệnh y hệt việc thực phạm vi cho StartIo AdapterControl Kết cuối địa logic mà lập trình thiết bị bạn Nó phù hợp hay không phù hợp với địa vật lý hiểu CPU Một lời khuyên nhỏ bị miễn cưỡng sử dụng số sơ đồ ghi phép thủ tục điều khiển điều hợp; StartIo lưu trữ số trường nMapRegistersAllocate thiết bị mở rộng Nếu toàn chuyển đổi hồn tất, cần giải phóng sơ đồ ghi mà vừa sử dụng Các câu lệnh lại thủ tục DPC điều khiển máy học hoàn tất IRP mà đưa cho taị vị trí Các chuyển đổi sử dụng danh sách tụ họp/tỏa Nếu phần cứng bạn có hỗ trợ tụ họp/toả ra, hệ thống có thời gian thực chuyển đổi DMA đến khỏi thiết bị bạn dễ dàng Khả toả ra/tụ họp cho phép thiết bị thực chuyển đổi dính líu đến trang mà khơng liên tục nhớ vật lý Sử dụng cấu trúc Scatter_Gather_List định nghĩa WDM.H để tạo danh sách này: typedef struct _SCATTER_GATHER_ELEMENT { PHYSICAL_ADDRESS Address; ULONG Length; ULONG_PTR Reserved; } SCATTER_GATHER_ELEMENT, *PSCATTER_GATHER_ELEMENT; typedef struct _SCATTER_GATHER_LIST { ULONG NumberOfElements; ULONG_PTR Reserved; SCATTER_GATHER_ELEMENT Elements[]; } SCATTER_GATHER_LIST, *PSCATTER_GATHER_LIST; 14/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) Cuối tơi giả sử bạn đơn giản định kích thước lớn danh sách Scatter/Gather hàm AddDevice bạn di chuyển để sử dụng mà bạn cần: pdx->sglist = (PSCATTER_GATHER_LIST) ExAllocatePool(NonPagedPool, sizeof(SCATTER_GATHER_LIST) + MAXSG * sizeof(SCATTER_GATHER_ELEMENT)); Với sở hạ tầng vị trí này, thủ tuch AdapterControl bạn trông giống là: IO_ALLOCATION_ACTION AdapterControl(PDEVICE_OBJECT fdo, PIRP junk, PVOID regbase, PDEVICE_EXTENSION pdx) { PIRP Irp = GetCurrentIrp(&pdx->dqReadWrite); PMDL mdl = Irp->MdlAddress; BOOLEAN isread = IoGetCurrentIrpStackLocation(Irp) ->MajorFunction == IRP_MJ_READ; pdx->regbase = regbase; KeFlushIoBuffers(mdl, isread, TRUE); PSCATTER_GATHER_LIST sglist = pdx->sglist; ULONG xfer = pdx->xfer; PVOID vaddr = pdx->vaddr; pdx->xfer = 0; ULONG isg = 0; 15/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) while (xfer && isg < MAXSG) { ULONG elen = xfer; sglist->Elements[isg].Address = (*pdx->AdapterObject->DmaOperations->MapTransfer) (pdx->AdapterObject, mdl, regbase, pdx->vaddr, &elen, !isread); sglist->Elements[isg].Length = elen; xfer -= elen; pdx->xfer += elen; vaddr = (PVOID) ((PUCHAR) vaddr + elen); ++isg; } sglist->NumberOfElements = isg; return DeallocateObjectKeepRegisters; 16/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) } Hãy xem mô tả ban đầu cách để lấy trỏ tới IRP thủ tục điều khiển điều hợp Trước tính tốn pdx→xfer dựa vào số lượng cho phép sơ đồ ghi Bây cố gắng để chuyển đổi nhiều liệu, số lượng cho phép phần tử Scatter/Gather vượt giới hạn vài (trong số đó)chúng ta chuyển đổi suốt phạm vi Trong suốt vòng lặp đây, xfer số lượng byte mà chưa lập sơ đồ, phải tính tốn lại pdx→xfer (đã tiến hành thực hiện) Đây vịng lặp mà tơi hứa với bạn, nơi mà gọi Map transfer để đặt phần tử Scatter/Gather Chúng ta tiếp tục vòng lặp tận sơ đồ hố tồn phạm vi chuyển đổi tận khỏi phần tử Scatter/Gather, điều xảy Khi gọi tới sơ đồ chuyển đổi (map transfer) cho thiết bị Scatter/ Gather, sửa đổi chiều dài tham số để có MDL bắt đầu địa ảo đựơc cung cấp (vaddr) liên quy luật tự nhiên va mà sơ đồ hoá phần tử danh sách Scatter/Gather đơn Nó trả địa vật lý điểm bắt đầu vùng Đây nơi mà cập nhật biến mà mô tả phạm vi thời chuyển đổi Khi rời khỏi vòng lặp, xfer bị giảm xuống (hoặc chạy phần tử Scatter/Gather), pxd→xfer tăng đến tổng số tất phần tử sơ đồ hố Chúng ta không cập nhật trường pdx→xfer thiết bị mmở rộng- làm việc thủ tục DPC Đó chi tiết phiền hà khác Đây nơi mà tăng số phần tử Scatter/Gather để phản ánh thực tế sử dụng tăng lên Tại vị trí này, có phần tử Scatter/Gather isg mà nên lập trình thiết bị thiết bị phụ thuộc theo cách thích đáng Sau nên khởi động hoạt động thiết bị yêu cầu Trả DeAllocateObjectKeepRegisters hợp lý cho thiết bị bus làm chủ Về mặt lý thuyết bạn có thiết bị khơng làm chủ với khả Scatter/Gather, trả KeepObject thay giá trị khác Thủ tục StartIo có dạng như: VOID StartIo(PDEVICE_OBJECT fdo, PIRP Irp) { PDEVICE_EXTENSION pdx = 17/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) (PDEVICE_EXTENSION) fdo->DeviceExtension; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status; PMDL mdl = Irp->MdlAddress; ULONG nbytes = MmGetMdlByteCount(mdl); PVOID vaddr = MmGetMdlVirtualAddress(mdl); BOOLEAN isread = stack->MajorFunction == IRP_MJ_READ; pdx->numxfer = 0; pdx->nbytes = nbytes; status = (*pdx->AdapterObject->DmaOperations->GetScatterGatherList) (pdx->AdapterObject, fdo, mdl, vaddr, nbytes, (PDRIVER_LIST_CONTROL) DmaExecutionRoutine, pdx, !isread); if (!NT_SUCCESS(status)) { CompleteRequest(Irp, status, 0); StartNextPacket(&pdx->dqReadWrite, fdo); } } Trong StartDevice, bạn có bít nhỏ phần code thêm vào để định kênh DMA mà trình quản lý PnP phân cơng cho bạn, bạn cần khởi tạo nhiều trường cấu trúc DEVICE_DESCRIPTION cho IoGetDmAAdapter: NTSTATUS StartDevice( ) 18/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) { ULONG dmachannel; // system DMA channel # ULONG dmaport; // MCA bus port number for (ULONG i = 0; i < nres; ++i, ++resource) { switch (resource->Type) { case CmResourceTypeDma: dmachannel = resource->u.Dma.Channel; dmaport = resource->u.Dma.Port; break; } } DEVICE_DESCRIPTION dd; RtlZeroMemory(&dd, sizeof(dd)); dd.Version = DEVICE_DESCRIPTION_VERSION; dd.InterfaceType = InterfaceTypeUndefined; dd.MaximumLength = MAXTRANSFER; 19/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) dd.DmaChannel = dmachannel; dd.DmaPort = dmaport; dd.DemandMode = ??; dd.AutoInitialize = ??; dd.IgnoreCount = ??; dd.DmaWidth = ??; dd.DmaSpeed = ??; pdx->AdapterObject = IoGetDmaAdapter( ); } Danh sách nguồn tài nguyên vào/ra có tài ngun DMA, từnhững mà bạn cần để trích kênh số hiệu cổng Số kênh định nghĩa số kênh hỗ trợ hệ thống điều khiển DMA Số hiệu cổng bus thiết bị MCA Bắt đầu từ đây, bạn buộc phải khởi tạo số trường cấu trúc DEVICE_DESCRIPTION dựa vào hiểu biết bạn thiết bị bạn Hãy xem bảng 7.5 Tất điều điều khiển điều hợp bạn thủ tục DPC giống hệt với đoạn code mà xem xét phần đầu phần điều khiển thiết bị busmastering khơng có khả sơ đồ ghi ngoại trừ hai chi tiết nhỏ Thứ là, adaptercontrol trả giá trị khác IO_ALLOCATION_ACTION AdapterControl( ) { return KeepObject; } 20/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) Giá trị trả KeepObject muốn giữ lại điều khiển thông qua sơ đồ ghi kênh DMA sử dụng Thứ hai là, từ khơng giải phóng đối tượng điều hợp mà AdapterControl trả ra, phải làm việc thủ tục DPC lời gọi FreeAdapterChannel thay FreeMapRegister: VOID DpcForIsr( ) { (*pdx->AdapterObject->DmaOperations->FreeAdapterChannel) (pdx->AdapterObject); } Sử dụng đệm chung (Using a Common Buffer) Bạn thường định đệm chung bạn thời điểm StartDevice sau tạo đối tượng điều hợp bạn: typedef struct _DEVICE_EXTENSION { PVOID vaCommonBuffer; PHYSICAL_ADDRESS paCommonBuffer; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; dd.Dma32BitAddresses = ??; dd.Dma64BitAddresses = ??; pdx->AdapterObject = IoGetDmaAdapter( ); 21/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) pdx->vaCommonBuffer = (*pdx->AdapterObject->DmaOperations->AllocateCommonBuffer) (pdx->AdapterObject, , &pdx->paCommonBuffer, FALSE); Ưu tiên cho gọi IoGetDmAAdapter, bạn thiết lập cờ Dma32BitAddresses & Dma64BitAddresses cấu trúc DEVICE_DESCRIPTION để nói rõ khả địa thiết bị bạn Điều là: thiết bị bạn định địa đệm sử dụng điạ vật lý 32 bít, thiết lập Dma32BitAddresses thành true Nếu định địa đệm sử dụng địa 64 bít thiết lập Dma64BitAddresses thành True Trong lời gọi tới hàm AllocateCommonBuffer, tham số thứ hai byte độ dài đệm bạn muốn định Đối số thứ giá trị Boolean mà định bạn muốn nhớ định chấp nhận nhớ cache CPU (TRUE) hay không (FALSE) AllocateCommonBuffer trả địa ảo Đây địa bạn sử dụng trình điều khiển bạn để truy cập vào vùng đệm định AllocateCommonBuffer thiết lập PHYSICAL_ADDRESS trỏ tới tham số thứ : địa logic sử dụng vởi thiết bị bạn cho vùng đệm truy cập Thiết bị Bus-Master đơn giản phận điều khiển mẫu PKTDMA nội dung sách hướng dẫn để thực hoạt động bus-master DMA không cần hỗ trợ scatter/gather sử sụng mai mối chíp (matchmaker chip) AMCC S5933 PCI Bạn thảo luận chi tiết điều khiển khởi tạo thiết bị StartDevice để khởi tạo chuyển giao DMA StartIo Bạn cần phải thảo luận tất điề xảy AdapterControl thiết bị thủ tục DpcForIsr tơi trình bày ngắn gọn đầu thủ tục cần phải có vài dịng code thiết bị - phụ thuộc cho việc bắt đầu hoạt động thiết bị Bạn viết hàm helper có tên StartTransfer với mục đích: VOID StartTransfer(PDEVICE_EXTENSION pdx, PHYSICAL_ADDRESS address, BOOLEAN isread) { ULONG mcsr = READ_PORT_ULONG((PULONG)(pdx->portbase + MCSR); ULONG intcsr = 22/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) READ_PORT_ULONG((PULONG)(pdx->portbase + INTCSR); if (isread) { mcsr │= MCSR_WRITE_NEED4 │ MCSR_WRITE_ENABLE; intcsr │= INTCSR_WTCI_ENABLE; WRITE_PORT_ULONG((PULONG)(pdx->portbase + MWTC), pdx->xfer); WRITE_PORT_ULONG((PULONG)(pdx->portbase + MWAR), address.LowPart); } else { mcsr │= MCSR_READ_NEED4 │ MCSR_READ_ENABLE; intcsr │= INTCSR_RTCI_ENABLE; WRITE_PORT_ULONG((PULONG)(pdx->portbase + MRTC), pdx->xfer); WRITE_PORT_ULONG((PULONG)(pdx->portbase + MRAR), address.LowPart); } WRITE_PORT_ULONG((PULONG)(pdx->portbase + INTCSR), intcsr); 23/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) WRITE_PORT_ULONG((PULONG)(pdx->portbase + MCSR), mcsr); } Thủ tục cài đặt ghi hoạt động S5933 cho chuyển giao DMA sau chuyển giao bắt đầu chạy Các Bước trình sau : Địa chương trình ( MxAR ) tổng số chuyển giao (MxTC) ghi thích hợp để định hướng cho luồng liệu AMCC chọn cho giới hạn đọc để miêu tả hoạt động truyền liệu thiết bị Bởi thực đầy đủ IRP_MJ_WRITE, chương trình đọc hoạt động chip level địa sửa dụng địa logic quay trở lại MapTransfer Cho phép ngắt mà chuyển đổi dần tới việc viết Intcsr Bắt đầu chuyển đổi cách thiết lập bít cho phép chuyển đổi MCSR Đoạn code không rõ ràng cho lắm, S5933 khả thực tế việc DMA đọc DMA viết thời điểm Tơi viết PKTdma theo cách với hoạt động (hoặc đọc viết) xảy Để khái qt hố trình điều khiển cho phép hai loại hoạt động xảy đồng thời, bạn cần tới phương tiện để tách hàng đợi cho việc đọc ghi IRP tạo hai đối tượng thiết bị hai đối tượng điều hợp- cặp để đọc cặp lại để viết Để tránh tình trạng lúng túng việc cố gắng để đợi gấp đôi đối tượng giống bên AllocateAdapterChannel Tôi nghĩ việc thêm phức tạp vào ví dụ mẫu gây khó khăn cho bạn (tôi biết cảm thấy lạc quan kĩ mô tả để hàm ý không làm cho bạn thấy lẫn lộn, tồi tệ hơn) Điều khiển ngắt PKTDMA PCI42 bao gồm thủ tục ngắt mà thực bit nhỏ công việc để di chuyển liệu Thủ tục ngắt PKTDMA đơn giản BOOLEAN OnInterrupt(PKINTERRUPT InterruptObject, PDEVICE_EXTENSION pdx) { ULONG intcsr = READ_PORT_ULONG((PULONG) (pdx->portbase + INTCSR)); 24/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) if (!(intcsr & INTCSR_INTERRUPT_PENDING)) return FALSE; ULONG mcsr = READ_PORT_ULONG((PULONG) (pdx->portbase + MCSR)); WRITE_PORT_ULONG((PULONG) (pdx->portbase + MCSR), mcsr & ~(MCSR_WRITE_ENABLE │ MCSR_READ_ENABLE)); intcsr &= ~(INTCSR_WTCI_ENABLE │ INTCSR_RTCI_ENABLE); BOOLEAN dpc = GetCurrentIrp(&pdx->dqReadWrite) != NULL; while (intcsr & INTCSR_INTERRUPT_PENDING) { InterlockedOr(&pdx->intcsr, intcsr); WRITE_PORT_ULONG((PULONG) (pdx->portbase + INTCSR), intcsr); intcsr = READ_PORT_ULONG((PULONG) (pdx->portbase + INTCSR)); } if (dpc) IoRequestDpc(pdx->DeviceObject, NULL, NULL); return TRUE; } Tôi mô tả cách thức mà ISR khơng giống với PCI42: S5933 trì cố gắng để chuyển đổi liệu- mà chủ đề ghi đếm- lâu bít cho phép thiết lập MCSR Câu lệnh xố hai bít Nếu trình điều khiển bạn điều khiển đồng thời việc đọc ghi, bạn cần định loại hoạt động kết thúc việc kiểm 25/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) tra cờ ngắt INTCSR sau bạn disable chuyển đổi theo phương diện Chúng ta viết lại đoạn ngắn INTCSR để xoá ngắt Câu lệnh đảm bảo disable việc chuyển đổi -đếm – ngắt để chúng sảy thêm lần Một lần nữa, trình điều khiển bạn mà điều khiển đọc ghi đồng thời khơng có khả ngắt mà xảy Kiểm tra PKTDMA Bạn kiểm tra PKTDMA bạn có bảng mạch phát triển S5933DK1 Nếu bạn chạy chương trình test PCI42, bạn cài đặt 5933DK1 SYS driver ISA thêm vào- card interface Nếu không, bạn cần phải cài đặt driver cho chương trình test Sau cài đặt PKTDMA.SYS trình điều khiển cho bo mạch phát triển S5933 Bạn chạy TEST.EXE kiểm tra chương trình mà thư mục PKTDMA \TEST\ DEBUG Test thực ghi cho 8192 bytes cho PKTDMA Nó phát DeviceIoCntrol cho S5933DK1 để đọc lại liệu từ mặtt thêm vào, kiểm tra có đọc giá trị khơng Những ý tính tương thích Windows 98/Me MnGetAddressForMdlSafe macro mà dẫn chứng hàm (MmMapLockedPagesSpecifyCache) mà Windows 98/Me không xuất Các macro cũ, MnGetAddressForMdl bị phản đối Việc thẩm tra trình điều khiển (Driver Verifier) flag lời gọi thời gian thực thi tới macro cũ Điểm khác biệt là: MnGetAddressForMdl bug check khơng có đủ tiếp nhận bảng trang để sơ đồ hoá nhớ định, ngược lại MnGetAddressForMdlSafe đơn giản trả trỏ Null Ở có cách giải khác cho vấn đề đưa MnGetAddressForMdlSafe: CSHORT oldfail = mdl->MdlFlags & MDL_MAPPING_CAN_FAIL; mdl->MdlFlags │= MDL_MAPPING_CAN_FAIL; PVOID address = MmMapLockedPages(mdl, KernelMode); if (!oldfail) mdl->MdlFlags &= ~MDL_MAPPING_CAN_FAIL; Thiết lập cờ MDL_MAPPING_CAN_FAIL nguyên nhân làm cho Windows 200 XP lấy đường dẫn bên đoạn code MnMapLockedPagesSpecifyCache, 26/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) cách hoàn thành lệnh để sử dụng macro Windows 98/ME lờ cờ (và ln trả giá trị Null trường hợp sai, không cần cờ hay macro mới.) Nếu bạn sử dụng GENERIC.SYS, lời gọi đơn giản GenericGetSystemAddressForMdl, mà chứa điều nói đoạn code Tôi không cố gắng để thêm vào MnMapLockedPagesSpecifyCache tới WDMSTUB.SYS (xem phục lục A) Windows 98/ME không cung cấp phận cần thiết để hỗ trợ hoàn toàn cho hàm 27/27 ... MRAR), address.LowPart); } WRITE_PORT_ULONG((PULONG)(pdx->portbase + INTCSR), intcsr); 23/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) WRITE_PORT_ULONG((PULONG)(pdx->portbase + MCSR), mcsr);... PDEVICE_EXTENSION pdx) { ULONG intcsr = READ_PORT_ULONG((PULONG) (pdx->portbase + INTCSR )) ; 24/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) if (!(intcsr & INTCSR_INTERRUPT_PENDING )) return FALSE;... AdapterControl, pdx); if (!NT_SUCCESS(status )) { CompleteRequest(Irp, status, 0); StartNextPacket(&pdx->dqReadWrite, fdo); 7/27 Truy nhập nhớ trực tiếp (Direct Memory Access ) } } thiết bị mở

Ngày đăng: 31/12/2015, 22:13

Từ khóa liên quan

Mục lục

  • Truy nhập bộ nhớ trực tiếp (Direct Memory Access )

Tài liệu cùng người dùng

Tài liệu liên quan