Then you need to do programmed read on Flash device,
I m not sure which Flash Device you are using, you can download the spec
and use see what registers and commands are used for programmed read.
Once you do this you will see the exact data written on Device.
SMBIOS wont give you the base pointers to BIOS CODE, so I don’t think
its much of your use. What I meant was you map the physical memory in
your application ( using a sample driver or I am not sure if you can use
MapViewofSection . and do a pointer read on virtual memory, you should
get the actual data written on flash .
Thanks & Regards
~ Neeraj
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Darmawan Salihun
Sent: Wednesday, July 11, 2007 4:10 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Reading system BIOS?
Hi,
Mark McDougall wrote:
Mark McDougall wrote:
> Thanks for your response, but I need to read every single byte in the
BIOS
> flash device to calculate a checksum - not just SMBIOS information -
from
> WinXP (I already have SMBIOS dumping code).
>
I’ve managed to read what I believe is the entire BIOS code from
system
memory (via pointers from SMBIOS) but it’s no good to me because it’s
the
uncompressed run-time image.
I need to read directly from the LPC flash device.
Regards,
My previous email attachment is rejected. So, I’ll just post the
relevant driver code inline:
— file bios_probe.h ----
#define BIOS_PROBE_DEVICE_NAME_U L"\Device\bios_probe"
#define BIOS_PROBE_DOS_DEVICE_NAME_U L"\DosDevices\bios_probe"
typedef struct _MMIO_RING_0_MAP{
PVOID sysAddrBase; // the starting system virtual address of
the mapped physical address range
ULONG size; // size of the mapped physical address range
PVOID usermodeAddrBase; // pointer to the usermode virtual address
where this range is mapped
PMDL pMdl; // Memory Descriptor List for the memory
mapped I/O range to be mapped
}MMIO_RING_0_MAP, *PMMIO_RING_0_MAP;
typedef struct _DEVICE_EXTENSION{
MMIO_RING_0_MAP mapZone[MAX_MAPPED_MMIO];
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING registryPath
);
…
NTSTATUS
DispatchIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
---- file bios_probe.c
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
registryPath - pointer to a unicode string representing the path,
to driver-specific key in the registry.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
–*/
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING unicodeDeviceName;
UNICODE_STRING unicodeDosDeviceName;
PDEVICE_OBJECT deviceObject;
PDEVICE_EXTENSION pDevExt;
ULONG i;
UNREFERENCED_PARAMETER (RegistryPath);
BIOS_PROBE_KDPRINT((“DriverEntry Enter \n”));
DriverObject->DriverUnload = DispatchUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE]= DispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
DispatchIoControl;
(void) RtlInitUnicodeString(&unicodeDeviceName,
BIOS_PROBE_DEVICE_NAME_U);
status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),
&unicodeDeviceName,
FILE_DEVICE_UNKNOWN,
0,
(BOOLEAN) FALSE,
&deviceObject
);
if (!NT_SUCCESS(status))
{
return status;
}
DbgPrint(“DeviceObject %p\n”, deviceObject);
//
// Set the flag signifying that we will do direct I/O. This causes
NT
// to lock the user buffer into memory when it’s accessed
//
deviceObject->Flags |= DO_DIRECT_IO;
//
// Allocate and initialize a Unicode String containing the Win32
name
// for our device.
//
(void)RtlInitUnicodeString( &unicodeDosDeviceName,
BIOS_PROBE_DOS_DEVICE_NAME_U );
status = IoCreateSymbolicLink( (PUNICODE_STRING)
&unicodeDosDeviceName,
(PUNICODE_STRING) &unicodeDeviceName );
if (!NT_SUCCESS(status))
{
IoDeleteDevice(deviceObject);
return status;
}
//
// Initialize device extension
//
pDevExt = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
for(i = 0; i < MAX_MAPPED_MMIO; i++)
{
pDevExt->mapZone[i].sysAddrBase = NULL;
pDevExt->mapZone[i].size = 0;
pDevExt->mapZone[i].usermodeAddrBase = NULL;
pDevExt->mapZone[i].pMdl = NULL;
}
BIOS_PROBE_KDPRINT((“DriverEntry Exit = %x\n”, status));
return status;
}
NTSTATUS
DispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the create IRPs sent to this device.
This routine does nothing but signalling
successful IRP handling.
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet.
Return Value:
NT Status code
–*/
{
NTSTATUS status = STATUS_SUCCESS;
BIOS_PROBE_KDPRINT((“DispatchCreate Enter\n”));
//
// The dispatch routine for IRP_MJ_CREATE is called when a
// file object associated with the device is created.
// This is typically because of a call to CreateFile() in
// a user-mode program or because a another driver is
// layering itself over a this driver. A driver is
// required to supply a dispatch routine for IRP_MJ_CREATE.
//
BIOS_PROBE_KDPRINT((“IRP_MJ_CREATE\n”));
Irp->IoStatus.Information = 0;
//
// Save Status for return and complete Irp
//
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
BIOS_PROBE_KDPRINT((" DispatchCreate Exit = %x\n", status));
return status;
}
NTSTATUS MapMmio(PDEVICE_OBJECT pDO, PIRP pIrp)
/*++
Routine Description:
Process the IRPs with IOCTL_MAP_MMIO code.
This routine maps a physical address range
to the usermode application address space.
Arguments:
pDO - pointer to the device object of this driver.
pIrp - pointer to an I/O Request Packet.
Return Value:
NT Status code
Notes:
This function can only map the area
below the 4-GB limit.
–*/
{
PDEVICE_EXTENSION pDevExt;
PHYSICAL_ADDRESS phyAddr;
PMMIO_MAP pUsermodeMem;
ULONG i, free_idx;
pDevExt = (PDEVICE_EXTENSION) pDO->DeviceExtension;
//
// Check for free mapZone in the device extension.
// If none is free, return an error code.
//
for(i = 0; i < MAX_MAPPED_MMIO; i++)
{
if( pDevExt->mapZone[i].sysAddrBase == NULL )
{
free_idx = i;
break;
}
}
if( i == MAX_MAPPED_MMIO )
{
return STATUS_INVALID_DEVICE_REQUEST;
}
//
// We have obtained a free mapZone, map the physical address range.
//
pUsermodeMem = (MMIO_MAP*) MmGetSystemAddressForMdlSafe(
pIrp->MdlAddress, NormalPagePriority );
if( NULL == pUsermodeMem) {
return STATUS_INVALID_USER_BUFFER;
}
phyAddr.HighPart = 0;
phyAddr.LowPart = pUsermodeMem->phyAddrStart;
pDevExt->mapZone[free_idx].sysAddrBase = MmMapIoSpace( phyAddr,
pUsermodeMem->size, MmNonCached);
if(NULL == pDevExt->mapZone[free_idx].sysAddrBase)
{
return STATUS_BUFFER_TOO_SMALL;
}
pDevExt->mapZone[free_idx].pMdl =
IoAllocateMdl(pDevExt->mapZone[free_idx].sysAddrBase,
pUsermodeMem->size, FALSE, FALSE, NULL);
if(NULL == pDevExt->mapZone[free_idx].pMdl)
{
MmUnmapIoSpace(pDevExt->mapZone[free_idx].sysAddrBase,
pUsermodeMem->size);
pDevExt->mapZone[free_idx].sysAddrBase = NULL;
return STATUS_BUFFER_TOO_SMALL;
}
pDevExt->mapZone[free_idx].size = pUsermodeMem->size;
//
// Map the system virtual address to usermode virtual address
//
MmBuildMdlForNonPagedPool(pDevExt->mapZone[free_idx].pMdl);
pDevExt->mapZone[free_idx].usermodeAddrBase =
MmMapLockedPagesSpecifyCache( pDevExt->mapZone[free_idx].pMdl,
UserMode, MmNonCached,
NULL, FALSE,
NormalPagePriority);
if(NULL == pDevExt->mapZone[free_idx].usermodeAddrBase)
{
IoFreeMdl(pDevExt->mapZone[free_idx].pMdl);
MmUnmapIoSpace(pDevExt->mapZone[free_idx].sysAddrBase,
pDevExt->mapZone[free_idx].size);
pDevExt->mapZone[free_idx].sysAddrBase = NULL;
pDevExt->mapZone[free_idx].size = 0;
return STATUS_BUFFER_TOO_SMALL;
}
// copy the resulting usermode virtual address to IRP “buffer”
pUsermodeMem->usermodeVirtAddr =
pDevExt->mapZone[free_idx].usermodeAddrBase;
return STATUS_SUCCESS;
}
NTSTATUS CleanupMmioMapping(PDEVICE_EXTENSION pDevExt, ULONG i)
/*++
Routine Description:
This routine cleanup the mapping of a MMIO range
and resources it consumes.
Arguments:
pDevExt - pointer to the device extension of the driver
i - index of the mapZone to cleanup
Return Value:
NT Status code
–*/
{
if( NULL != pDevExt->mapZone[i].usermodeAddrBase )
{
MmUnmapLockedPages( pDevExt->mapZone[i].usermodeAddrBase,
pDevExt->mapZone[i].pMdl);
pDevExt->mapZone[i].usermodeAddrBase = NULL;
}
if( NULL != pDevExt->mapZone[i].pMdl )
{
IoFreeMdl(pDevExt->mapZone[i].pMdl);
pDevExt->mapZone[i].pMdl = NULL;
}
if( NULL != pDevExt->mapZone[i].sysAddrBase )
{
MmUnmapIoSpace( pDevExt->mapZone[i].sysAddrBase,
pDevExt->mapZone[i].size);
pDevExt->mapZone[i].sysAddrBase = NULL;
pDevExt->mapZone[i].size = 0;
}
return STATUS_SUCCESS;
}
NTSTATUS UnmapMmio(PDEVICE_OBJECT pDO, PIRP pIrp)
/*++
Routine Description:
Process the IRPs with IOCTL_UNMAP_MMIO code.
This routine unmaps a previously mapped physical
address range.
Arguments:
pDO - pointer to the device object of this driver.
pIrp - pointer to an I/O Request Packet.
Return Value:
NT Status code
Notes:
This function can only unmap the area
below the 4-GB limit.
–*/
{
PDEVICE_EXTENSION pDevExt;
PMMIO_MAP pMmioMap;
ULONG i;
//
// Unmap the requested zone from the system address space
// and update the device extension data
//
pDevExt = (PDEVICE_EXTENSION) pDO->DeviceExtension;
pMmioMap = (PMMIO_MAP) MmGetSystemAddressForMdlSafe(
pIrp->MdlAddress, NormalPagePriority );
for(i = 0 ; i < MAX_MAPPED_MMIO; i++)
{
if(pDevExt->mapZone[i].usermodeAddrBase ==
pMmioMap->usermodeVirtAddr)
{
CleanupMmioMapping(pDevExt, i);
break;
}
}
return STATUS_SUCCESS;
}
NTSTATUS
DispatchIoControl(
IN PDEVICE_OBJECT pDO,
IN PIRP pIrp
)
/*++
Routine Description:
Io control code dispatch routine
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to current Irp
Return Value:
NT status code.
–*/
{
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(pIrp);
switch(irpStack->Parameters.DeviceIoControl.IoControlCode)
{
…
case IOCTL_MAP_MMIO:
{
if(irpStack->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(MMIO_MAP)) {
status = MapMmio(pDO, pIrp);
} else {
status = STATUS_BUFFER_TOO_SMALL;
}
}break;
case IOCTL_UNMAP_MMIO:
{
if(irpStack->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(MMIO_MAP)) {
status = UnmapMmio(pDO, pIrp);
} else {
status = STATUS_BUFFER_TOO_SMALL;
}
}break;
default:
{
status = STATUS_INVALID_DEVICE_REQUEST;
}break;
}
//
// complete the I/O request and return appropriate values
//
pIrp->IoStatus.Status = status;
// Set number of bytes to copy back to user-mode
if(status == STATUS_SUCCESS)
{
pIrp->IoStatus.Information =
irpStack->Parameters.DeviceIoControl.OutputBufferLength;
}
else
{
pIrp->IoStatus.Information = 0;
}
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return status;
}
I think the code snippet above should give you enough hints.
The driver code basically allows you to map the entire 4GB physical
address space to a user mode
application which is bad. So, you have to limit the mapping only to
BIOS chip address range
near the 4GB limit. It should be trivial.
Cheers,
Darmawan Salihun
Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256
To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer