a1ive/grub

Add Firadisk support

Closed this issue · 5 comments

Some WinPE ISOs and VHDs have the Firadisk driver installed.
A typical example is the Sergei Strelec WinPE ISOs.
https://sergeistrelec.ru/winpe-10-8-sergei-strelec-english/
These can be booted correctly using grub4dos. This string in memory can contain instructions - for instance what the path and name of the ISO file is that it should mount in WinPE as a drive.

In grub4dos, we just need to write the correct bytes into upper memory (so the bytes are still present after the boot.wim has loaded into RAM).

Here is a sample grub4dos menu - %ISOC% is the full path, %~pnx1 is the path+filename (no device):

#for BartPE/Hirens Boot CD 13.1/Strelec using  FiraDisk string in memory
# create small drive at top of memory (4 x 512 bytes)
map --mem --top (md)+4 (99) 
map %ISOC% (0xff) > nul || map --mem %ISOC% (0xff)
map --hook
root (0xff) || rootnoverify (0xff)
# write FiraDisk command string into memory
write (99) [FiraDisk]\nStartOptions=cdrom,vmem=find:%~pnx1;\n\0 > nul
chainloader (0xff)

Is there an equivalent in grub - maybe using dd?
If so, this would boot these ISOs properly (with all Desktop icons).
The code could also be added into grubfm File Manager when an ISO is booted to (it can do no harm if the ISO does not contain the FiraDisk driver).

a1ive commented

http://reboot.pro/topic/8804-firadisk-latest-00130/
info

value StartOptions type REG_SZ
data = list of drive description to create separated by semicolon.
Example: disk,vmem=find:\file1.img;cdrom,vmem=find:\file2.iso;floppy,vmem=c:\file3.img;disk,vmem=c:\file4.img,size=1052835840
There are 3 types of virtual drive : disk, cdrom, floppy
There are 3 main types of media/image :

file=path : File read/write.
vmem=path : Memory mapped file.
vmem without path : Allocate from virtual memory (RAM+pagefile).
Optional parameters

offset=number
size=number
heads=number
sectors-per-track=number
ro : read-only
boot : indicate that the virtual drive is required for booting Windows.
If file does not exist and size is specified, new file will be created.
If file exists but is smaller than offset+size, it will be extended.

Begin with [FiraDisk] (case insensitive)
followed by \n
then StartOptions=data\n
and end with \0.
Backslash is escape character in write command.
You can use / instead of \ in data field. When FiraDisk read this data, it will convert / to \ automatically.

a1ive commented

doesn't work ...
深度截图_选择区域_20200106110943
深度截图_选择区域_20200106111358

Looking at the source file driver.c. It seems to look at the BIOS Int 13h drive map for the string GRUB4DOS.
see FiraDiskDriverStartDetectRAMDrive in driver.c
So it seems that we must use the BIOS to map a BIOS Int 13h drive and see the string GRUB4DOS.
I did not realise it was so specific!

