Skip to content

Commit

Permalink
Fix multi-cluster allocation when writing using fatstream.
Browse files Browse the repository at this point in the history
  • Loading branch information
charlesbetros committed Apr 19, 2019
1 parent 169dc5e commit b9307ac
Show file tree
Hide file tree
Showing 18 changed files with 361 additions and 79 deletions.
3 changes: 3 additions & 0 deletions Tests/Cosmos.System.Tests/Cosmos.System.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="MSTest.TestAdapter" />
<PackageReference Include="MSTest.TestFramework" />
<PackageReference Include="NSubstitute" Version="4.0.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
</ItemGroup>

<ItemGroup>
Expand Down
49 changes: 49 additions & 0 deletions Tests/Cosmos.System.Tests/FatFileSystem_Should.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Text;
using Cosmos.HAL.BlockDevice;
using Cosmos.System.FileSystem;
using Cosmos.System.FileSystem.FAT;
using NUnit.Framework;

namespace Cosmos.System.Tests
{
public class FatFileSystem_Should
{
private FatFileSystem mFS;

[SetUp]
public void Setup()
{
var xDevice = new TestBlockDevice();
var xPartition = new Partition(xDevice, 0, xDevice.BlockCount);
var xFactory = new FatFileSystemFactory();
mFS = (FatFileSystem) xFactory.Create(xPartition, "0:\\", (long) (xPartition.BlockSize * xPartition.BlockCount));
}

[Test]
public void Load_Root_Directory_Entry()
{
var xRootDirectory = mFS.GetRootDirectory();
Assert.NotNull(xRootDirectory);
}

[Test]
public void Create_A_Directory_Entry()
{
string xNewDirectoryEntryName = "NEW";

var xRootDirectory = mFS.GetRootDirectory();
Assert.NotNull(xRootDirectory);

var xRootDirectoryListing = mFS.GetDirectoryListing(xRootDirectory);
Assert.AreEqual(xRootDirectoryListing.Count, 0);

mFS.CreateDirectory(xRootDirectory, xNewDirectoryEntryName);

xRootDirectoryListing = mFS.GetDirectoryListing(xRootDirectory);
Assert.AreEqual(xRootDirectoryListing.Count, 1);

var xNewDirectoryEntry = xRootDirectoryListing[0];
Assert.AreEqual(xNewDirectoryEntry.mName, xNewDirectoryEntryName);
}
}
}
49 changes: 49 additions & 0 deletions Tests/Cosmos.System.Tests/Fat_Should.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Cosmos.HAL.BlockDevice;
using Cosmos.System.FileSystem;
using Cosmos.System.FileSystem.FAT;
using NUnit.Framework;

namespace Cosmos.System.Tests
{
public class Fat_Should
{
private FatFileSystem mFS;
private FatFileSystem.Fat mFat;

[SetUp]
public void Setup()
{
var xDevice = new TestBlockDevice();
var xPartition = new Partition(xDevice, 0, xDevice.BlockCount);
var xFactory = new FatFileSystemFactory();
mFS = (FatFileSystem)xFactory.Create(xPartition, "0:\\", (long)(xPartition.BlockSize * xPartition.BlockCount));
mFat = mFS.GetFat(0);
}

[Test]
public void Add_New_Clusters_To_Chain_When_Needed()
{
uint xStartCluster = mFS.RootCluster;
mFat.SetFatEntry(xStartCluster, mFat.FatEntryEofValue());
mFat.SetFatEntry(xStartCluster + 2, mFat.FatEntryEofValue());
mFat.SetFatEntry(xStartCluster + 5, mFat.FatEntryEofValue());

uint[] xChain = mFat.GetFatChain(xStartCluster, mFS.BytesPerCluster);
Assert.AreEqual(xChain.Length, 1);

xChain = mFat.GetFatChain(xStartCluster, mFS.BytesPerCluster * 3);
Assert.AreEqual(3, xChain.Length);
Assert.AreEqual(2, xChain[0]);
Assert.AreEqual(3, xChain[1]);
Assert.AreEqual(5, xChain[2]);

xChain = mFat.GetFatChain(xStartCluster, mFS.BytesPerCluster * 5);
Assert.AreEqual(5, xChain.Length);
Assert.AreEqual(2, xChain[0]);
Assert.AreEqual(3, xChain[1]);
Assert.AreEqual(5, xChain[2]);
Assert.AreEqual(6, xChain[3]);
Assert.AreEqual(8, xChain[4]);
}
}
}
69 changes: 69 additions & 0 deletions Tests/Cosmos.System.Tests/TestBlockDevice.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.IO;
using Cosmos.HAL.BlockDevice;

