Skip to content

Commit

Permalink
Add WIP GPT generation code (#1040)
Browse files Browse the repository at this point in the history
  • Loading branch information
AnErrupTion committed May 13, 2023
1 parent 956bd4f commit 602d162
Show file tree
Hide file tree
Showing 13 changed files with 252 additions and 139 deletions.
91 changes: 0 additions & 91 deletions Source/Mosa.DeviceSystem/GUIDPartitionTable.cs

This file was deleted.

6 changes: 6 additions & 0 deletions Source/Mosa.Tool.Launcher/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@
<Label FontSize="14" Name="qemuPathLbl" Margin="165, -23, 0, 0">No path specified</Label>
<Label FontSize="14">QEMU BIOS Directory:</Label>
<Label FontSize="14" Name="qemuBiosPathLbl" Margin="165, -23, 0, 0">No path specified</Label>
<Label FontSize="14">QEMU EDK2 x86:</Label>
<Label FontSize="14" Name="qemuEdk2X86PathLbl" Margin="165, -23, 0, 0">No path specified</Label>
<Label FontSize="14">QEMU EDK2 x64:</Label>
<Label FontSize="14" Name="qemuEdk2X64PathLbl" Margin="165, -23, 0, 0">No path specified</Label>
<Label FontSize="14">QEMU EDK2 ARM:</Label>
<Label FontSize="14" Name="qemuEdk2ARMPathLbl" Margin="165, -23, 0, 0">No path specified</Label>
<Label FontSize="14">QEMU Image:</Label>
<Label FontSize="14" Name="qemuImgPathLbl" Margin="165, -23, 0, 0">No path specified</Label>
<Label FontSize="14">Bochs:</Label>
Expand Down
3 changes: 3 additions & 0 deletions Source/Mosa.Tool.Launcher/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ private void UpdateInterfaceAppLocations()
ndiasmPathLbl.Content = settings.GetValue("AppLocation.Ndisasm", "N/A");
qemuPathLbl.Content = settings.GetValue("AppLocation.Qemu", "N/A");
qemuBiosPathLbl.Content = settings.GetValue("AppLocation.QemuBIOS", "N/A");
qemuEdk2X86PathLbl.Content = settings.GetValue("AppLocation.QemuEDK2X86", "N/A");
qemuEdk2X64PathLbl.Content = settings.GetValue("AppLocation.QemuEDK2X64", "N/A");
qemuEdk2ARMPathLbl.Content = settings.GetValue("AppLocation.QemuEDK2ARM", "N/A");
qemuImgPathLbl.Content = settings.GetValue("AppLocation.QemuImg", "N/A");
vboxPathLbl.Content = settings.GetValue("AppLocation.VirtualBox", "N/A");
mkisofsPathLbl.Content = settings.GetValue("AppLocation.Mkisofs", "N/A");
Expand Down
11 changes: 0 additions & 11 deletions Source/Mosa.Utility.BootImage/BootImageOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,15 @@

namespace Mosa.Utility.BootImage;

/// <summary>
///
/// </summary>
public class BootImageOptions
{
public Guid MediaGuid = Guid.NewGuid();
public Guid MediaLastSnapGuid = Guid.NewGuid();
public byte[] MBRCode = null;
public byte[] FatBootCode = null;
public string VolumeLabel = string.Empty;
public ImageFirmware ImageFirmware = ImageFirmware.Bios;
public ImageFormat ImageFormat = ImageFormat.IMG;
public bool MBROption = true;
public uint BlockCount = 0;
public FileSystem FileSystem = FileSystem.FAT12;
public List<IncludeFile> IncludeFiles = new List<IncludeFile>();

public string DiskImageFileName = null;

public BootImageOptions()
{
}
}
84 changes: 53 additions & 31 deletions Source/Mosa.Utility.BootImage/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,52 +75,74 @@ public static void Create(BootImageOptions options)
var partitionDevice = new PartitionDeviceDriver();

// Setup partition configuration
var configuraiton = new DiskPartitionConfiguration
var configuration = new DiskPartitionConfiguration
{
Index = 0,
ReadOnly = false,
};

if (options.MBROption)
if (options.ImageFirmware == ImageFirmware.Bios)
{
// Create master boot block record
var mbr = new MasterBootBlock(diskDeviceDriver)
{
// Setup partition entry
DiskSignature = 0x12345678
DiskSignature = 0x12345678,
Code = null
};

mbr.Partitions[0].Bootable = true;
mbr.Partitions[0].StartLBA = 2048; // minimum for grub legacy = 64, grub2 = 2048 (1Mb)
mbr.Partitions[0].StartLBA = 2048;
mbr.Partitions[0].TotalBlocks = blockCount - mbr.Partitions[0].StartLBA;
mbr.Partitions[0].PartitionType = options.FileSystem switch

Check warning on line 97 in Source/Mosa.Utility.BootImage/Generator.cs

View workflow job for this annotation

GitHub Actions / Windows Build

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Mosa.Utility.BootImage.FileSystem)3' is not covered.

Check warning on line 97 in Source/Mosa.Utility.BootImage/Generator.cs

View workflow job for this annotation

GitHub Actions / Linux Build

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Mosa.Utility.BootImage.FileSystem)3' is not covered.
{
FileSystem.FAT12 => PartitionType.FAT12,
FileSystem.FAT16 => PartitionType.FAT16,
FileSystem.FAT32 => PartitionType.FAT32
};