void FiraDiskDriverStartDetectRAMDrive (HANDLE hkFiraDisk, HANDLE hkData)
{
	NTSTATUS status;
	PHYSICAL_ADDRESS physaddr;
	SIZE_T viewsize;
	PCHAR physmem;
	physaddr.QuadPart = 0; viewsize = 0xA0000; // real-mode RAM range 0-640KB
	physmem = (PCHAR) MmMapIoSpace(physaddr, viewsize, MmCached);
	if (physmem) {
		WCHAR namebuffer[FIRADISKMAXKEYPATH];
		UNICODE_STRING usname = { 0, CCSIZEOF(namebuffer), namebuffer };
		ULONG ramdrivecount = 0;
		ULONG ramdrivenumber = 0;
		INTRVECT int13vector;
		PCHAR int13entry;
		UCHAR foundhandler = 0;
		FIRADISK_RAM_DRIVE_PARAMETERS ramdriveparam;
		RtlZeroMemory(&ramdriveparam, sizeof(ramdriveparam));
		DBGPrint0(("FiraDisk:  map real-mode memory success\n",physmem));
		//dumpmemory(physmem,0x20*4);
		for ( int13vector = ((PINTRVECT)(PVOID)(physmem))[0x13]
			; 
			(((UINT32)int13vector.segment << 4) + int13vector.offset) <= (0xA0000-27)
			; 
			int13vector = *((UNALIGNED INTRVECT *)(PVOID)(int13entry+3+8+8)) ) 
		{
			int13entry = physmem+(((UINT32)int13vector.segment << 4) + int13vector.offset);
			DBGPrint0(("FiraDisk:  int13=%04x:%04x\n",int13vector.segment,int13vector.offset));
			//dumpmemory(int13entry,0x20);
			if (!RtlEqualMemory(int13entry+3,"$INT13SF",8))
				break;
			if( !configDisableDetectGrub4dos && RtlEqualMemory(int13entry+3+8,"GRUB4DOS",8) )
				// version checking has not been implemented
				// support GRUB4DOS 0.4.4-0.4.5a
				// other version has not been tested
			{
				PGRUB4DOS_DRIVE_MAP_SLOT pdrvmap;
				ULONG i;
				DBGPrint0(("FiraDisk:  GRUB4DOS at %04x:%04x\n",int13vector.segment,int13vector.offset));
				foundhandler = 1;
				// drive map slot starts at offset 0x20 of the same segment as int13 entry
				pdrvmap = (PGRUB4DOS_DRIVE_MAP_SLOT)(physmem+(((UINT32)int13vector.segment << 4) + 0x20));
				RtlCopyMemory(&drive_map_table, pdrvmap, sizeof(drive_map_table));
				for (i=0
					; 
					i<GRUB4DOS_DRIVE_MAP_MAX
					&& ( ((PUINT32)pdrvmap)[0] || ((PUINT32)pdrvmap)[1] || ((PUINT32)pdrvmap)[2]
				      || ((PUINT32)pdrvmap)[3] || ((PUINT32)pdrvmap)[4] || ((PUINT32)pdrvmap)[5] )
					; 
					++i, ++pdrvmap)
				{
					UCHAR sclass; UCHAR sectorsizelog;
					sclass = (pdrvmap->from_cdrom)? FiraDiskSClassCDROM:
						(pdrvmap->from_drive >= 0x80)? FiraDiskSClassDisk:
							FiraDiskSClassFloppy;
					sectorsizelog = (pdrvmap->from_cdrom)? FiraDiskSectorSizeLogCDROM: FiraDiskSectorSizeLogDisk;
					if (pdrvmap->to_drive==0xFF && !pdrvmap->to_cdrom) // map mem drive
					{
						ULONG isoptiondrive = 0;
						RtlZeroMemory(&ramdriveparam,sizeof(ramdriveparam));
						ramdriveparam.sclass = sclass;
						ramdriveparam.address = pdrvmap->start_sector << GRUB4DOSMemSectorSizeLog;
						ramdriveparam.length  = pdrvmap->sector_count << GRUB4DOSMemSectorSizeLog;
						ramdriveparam.sectorsizelog = sectorsizelog;
						ramdriveparam.sectorpertrack = pdrvmap->max_sector;
						ramdriveparam.trackpercylinder = pdrvmap->max_head? pdrvmap->max_head+1: 0;
						if (sclass==FiraDiskSClassFloppy 
							&& ramdriveparam.length 
							&& ramdriveparam.length < (1UL<<20))
						{
							PHYSICAL_ADDRESS physaddr;
							PVOID pdata;
							physaddr.QuadPart = ramdriveparam.address;
							pdata = MmMapIoSpace(physaddr, (SIZE_T)ramdriveparam.length, MmCached);
							if (pdata)
							{
								ANSI_STRING as = { asFiraDiskSection.Length,asFiraDiskSection.Length, (PCHAR)pdata };
								if (RtlEqualString(&as,&asFiraDiskSection,TRUE))
								{ //[FIRADISK]
									isoptiondrive = 1;
									DBGPrint0(("FiraDisk:   Detected RAM options addr=0x%I64x len=%I64d\n",
										ramdriveparam.address, ramdriveparam.length));
									FiraDiskReadRAMOptions(pdata,(ULONG)ramdriveparam.length,hkData);
								}
								MmUnmapIoSpace(pdata, (SIZE_T)ramdriveparam.length);
							}
						}

I dont think firadisk can work with UEFI systems, so closing.