namespace Cosmos.System.Tests
{
class TestBlockDevice : BlockDevice
{
private byte[] mData;

public TestBlockDevice()
{
LoadTestData();

mBlockSize = 512;
mBlockCount = (ulong) (mData.Length / (int) mBlockSize);
}

private void LoadTestData()
{
var xList = new List<byte>();

using (var xReader = new StreamReader("../../../../Data/disk.txt"))
{
while (!xReader.EndOfStream)
{
string xLine = xReader.ReadLine();
if (!string.IsNullOrWhiteSpace(xLine))
{
xLine = xLine.Replace(" ", "");
xList.AddRange(StringToByteArray(xLine));
}
}
xReader.Close();
}

for (int i = 0; i < 534610432 - xList.Count; i++)
{
xList.Add(0x00);
}

mData = xList.ToArray();
}

private static byte[] StringToByteArray(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}

return bytes;
}

public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, ref byte[] aData)
{
aData = NewBlockArray((uint) aBlockCount);
Array.Copy(mData, (long) (aBlockNo * BlockSize), aData, 0, (long) (aBlockCount * BlockSize));
}

public override void WriteBlock(ulong aBlockNo, ulong aBlockCount, ref byte[] aData)
{
Array.Copy(aData, 0, mData, (long)(aBlockNo * BlockSize), (long)(aBlockCount * BlockSize));
}
}
}
14 changes: 14 additions & 0 deletions Tests/Cosmos.TestRunner.TestController/Assert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,19 @@ public static void AreEqual(int expected, int actual, string message, [CallerFil
}
IsTrue(xResult, message, file, line);
}

public static void AreEqual(string expected, string actual, string message, [CallerFilePath] string file = null, [CallerLineNumber] int line = 0)
{
var xResult = expected == actual;
if (!xResult)
{
TestController.Debugger.Send("Expected value");
TestController.Debugger.Send(expected);
TestController.Debugger.Send("Actual value");
TestController.Debugger.Send(actual);
}
IsTrue(xResult, message, file, line);
}

}
}
32 changes: 32 additions & 0 deletions Tests/Data/disk.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
EB 58 90 4D 53 44 4F 53 35 2E 30 00 02 08 18 18
02 00 00 00 00 F8 00 00 3F 00 10 00 3F 00 00 00
C2 EE 0F 00 F4 03 00 00 00 00 00 00 02 00 00 00
01 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00
80 00 29 79 5D 0F 04 4E 4F 20 4E 41 4D 45 20 20
20 20 46 41 54 33 32 20 20 20 33 C9 8E D1 BC F4
7B 8E C1 8E D9 BD 00 7C 88 4E 02 8A 56 40 B4 41
BB AA 55 CD 13 72 10 81 FB 55 AA 75 0A F6 C1 01
74 05 FE 46 02 EB 2D 8A 56 40 B4 08 CD 13 73 05
B9 FF FF 8A F1 66 0F B6 C6 40 66 0F B6 D1 80 E2
3F F7 E2 86 CD C0 ED 06 41 66 0F B7 C9 66 F7 E1
66 89 46 F8 83 7E 16 00 75 38 83 7E 2A 00 77 32
66 8B 46 1C 66 83 C0 0C BB 00 80 B9 01 00 E8 2B
00 E9 2C 03 A0 FA 7D B4 7D 8B F0 AC 84 C0 74 17
3C FF 74 09 B4 0E BB 07 00 CD 10 EB EE A0 FB 7D
EB E5 A0 F9 7D EB E0 98 CD 16 CD 19 66 60 80 7E
02 00 0F 84 20 00 66 6A 00 66 50 06 53 66 68 10
00 01 00 B4 42 8A 56 40 8B F4 CD 13 66 58 66 58
66 58 66 58 EB 33 66 3B 46 F8 72 03 F9 EB 2A 66
33 D2 66 0F B7 4E 18 66 F7 F1 FE C2 8A CA 66 8B
D0 66 C1 EA 10 F7 76 1A 86 D6 8A 56 40 8A E8 C0
E4 06 0A CC B8 01 02 CD 13 66 61 0F 82 75 FF 81
C3 00 02 66 40 49 75 94 C3 42 4F 4F 54 4D 47 52
20 20 20 20 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 0D 0A 52 65
6D 6F 76 65 20 64 69 73 6B 73 20 6F 72 20 6F 74
68 65 72 20 6D 65 64 69 61 2E FF 0D 0A 44 69 73
6B 20 65 72 72 6F 72 FF 0D 0A 50 72 65 73 73 20
61 6E 79 20 6B 65 79 20 74 6F 20 72 65 73 74 61
72 74 0D 0A 00 00 00 00 00 AC CB D8 00 00 55 AA
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static void Execute(Debugger mDebugger)
var xDirs = xDi.GetDirectories();
Assert.IsTrue(xDirs != null, "GetDirectories() failed it returns null array");
Assert.IsTrue(xDirs.Length != 0, "GetDirectories() failed it returns empty array");
Assert.IsTrue(xDirs[0].FullName == xSubDi.FullName, "GetDirectories() does not return the expected directories");
Assert.AreEqual(xDirs[0].FullName, xSubDi.FullName, "GetDirectories() failed");
mDebugger.Send("END TEST");
mDebugger.Send("");