mbr.Write();

switch (options.FileSystem)
configuration.StartLBA = mbr.Partitions[0].StartLBA;
configuration.TotalBlocks = mbr.Partitions[0].TotalBlocks;
}
else if (options.ImageFirmware == ImageFirmware.Uefi)
{
// Create protective MBR
var mbr = new MasterBootBlock(diskDeviceDriver)
{
case FileSystem.FAT12: mbr.Partitions[0].PartitionType = PartitionType.FAT12; break;
case FileSystem.FAT16: mbr.Partitions[0].PartitionType = PartitionType.FAT16; break;
case FileSystem.FAT32: mbr.Partitions[0].PartitionType = PartitionType.FAT32; break;
default: break;
}
// Setup partition entry
DiskSignature = 0x12345678,
Code = null
};

mbr.Code = options.MBRCode;
mbr.Partitions[0].Bootable = false;
mbr.Partitions[0].StartLBA = 1;
mbr.Partitions[0].TotalBlocks = blockCount - mbr.Partitions[0].StartLBA;
mbr.Partitions[0].PartitionType = 0xEE; // GPT protective MBR ID

mbr.Write();

configuraiton.StartLBA = mbr.Partitions[0].StartLBA;
configuraiton.TotalBlocks = mbr.Partitions[0].TotalBlocks;
// Create GUID partition table
var gpt = new GuidPartitionTable(diskDeviceDriver);

gpt.Write();

configuration.StartLBA = 3;
configuration.TotalBlocks = blockCount - configuration.StartLBA;
}
else
{
configuraiton.StartLBA = 0;
configuraiton.TotalBlocks = diskDeviceDriver.TotalBlocks;
configuration.StartLBA = 0;
configuration.TotalBlocks = diskDeviceDriver.TotalBlocks;
}

// Setup device -- required as part of framework in operating system
var device = new Device
{
Configuration = configuraiton,
Configuration = configuration,
DeviceDriver = partitionDevice,
Parent = diskDevice,
Parent = diskDevice
};

// Setup and initialize
Expand All @@ -129,22 +151,22 @@ public static void Create(BootImageOptions options)
partitionDevice.Start();

// Set FAT settings
var fatSettings = new FatSettings();

fatSettings.FATType = options.FileSystem switch
var fatSettings = new FatSettings
{
FileSystem.FAT12 => FatType.FAT12,
FileSystem.FAT16 => FatType.FAT16,
FileSystem.FAT32 => FatType.FAT32,
_ => fatSettings.FATType
FATType = options.FileSystem switch

Check warning on line 156 in Source/Mosa.Utility.BootImage/Generator.cs

View workflow job for this annotation

GitHub Actions / Windows Build

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Mosa.Utility.BootImage.FileSystem)3' is not covered.

Check warning on line 156 in Source/Mosa.Utility.BootImage/Generator.cs

View workflow job for this annotation

GitHub Actions / Linux Build

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Mosa.Utility.BootImage.FileSystem)3' is not covered.
{
FileSystem.FAT12 => FatType.FAT12,
FileSystem.FAT16 => FatType.FAT16,
FileSystem.FAT32 => FatType.FAT32
},
FloppyMedia = false,
VolumeLabel = options.VolumeLabel,
SerialID = new byte[] { 0x01, 0x02, 0x03, 0x04 },
SectorsPerTrack = diskGeometry.SectorsPerTrack,
NumberOfHeads = diskGeometry.Heads,
HiddenSectors = diskGeometry.SectorsPerTrack,
OSBootCode = null
};
fatSettings.FloppyMedia = false;
fatSettings.VolumeLabel = options.VolumeLabel;
fatSettings.SerialID = new byte[] { 0x01, 0x02, 0x03, 0x04 };
fatSettings.SectorsPerTrack = diskGeometry.SectorsPerTrack;
fatSettings.NumberOfHeads = diskGeometry.Heads;
fatSettings.HiddenSectors = diskGeometry.SectorsPerTrack;
fatSettings.OSBootCode = options.FatBootCode;

// Create FAT file system
var fat = new FatFileSystem(partitionDevice);
Expand Down
84 changes: 84 additions & 0 deletions Source/Mosa.Utility.BootImage/GuidPartitionTable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) MOSA Project. Licensed under the New BSD License.

using System;
using System.IO.Hashing;
using System.Text;
using Mosa.DeviceSystem;

namespace Mosa.Utility.BootImage;

