From e94a9d76f2c12a01938b844bbca86077e1fa6e3a Mon Sep 17 00:00:00 2001 From: Mathias Gottschlag Date: Sun, 30 Nov 2008 13:59:05 +0100 Subject: [PATCH] Implemented DMA. --- system/{modules/cdi/dma.c => include/ke/dma.h} | 45 ++++----- system/kernel/CMakeLists.txt | 1 + system/kernel/ke/dma.c | 128 +++++++++++++++++++++++++ system/kernel/ke/start.c | 10 +- system/modules/cdi/dma.c | 26 +++-- 5 files changed, 174 insertions(+), 36 deletions(-) copy system/{modules/cdi/dma.c => include/ke/dma.h} (68%) create mode 100644 system/kernel/ke/dma.c diff --git a/system/modules/cdi/dma.c b/system/include/ke/dma.h similarity index 68% copy from system/modules/cdi/dma.c copy to system/include/ke/dma.h index 04be981..e4d319a 100644 --- a/system/modules/cdi/dma.c +++ b/system/include/ke/dma.h @@ -19,31 +19,22 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include - -int cdi_dma_open(struct cdi_dma_handle* handle, uint8_t channel, uint8_t mode, - size_t length, void* buffer) -{ - kePrint("cdi_dma_open: Stub!\n"); - return -1; -} - -int cdi_dma_read(struct cdi_dma_handle* handle) -{ - kePrint("cdi_dma_read: Stub!\n"); - return -1; -} - -int cdi_dma_write(struct cdi_dma_handle* handle) -{ - kePrint("cdi_dma_write: Stub!\n"); - return -1; -} - -int cdi_dma_close(struct cdi_dma_handle* handle) -{ - kePrint("cdi_dma_close: Stub!\n"); - return -1; -} +#ifndef KE_DMA_H_INCLUDED +#define KE_DMA_H_INCLUDED + +#include + +#define KE_DMA_MODE_READ (1 << 2) +#define KE_DMA_MODE_WRITE (2 << 2) +#define KE_DMA_MODE_ON_DEMAND (0 << 6) +#define KE_DMA_MODE_SINGLE (1 << 6) +#define KE_DMA_MODE_BLOCK (2 << 6) + +int keOpenDMA(uint8_t channel, uint8_t mode, void *buffer, uint32_t length); +int keCloseDMA(uint8_t channel); + +int keReadDMA(uint8_t channel); +int keWriteDMA(uint8_t channel); + +#endif diff --git a/system/kernel/CMakeLists.txt b/system/kernel/CMakeLists.txt index db47520..20dd4f4 100644 --- a/system/kernel/CMakeLists.txt +++ b/system/kernel/CMakeLists.txt @@ -6,6 +6,7 @@ fs/request.c ke/apic.c ke/cpu.c ke/debug.c +ke/dma.c ke/gdt.c ke/interrupts.c ke/intstubs.S diff --git a/system/kernel/ke/dma.c b/system/kernel/ke/dma.c new file mode 100644 index 0000000..963be61 --- /dev/null +++ b/system/kernel/ke/dma.c @@ -0,0 +1,128 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "ke/dma.h" +#include "ke/errors.h" +#include "ke/spinlock.h" +#include "ke/ports.h" +#include "mm/memory.h" +#include + +typedef struct +{ + uint8_t channel; + uint8_t mode; + void *buffer; + uint32_t length; + uintptr_t dmabuffer_phys; + void *dmabuffer; + KeSpinlock opened; +} KeDMAChannel; + +static KeDMAChannel channels[8]; + +//static uint16_t dma_status[8] = {0x08, 0x08, 0x08, 0x08, 0xD0, 0xD0, 0xD0, 0xD0}; +//static uint16_t dma_command[8] = {0x08, 0x08, 0x08, 0x08, 0xD0, 0xD0, 0xD0, 0xD0}; +//static uint16_t dma_request[8] = {0x09, 0x09, 0x09, 0x09, 0xD2, 0xD2, 0xD2, 0xD2}; +static uint16_t dma_channel_mask[8] = {0x0A, 0x0A, 0x0A, 0x0A, 0xD4, 0xD4, 0xD4, 0xD4}; +static uint16_t dma_mode[8] = {0x0B, 0x0B, 0x0B, 0x0B, 0xD6, 0xD6, 0xD6, 0xD6}; +static uint16_t dma_data[8] = {0x0C, 0x0C, 0x0C, 0x0C, 0xD8, 0xD8, 0xD8, 0xD8}; +//static uint16_t dma_intermediate[8] = {0x0D, 0x0D, 0x0D, 0x0D, 0xDA, 0xDA, 0xDA, 0xDA}; +//static uint16_t dma_mask[8] = {0x0F, 0x0F, 0x0F, 0x0F, 0xDE, 0xDE, 0xDE, 0xDE}; +static uint16_t dma_addr[8] = {0x00, 0x02, 0x04, 0x06, 0xC0, 0xC4, 0xC8, 0xCC}; +static uint16_t dma_page[8] = {0x87, 0x83, 0x81, 0x82, 0x8F, 0x8B, 0x89, 0x8A}; +static uint16_t dma_size[8] = {0x01, 0x03, 0x05, 0x07, 0xC2, 0xC6, 0xCA, 0xCE}; + +int keOpenDMA(uint8_t channel, uint8_t mode, void *buffer, uint32_t length) +{ + // Open channel + if (channel >= 8) return KE_ERROR_UNKNOWN; + if (keTryLockSpinlock(&channels[channel].opened)) return KE_ERROR_UNKNOWN; + channels[channel].channel = channel; + channels[channel].mode = mode; + channels[channel].buffer = buffer; + channels[channel].length = length; + + // Allocate buffer + uint32_t pagecount = (length + 0xFFF) / 0x1000; + uintptr_t dmabuffer_phys = mmAllocPhysicalMemory(MM_MEMORY_ALLOC_DMA, + 0, pagecount * 0x1000); + channels[channel].dmabuffer_phys = dmabuffer_phys; + uintptr_t dmabuffer = mmFindFreeKernelPages(MM_MAX_KERNEL_PAGE, + MM_MIN_KERNEL_PAGE, 0, pagecount * 0x1000); + uint32_t i; + for (i = 0; i < pagecount; i++) + { + mmMapKernelMemory(dmabuffer_phys + i * 0x1000, dmabuffer + i * 0x1000, + MM_MAP_READ | MM_MAP_WRITE); + } + memset((void*)dmabuffer, 0, length); + channels[channel].dmabuffer = (void*)dmabuffer; + // Setup DMA + // Mask channel + outb(dma_channel_mask[channel], channel | 0x4); + // Set address + outb(dma_data[channel], 0xFF); + outb(dma_addr[channel], dmabuffer_phys & 0xFF); + outb(dma_addr[channel], (dmabuffer_phys >> 8) & 0xFF); + outb(dma_page[channel], (dmabuffer_phys >> 16) & 0xFF); + // Set size + outb(dma_data[channel], 0xFF); + outb(dma_size[channel], length & 0xFF); + outb(dma_size[channel], (length >> 8) & 0xFF); + // Set mode + outb(dma_mode[channel], (mode & 0xFC) + (channel & 0x3)); + // Unmask channel + outb(dma_channel_mask[channel], channel); + + return 0; +} +int keCloseDMA(uint8_t channel) +{ + if (channel >= 8) return KE_ERROR_UNKNOWN; + // Free buffer + uint32_t pagecount = (channels[channel].length + 0xFFF) / 0x1000; + mmFreePhysicalMemory(channels[channel].dmabuffer_phys, pagecount * 0x1000); + uint32_t i; + for (i = 0; i < pagecount; i++) + { + mmMapKernelMemory(0, (uintptr_t)channels[channel].dmabuffer + i * 0x1000, 0); + } + // Close channel + keUnlockSpinlock(&channels[channel].opened); + return 0; +} + +int keReadDMA(uint8_t channel) +{ + if (channel >= 8) return KE_ERROR_UNKNOWN; + memcpy(channels[channel].buffer, channels[channel].dmabuffer, + channels[channel].length); + return 0; +} +int keWriteDMA(uint8_t channel) +{ + if (channel >= 8) return KE_ERROR_UNKNOWN; + memcpy(channels[channel].dmabuffer, channels[channel].buffer, + channels[channel].length); + return 0; +} + diff --git a/system/kernel/ke/start.c b/system/kernel/ke/start.c index d8f8d2e..43542b7 100644 --- a/system/kernel/ke/start.c +++ b/system/kernel/ke/start.c @@ -60,11 +60,19 @@ static void keInit2(void) } else { - char test[512]; + unsigned char test[512]; int read = fsRead(testfile, test, 512, 1); kePrint("Read %d bytes.\n", read); if (read != -1) { + uint32_t i; + for (i = 0; i < 512; i++) + { + char buffer[3]; + snprintf(buffer, 3, "%02x", test[i]); + kePrint("%s", buffer); + } + kePrint("\n"); } kePrint("Closing test file.\n"); diff --git a/system/modules/cdi/dma.c b/system/modules/cdi/dma.c index 04be981..dce5ccf 100644 --- a/system/modules/cdi/dma.c +++ b/system/modules/cdi/dma.c @@ -21,29 +21,39 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include int cdi_dma_open(struct cdi_dma_handle* handle, uint8_t channel, uint8_t mode, size_t length, void* buffer) { - kePrint("cdi_dma_open: Stub!\n"); - return -1; + if (!handle) return -1; + if (keOpenDMA(channel, mode, buffer, length)) return -1; + // Save info in struct + handle->channel = channel; + handle->length = length; + handle->mode = mode; + handle->buffer = buffer; + return 0; } int cdi_dma_read(struct cdi_dma_handle* handle) { - kePrint("cdi_dma_read: Stub!\n"); - return -1; + if (!handle) return -1; + if (keReadDMA(handle->channel)) return -1; + return 0; } int cdi_dma_write(struct cdi_dma_handle* handle) { - kePrint("cdi_dma_write: Stub!\n"); - return -1; + if (!handle) return -1; + if (keWriteDMA(handle->channel)) return -1; + return 0; } int cdi_dma_close(struct cdi_dma_handle* handle) { - kePrint("cdi_dma_close: Stub!\n"); - return -1; + if (!handle) return -1; + if (keCloseDMA(handle->channel)) return -1; + return 0; } -- 2.11.4.GIT