Expand Down
4 changes: 2 additions & 2 deletions source/Cosmos.HAL2/BlockDevice/AHCI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ public AHCI(PCIDevice aAHCIDevice)
{
mAHCIDebugger.Send($"{xPort.mPortName} Port 0:{xPort.mPortNumber}");
var xMBRData = new byte[512];
xPort.ReadBlock(0UL, 1U, xMBRData);
xPort.ReadBlock(0UL, 1U, ref xMBRData);
var xMBR = new MBR(xMBRData);

if (xMBR.EBRLocation != 0)
{
// EBR Detected!
mAHCIDebugger.Send("EBR Detected within MBR code");
var xEBRData = new byte[512];
xPort.ReadBlock(xMBR.EBRLocation, 1U, xEBRData);
xPort.ReadBlock(xMBR.EBRLocation, 1U, ref xEBRData);
var xEBR = new EBR(xEBRData);
for (int i = 0; i < xEBR.Partitions.Count; i++)
{
Expand Down
4 changes: 2 additions & 2 deletions source/Cosmos.HAL2/BlockDevice/AtaPio.cs
Original file line number Diff line number Diff line change
Expand Up @@ -342,15 +342,15 @@ protected void SelectSector(UInt64 aSectorNo, UInt64 aSectorCount)
//TODO LBA3 ...
}

public override void ReadBlock(UInt64 aBlockNo, UInt64 aBlockCount, byte[] aData)
public override void ReadBlock(UInt64 aBlockNo, UInt64 aBlockCount, ref byte[] aData)
{
CheckDataSize(aData, aBlockCount);
SelectSector(aBlockNo, aBlockCount);
SendCmd(LBA48Bit ? Cmd.ReadPioExt : Cmd.ReadPio);
IO.Data.Read8(aData);
}

public override void WriteBlock(UInt64 aBlockNo, UInt64 aBlockCount, byte[] aData)
public override void WriteBlock(UInt64 aBlockNo, UInt64 aBlockCount, ref byte[] aData)
{
CheckDataSize(aData, aBlockCount);
SelectSector(aBlockNo, aBlockCount);
Expand Down
4 changes: 2 additions & 2 deletions source/Cosmos.HAL2/BlockDevice/BlockDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public byte[] NewBlockArray(UInt32 aBlockCount)
// Only allow reading and writing whole blocks because many of the hardware
// command work that way and we dont want to add complexity at the BlockDevice level.
// public abstract void ReadBlock(UInt64 aBlockNo, UInt32 aBlockCount, byte[] aData);
public abstract void ReadBlock(UInt64 aBlockNo, UInt64 aBlockCount, byte[] aData);
public abstract void WriteBlock(UInt64 aBlockNo, UInt64 aBlockCount, byte[] aData);
public abstract void ReadBlock(UInt64 aBlockNo, UInt64 aBlockCount, ref byte[] aData);
public abstract void WriteBlock(UInt64 aBlockNo, UInt64 aBlockCount, ref byte[] aData);

protected void CheckDataSize(byte[] aData, UInt64 aBlockCount)
{
Expand Down
4 changes: 2 additions & 2 deletions source/Cosmos.HAL2/BlockDevice/IDE.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ private static void Initialize(Ata.ControllerIdEnum aControllerID, Ata.BusPositi
return;
}
var xMbrData = new byte[512];
xATA.ReadBlock(0UL, 1U, xMbrData);
xATA.ReadBlock(0UL, 1U, ref xMbrData);
var xMBR = new MBR(xMbrData);

if (xMBR.EBRLocation != 0)
{
//EBR Detected
var xEbrData = new byte[512];
xATA.ReadBlock(xMBR.EBRLocation, 1U, xEbrData);
xATA.ReadBlock(xMBR.EBRLocation, 1U, ref xEbrData);
var xEBR = new EBR(xEbrData);

for (int i = 0; i < xEBR.Partitions.Count; i++)
Expand Down
8 changes: 4 additions & 4 deletions source/Cosmos.HAL2/BlockDevice/Partition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ public Partition(BlockDevice aHost, UInt64 aStartingSector, UInt64 aSectorCount)
mBlockSize = aHost.BlockSize;
}

public override void ReadBlock(UInt64 aBlockNo, UInt64 aBlockCount, byte[] aData)
public override void ReadBlock(UInt64 aBlockNo, UInt64 aBlockCount, ref byte[] aData)
{
CheckDataSize(aData, aBlockCount);
UInt64 xHostBlockNo = mStartingSector + aBlockNo;
CheckBlockNo(xHostBlockNo, aBlockCount);
mHost.ReadBlock(xHostBlockNo, aBlockCount, aData);
mHost.ReadBlock(xHostBlockNo, aBlockCount, ref aData);
}

public override void WriteBlock(UInt64 aBlockNo, UInt64 aBlockCount, byte[] aData)
public override void WriteBlock(UInt64 aBlockNo, UInt64 aBlockCount,ref byte[] aData)
{
CheckDataSize(aData, aBlockCount);
UInt64 xHostBlockNo = mStartingSector + aBlockNo;
CheckBlockNo(xHostBlockNo, aBlockCount);
mHost.WriteBlock(xHostBlockNo, aBlockCount, aData);
mHost.WriteBlock(xHostBlockNo, aBlockCount, ref aData);
}

public override string ToString()
Expand Down
4 changes: 2 additions & 2 deletions source/Cosmos.HAL2/BlockDevice/Ports/Sata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -350,15 +350,15 @@ protected string GetString(UInt16[] aBuffer, int aIndexStart, int aStringLength)
}

// BlockDevice Methods
public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, ref byte[] aData)
{
//CheckDataSize(aData, aBlockCount);
//CheckBlockNo(aBlockNo, aBlockCount);
SendSATA48Command(ATACommands.ReadDmaExt, (uint)aBlockNo, (uint)aBlockCount);
Mem.DataBlock.Read8(aData);
}

public override void WriteBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
public override void WriteBlock(ulong aBlockNo, ulong aBlockCount, ref byte[] aData)
{
Mem.DataBlock.Write8(aData);
SendSATA48Command(ATACommands.WriteDmaExt, (uint)(aBlockNo), (uint)aBlockCount);
Expand Down
4 changes: 2 additions & 2 deletions source/Cosmos.HAL2/BlockDevice/Ports/Satapi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public int FindCMDSlot(PortRegisters aPort)
return -1;
}

public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, ref byte[] aData)
{
SendSATAPICommand(ATACommands.Read, (uint)aBlockNo, (uint)aBlockCount);
byte[] xByte = new byte[512];
Expand All @@ -140,7 +140,7 @@ public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
}
}

public override void WriteBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
public override void WriteBlock(ulong aBlockNo, ulong aBlockCount, ref byte[] aData)
{
// To be implemented!
}
Expand Down
Loading

0 comments on commit b9307ac

Please sign in to comment.