//https://en.wikipedia.org/wiki/GUID_Partition_Table
public class GuidPartitionTable
{
private const uint HeaderSize = 0x5C; // 92 bytes
private const uint PartitionEntrySize = 0x80; // 128 bytes

private readonly IDiskDevice diskDevice;

private static readonly byte[] Signature = { 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54 }; // "EFI PART"
private static readonly byte[] Revision = { 0x00, 0x00, 0x01, 0x00 }; // Revision 1.0 (UEFI 2.8)

public GuidPartitionTable(IDiskDevice diskDevice)
{
this.diskDevice = diskDevice;
}

public void Write()
{
var tableHeaderLba = 1U;
var partitionEntriesLba = 2U;
var backupTableHeaderLba = diskDevice.TotalBlocks - 1; // Last LBA
var backupPartitionEntriesLba = diskDevice.TotalBlocks - 2;

// EFI System Partition
var efiSystemPartition = new DataBlock(diskDevice.BlockSize);
efiSystemPartition.SetBytes(0, Guid.Parse("C12A7328-F81F-11D2-BA4B-00A0C93EC93B").ToByteArray());
efiSystemPartition.SetBytes(16, Guid.NewGuid().ToByteArray());
efiSystemPartition.SetULong(32, partitionEntriesLba + 1);
efiSystemPartition.SetULong(40, backupPartitionEntriesLba - 1);
efiSystemPartition.SetULong(48, 0b0000000000000000000000000000000000000000000000000000000000000000);
efiSystemPartition.SetBytes(56, Encoding.Unicode.GetBytes("MOSA-PROJECT-POWERED-BY-DO"));

var partitionEntries = new DataBlock[1];
partitionEntries[0] = efiSystemPartition;

var partitionEntriesCrc32 = Crc32.Hash(efiSystemPartition.Data[..128]);

// Partition table header
var partitionTableHeader = new DataBlock(diskDevice.BlockSize);
partitionTableHeader.SetBytes(0, Signature);
partitionTableHeader.SetBytes(8, Revision);
partitionTableHeader.SetUInt32(12, HeaderSize);
partitionTableHeader.SetUInt32(16, 0); // CRC32 checksum, zeroed during calculation
partitionTableHeader.SetUInt32(20, 0); // Reserved
partitionTableHeader.SetULong(24, tableHeaderLba);
partitionTableHeader.SetULong(32, backupTableHeaderLba);
partitionTableHeader.SetULong(40, (uint)(partitionEntriesLba + partitionEntries.Length + 1)); // First usable LBA
partitionTableHeader.SetULong(48, (uint)(backupPartitionEntriesLba - partitionEntries.Length - 1)); // Last usable LBA
partitionTableHeader.SetBytes(56, Guid.NewGuid().ToByteArray()); // Disk GUID
partitionTableHeader.SetULong(72, partitionEntriesLba);
partitionTableHeader.SetUInt32(80, (uint)partitionEntries.Length);
partitionTableHeader.SetUInt32(84, PartitionEntrySize);
partitionTableHeader.SetBytes(88, partitionEntriesCrc32); // CRC32 checksum of partition entries array

var tableHeaderCrc32 = Crc32.Hash(partitionTableHeader.Data[..0x5C]);
partitionTableHeader.SetBytes(16, tableHeaderCrc32);

for (uint offset = 92; offset < partitionTableHeader.Length; offset++)
partitionTableHeader.SetByte(offset, 0);

// Main table header
diskDevice.WriteBlock(tableHeaderLba, 1, partitionTableHeader.Data);

// Main entries
for (uint i = 0; i < partitionEntries.Length; i++)
diskDevice.WriteBlock(partitionEntriesLba + i, 1, partitionEntries[i].Data);

// Backup entries
for (uint i = 0; i < partitionEntries.Length; i++)
diskDevice.WriteBlock(backupPartitionEntriesLba + i, 1, partitionEntries[i].Data);

// Backup table header
diskDevice.WriteBlock(backupTableHeaderLba, 1, partitionTableHeader.Data);
}
}
3 changes: 2 additions & 1 deletion Source/Mosa.Utility.BootImage/ImageFirmware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ namespace Mosa.Utility.BootImage;

public enum ImageFirmware
{
Bios
Bios,
Uefi
}
7 changes: 5 additions & 2 deletions Source/Mosa.Utility.BootImage/Mosa.Utility.BootImage.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<AssemblyTitle>Mosa.Utility.BootImage</AssemblyTitle>
Expand All @@ -17,4 +17,7 @@
<ProjectReference Include="..\Mosa.Compiler.Common\Mosa.Compiler.Common.csproj" />
<ProjectReference Include="..\Mosa.Utility.FileSystem\Mosa.Utility.FileSystem.csproj" />
</ItemGroup>
</Project>
<ItemGroup>
<PackageReference Include="System.IO.Hashing" Version="7.0.0" />
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions Source/Mosa.Utility.Configuration/CommandLineArguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ private static List<Argument> GetMap()
new Argument { Name = "-include", Setting = "Image.FileSystem.RootInclude" },

new Argument { Name = "-bios", Setting = "Image.Firmware", Value="bios"},
new Argument { Name = "-uefi", Setting = "Image.Firmware", Value="uefi"},
new Argument { Name = "-firmware", Setting = "Image.Firmware"},

// Advance:
Expand Down

0 comments on commit 602d162

Please sign in to comment.