From: John Hodge Date: Sun, 11 Oct 2009 01:54:05 +0000 (+0800) Subject: Implemented basic disk write support in EXT2. X-Git-Tag: rel0.06~383 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=1ca0233bb1e142c536d09c35ce8dcdb209a2938b;p=tpg%2Facess2.git Implemented basic disk write support in EXT2. Fixed Debug_HexDump bug. Made changes to NE2000 driver (now triplefaults on write, instead of doing nothing --- diff --git a/Kernel/arch/x86/time.c b/Kernel/arch/x86/time.c index 9248bd12..adc2d133 100644 --- a/Kernel/arch/x86/time.c +++ b/Kernel/arch/x86/time.c @@ -51,7 +51,7 @@ int Time_Setup() outb(0x70, inb(0x70)|0x80); // Disable NMIs // Install IRQ Handler - IRQ_AddHandler(8, Time_Interrupt); + //IRQ_AddHandler(8, Time_Interrupt); return 0; } diff --git a/Kernel/debug.c b/Kernel/debug.c index bf2282ff..99a236ec 100644 --- a/Kernel/debug.c +++ b/Kernel/debug.c @@ -311,7 +311,7 @@ void Debug_HexDump(char *Header, void *Data, Uint Length) Uint byte = *cdat; LogF("%02x ", byte); Length--; - cdat --; + cdat ++; } E9('\n'); } diff --git a/Kernel/drv/ata_x86.c b/Kernel/drv/ata_x86.c index e64c65f9..540ba2f6 100644 --- a/Kernel/drv/ata_x86.c +++ b/Kernel/drv/ata_x86.c @@ -105,10 +105,12 @@ tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name); Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data); -// Disk Read +// Read/Write Interface/Quantiser Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk); +Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk); +// Read/Write DMA int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer); -// Disk Write + int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer); // IRQs void ATA_IRQHandlerPri(int unused); void ATA_IRQHandlerSec(int unused); @@ -326,7 +328,7 @@ int ATA_ScanDisk(int Disk) = node->CTime = now(); node->Read = ATA_ReadFS; - //node->Write = ATA_WriteFS; + node->Write = ATA_WriteFS; node->IOCtl = ATA_IOCtl; @@ -590,6 +592,7 @@ void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start Part->Node.ImplPtr = Part->Name; Part->Node.Read = ATA_ReadFS; + Part->Node.Write = ATA_WriteFS; Part->Node.IOCtl = ATA_IOCtl; LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node); LEAVE('-'); @@ -683,7 +686,30 @@ Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) */ Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) { - return 0; + int disk = Node->Inode >> 8; + int part = Node->Inode & 0xFF; + + // Raw Disk Access + if(part == 0xFF) + { + if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) + return 0; + if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE ) + Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset; + } + // Partition + else + { + if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) + return 0; + if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) + Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset; + Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE; + } + + Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer); + Debug_HexDump("ATA_WriteFS", Buffer, Length); + return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk); } /** @@ -735,6 +761,41 @@ Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk) return done+Count; } +/** + * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk) + */ +Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk) +{ + int ret; + Uint offset; + Uint done = 0; + + // Pass straight on to ATA_ReadDMAPage if we can + if(Count <= MAX_DMA_SECTORS) + { + ret = ATA_WriteDMA(Disk, Address, Count, Buffer); + if(ret == 0) return 0; + return Count; + } + + // Else we will have to break up the transfer + offset = 0; + while(Count > MAX_DMA_SECTORS) + { + ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset); + // Check for errors + if(ret != 1) return done; + // Change Position + done += MAX_DMA_SECTORS; + Count -= MAX_DMA_SECTORS; + offset += MAX_DMA_SECTORS*SECTOR_SIZE; + } + + ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset); + if(ret != 1) return 0; + return done+Count; +} + /** * \fn int ATA_ReadDMAPage(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) */ @@ -801,6 +862,72 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) return 1; } +/** + * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) + */ +int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) +{ + int cont = (Disk>>1)&1; // Controller ID + int disk = Disk & 1; + Uint16 base; + + // Check if the count is small enough + if(Count > MAX_DMA_SECTORS) return 0; + + // Get exclusive access to the disk controller + LOCK( &giaATA_ControllerLock[ cont ] ); + + // Set Size + gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE; + + // Get Port Base + base = ATA_GetBasePort(Disk); + + // Set up transfer + outb(base+0x01, 0x00); + if( Address > 0x0FFFFFFF ) // Use LBA48 + { + outb(base+0x6, 0x40 | (disk << 4)); + outb(base+0x2, 0 >> 8); // Upper Sector Count + outb(base+0x3, Address >> 24); // Low 2 Addr + outb(base+0x3, Address >> 28); // Mid 2 Addr + outb(base+0x3, Address >> 32); // High 2 Addr + } + else + { + outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr + } + + outb(base+0x02, (Uint8) Count); // Sector Count + outb(base+0x03, (Uint8) Address); // Low Addr + outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr + outb(base+0x05, (Uint8) (Address >> 16)); // High Addr + if( Address > 0x0FFFFFFF ) + outb(base+0x07, HDD_DMA_W48); // Write Command (LBA48) + else + outb(base+0x07, HDD_DMA_W28); // Write Command (LBA28) + + // Reset IRQ Flag + gaATA_IRQs[cont] = 0; + + // Copy to output buffer + memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE ); + + // Start transfer + ATA_int_BusMasterWriteByte( cont << 3, 1 ); // Write and start + + // Wait for transfer to complete + while( gaATA_IRQs[cont] == 0 ) Threads_Yield(); + + // Complete Transfer + ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop + + // Release controller lock + RELEASE( &giaATA_ControllerLock[ cont ] ); + + return 1; +} + /** * \fn void ATA_IRQHandlerPri(int unused) */ diff --git a/Kernel/drv/ne2000.c b/Kernel/drv/ne2000.c index c25718ac..6fdbe894 100644 --- a/Kernel/drv/ne2000.c +++ b/Kernel/drv/ne2000.c @@ -3,6 +3,7 @@ * * See: ~/Sources/bochs/bochs.../iodev/ne2k.cc */ +#define DEBUG 1 #include #include #include @@ -143,7 +144,7 @@ int Ne2k_Install(char **Options) outb( base + IMR, 0x00 ); outb( base + ISR, 0xFF ); outb( base + RCR, 0x20 ); // Reciever to Monitor - outb( base + TCR, 0x02 ); // Transmitter OFF + outb( base + TCR, 0x02 ); // Transmitter OFF (TCR.LB = 1, Internal Loopback) outb( base + RBCR0, 6*4 ); // Remote Byte Count outb( base + RBCR1, 0 ); outb( base + RSAR0, 0 ); // Clear Source Address @@ -164,7 +165,7 @@ int Ne2k_Install(char **Options) outb( base+ISR, 0xFF ); // Clear all ints outb( base+CMD, 0x22 ); // No DMA, Start outb( base+IMR, 0x3F ); // Set Interupt Mask - outb( base+RCR, 0x8F ); // Set WRAP and allow all packet matches + outb( base+RCR, 0x0F ); // Set WRAP and allow all packet matches outb( base+TCR, 0x00 ); // Set Normal Transmitter mode outb( base+TPSR, 0x40); // Set Transmit Start // Set MAC Address @@ -231,11 +232,19 @@ Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) Uint16 *buf = Buffer; int rem = Length; + ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); + // Sanity Check Length - if(Length > TX_BUF_SIZE) return 0; + if(Length > TX_BUF_SIZE) { + LEAVE('i', 0); + return 0; + } outb(Card->IOBase + CMD, 0|0x22); // Page 0, Start, NoDMA - // Send Size + // Send Size - Transmit Byte Count Register + outb(Card->IOBase + TBCR0, Length & 0xFF); + outb(Card->IOBase + TBCR1, Length >> 8); + // Send Size - Remote Byte Count Register outb(Card->IOBase + RBCR0, Length & 0xFF); outb(Card->IOBase + RBCR1, Length >> 8); // Clear Remote DMA Flag @@ -244,12 +253,17 @@ Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) outb(Card->IOBase + RSAR0, 0x00); // Page Offset outb(Card->IOBase + RSAR1, Ne2k_int_GetWritePage(Card, Length)); // Page Offset // Start - outb(Card->IOBase + CMD, 0|0x12); // Page 0, Start, DMA + outb(Card->IOBase + CMD, 0|0x18|0x4|0x2); // Page 0, Transmit Packet, TXP, Start // Send Data for(rem = Length; rem; rem -= 2) outw(Card->IOBase + 0x10, *buf++); - return 0; + + // Complete DMA + outb(Card->IOBase + CMD, 0|0x20); + + LEAVE('i', Length); + return Length; } /** diff --git a/Kernel/drvutil.c b/Kernel/drvutil.c index 281ee382..c40a5d24 100644 --- a/Kernel/drvutil.c +++ b/Kernel/drvutil.c @@ -130,7 +130,7 @@ Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, void *Buffer, // Read central blocks if(num) { - LOG("Reading %i blocks", num); + LOG("Writing %i blocks", num); ret = WriteBlocks(block, num, Buffer, Argument); if(ret != num ) { LEAVE('X', leading + ret * BlockSize); @@ -141,7 +141,7 @@ Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, void *Buffer, // Read last tailing block if(tailings != 0) { - LOG("Reading %i bytes from last block", tailings); + LOG("Writing %i bytes to last block", tailings); block += num; Buffer += num * BlockSize; // Read diff --git a/Kernel/vfs/fs/ext2.c b/Kernel/vfs/fs/ext2.c index 0c4b527b..da941f72 100644 --- a/Kernel/vfs/fs/ext2.c +++ b/Kernel/vfs/fs/ext2.c @@ -270,18 +270,25 @@ Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) Uint64 allocSize; int bNewBlocks = 0; + Debug_HexDump("Ext2_Write", Buffer, Length); + Ext2_int_GetInode(Node, &inode); - // Round size up to block size - // block size is a power of two, so this will work + // Get the ammount of space already allocated + // - Round size up to block size + // - block size is a power of two, so this will work allocSize = (inode.i_size + disk->BlockSize) & ~(disk->BlockSize-1); + + // Are we writing to inside the allocated space? if( Offset < allocSize ) { + // Will we go out of it? if(Offset + Length > allocSize) { bNewBlocks = 1; retLen = allocSize - Offset; } else retLen = Length; + // Within the allocated space block = Offset / disk->BlockSize; Offset %= disk->BlockSize; @@ -290,7 +297,7 @@ Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) // Write only block (if only one) if(Offset + retLen <= disk->BlockSize) { VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer); - if(bNewBlocks) return Length; + if(!bNewBlocks) return Length; goto addBlocks; // Ugh! A goto, but it seems unavoidable } @@ -313,7 +320,7 @@ Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) // Write last block base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); VFS_WriteAt(disk->FD, base, retLen, Buffer); - if(bNewBlocks) return Length; // Writing in only allocated space + if(!bNewBlocks) return Length; // Writing in only allocated space } addBlocks: diff --git a/Kernel/vfs/open.c b/Kernel/vfs/open.c index a1245f3b..50641ca3 100644 --- a/Kernel/vfs/open.c +++ b/Kernel/vfs/open.c @@ -365,7 +365,7 @@ tVFS_Node *VFS_ParsePath(char *Path, char **TruePath) // Check if file was found if(!tmpNode) { LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path); - Log("Child fail '%s' ('%s')", Path, &Path[ofs]); + //Log("Child fail '%s' ('%s')", Path, &Path[ofs]); if(TruePath) free(*TruePath); if(curNode->Close) curNode->Close(curNode); LEAVE('n');