Reading system BIOS?

How does one go about reading the contents of the motherboard BIOS under
(32-bit) WinXP?

I’ve seen code that uses \device\physicalmemory but it would appear to me
that it can only read the chunked mapped into the upper area of the low
1MB of physical memory?!?

Regards,


Mark McDougall, Engineer
Virtual Logic Pty Ltd, http:
21-25 King St, Rockdale, 2216
Ph: +612-9599-3255 Fax: +612-9599-3266</http:>

> How does one go about reading the contents of the motherboard BIOS under (32-bit) WinXP?

I came across this requirement in one of the projects I had worked on. I just mapped the physical range 0xf0000 - 0xfffff with MmMapIoSpace() - this is all you need in order to locate SMBIOS table. From this table you can obtain the physical address of the structure table that you can subsequently map into the kernel address space with MmMapIoSpace(), so that you can obtain all data you need. I did all the above without a slightest problem.

I’ve seen code that uses \device\physicalmemory but it would appear to me
that it can only read the chunked mapped into the upper area of the low 1MB of
physical memory?!?

Upper area of the low 1MB of physical memory (i.e. the range 0xf0000 - 0xfffff ) is all that is needed in order to start you off - SMBIOS table is located in this range.

Anton Bassov

xxxxx@hotmail.com wrote:

> How does one go about reading the contents of the motherboard BIOS
> under (32-bit) WinXP?

I came across this requirement in one of the projects I had worked on.
I just mapped the physical range 0xf0000 - 0xfffff with MmMapIoSpace()

  • this is all you need in order to locate SMBIOS table. From this
    table you can obtain the physical address of the structure table that
    you can subsequently map into the kernel address space with
    MmMapIoSpace(), so that you can obtain all data you need.

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).

FWIW the BIOS in question is an LPC firmware hub. I’m guessing I need to
manipulate the ICH7 LPC registers to read blocks of the BIOS into system
memory??? But there appears to be no information at all on how to do this.

Regards,


Mark McDougall, Engineer
Virtual Logic Pty Ltd, http:
21-25 King St, Rockdale, 2216
Ph: +612-9599-3255 Fax: +612-9599-3266</http:>

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,


Mark McDougall, Engineer
Virtual Logic Pty Ltd, http:
21-25 King St, Rockdale, 2216
Ph: +612-9599-3255 Fax: +612-9599-3266</http:>

> I need to read directly from the LPC flash device.

AFAIK, there is no way to do it under Windows - you have to write a code that may be specific to a particular hardware, bang on IO registers that you don’t own, and, in all respects, do everything that you are not supposed to do under Windows. If you stilll want to proceed, go to Intel site and search for the document that describes your target hardware - all these tricks are normally hardware-specific.

BTW, why do you need all this, in the first place??? Are you writing software that tries to detect BIOS modification/corruption?

Anton Bassov

Mark McDougall wrote:

I need to read directly from the LPC flash device.

Access to this storage device will usually be mainboard/BIOS dependent.

AFAIK that’s the reason why every mainboard manufacturer hands out their
own update software.

LPC Flash device is memory mapped in the space from 0xffffffff-SIZE
to 0xffffffff, you need to map this physical memory in your process (
using driver just MmIoSpace ) and read the data, you can just read it
not write.

what do you want to do ??

Thanks & Regards
~ Neeraj

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Hagen Patzke
Sent: Wednesday, July 11, 2007 1:54 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Reading system BIOS?

Mark McDougall wrote:

I need to read directly from the LPC flash device.

Access to this storage device will usually be mainboard/BIOS dependent.

AFAIK that’s the reason why every mainboard manufacturer hands out their

own update software.


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

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

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

> LPC Flash device is memory mapped in the space from 0xffffffff-SIZE

to 0xffffffff

Actually, things are not as easy as you present them. Indeed, the range that you have mentioned is always enabled in memory ( for example, on ICH5 hub it is 0xFFF80000-0xFFFFFFFF), because the first instruction that is fetched and executed following a hardware reset is located at physical address FFFFFFF0H.

However, besides this, flash BIOS may occupy some other memory ranges that are not contingent and may be specific to the motherboard, with possible presence of these ranges indicated by bits in ‘BIOS decode enable’ registers. If you want to see these ranges, you can check, for example, ICH5 hub documentation, but please note that thing may be different for other controllers. In other words, no matter how you look at it, the whole thing is hardware-specific…

Anton Bassov

Totally Agreed with you, Is chipset specific, the memory range I,e, BIOS
range can be looked into Chipset Registers…

Thanks & Regards
~ Neeraj

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@hotmail.com
Sent: Wednesday, July 11, 2007 4:41 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Reading system BIOS?

LPC Flash device is memory mapped in the space from 0xffffffff-SIZE
to 0xffffffff

Actually, things are not as easy as you present them. Indeed, the range
that you have mentioned is always enabled in memory ( for example, on
ICH5 hub it is 0xFFF80000-0xFFFFFFFF), because the first instruction
that is fetched and executed following a hardware reset is located at
physical address FFFFFFF0H.

However, besides this, flash BIOS may occupy some other memory ranges
that are not contingent and may be specific to the motherboard, with
possible presence of these ranges indicated by bits in ‘BIOS decode
enable’ registers. If you want to see these ranges, you can check, for
example, ICH5 hub documentation, but please note that thing may be
different for other controllers. In other words, no matter how you look
at it, the whole thing is hardware-specific…

Anton Bassov


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

> BIOS range can be looked into Chipset Registers…

This approach is hardly appropriate for a commercial product that runs under Windows, although you can do it if you intend to run your software in a “controlled environment”…

Anton Bassov

A simplified but quite detailed explanation is at:

http://www.geocities.com/mamanzip/Articles/Award_Bios_RE/Award_Bios_RE_guide.html#Bios_Chip_Addressing

Cheers,

Darmawan Salihun

Ladkani, Neeraj wrote:

Totally Agreed with you, Is chipset specific, the memory range I,e, BIOS
range can be looked into Chipset Registers…

Thanks & Regards
~ Neeraj

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@hotmail.com
Sent: Wednesday, July 11, 2007 4:41 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Reading system BIOS?

> LPC Flash device is memory mapped in the space from 0xffffffff-SIZE
> to 0xffffffff
>

Actually, things are not as easy as you present them. Indeed, the range
that you have mentioned is always enabled in memory ( for example, on
ICH5 hub it is 0xFFF80000-0xFFFFFFFF), because the first instruction
that is fetched and executed following a hardware reset is located at
physical address FFFFFFF0H.

However, besides this, flash BIOS may occupy some other memory ranges
that are not contingent and may be specific to the motherboard, with
possible presence of these ranges indicated by bits in ‘BIOS decode
enable’ registers. If you want to see these ranges, you can check, for
example, ICH5 hub documentation, but please note that thing may be
different for other controllers. In other words, no matter how you look
at it, the whole thing is hardware-specific…

Anton Bassov


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


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

xxxxx@hotmail.com wrote:

> BIOS range can be looked into Chipset Registers…
>

This approach is hardly appropriate for a commercial product that runs under Windows, although you can do it if you intend to run your software in a “controlled environment”…

Only very specialized software such as windows-based BIOS flashing
software that does so, such as winflash from Phoenix-Award, Inc.
Of course, this kind of tool must run in a “controlled environment” ;-).
BIOS flashing is no ordinary task.

Cheers,

Darmawan Salihun

This link doesn’t work.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Darmawan Salihun
Sent: Wednesday, July 11, 2007 8:15 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Reading system BIOS?

A simplified but quite detailed explanation is at:

http://www.geocities.com/mamanzip/Articles/Award_Bios_RE/Award_Bios_RE_guide
.html#Bios_Chip_Addressing

Cheers,

Darmawan Salihun

Ladkani, Neeraj wrote:

Totally Agreed with you, Is chipset specific, the memory range I,e, BIOS
range can be looked into Chipset Registers…

Thanks & Regards
~ Neeraj

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@hotmail.com
Sent: Wednesday, July 11, 2007 4:41 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Reading system BIOS?

> LPC Flash device is memory mapped in the space from 0xffffffff-SIZE
> to 0xffffffff
>

Actually, things are not as easy as you present them. Indeed, the range
that you have mentioned is always enabled in memory ( for example, on
ICH5 hub it is 0xFFF80000-0xFFFFFFFF), because the first instruction
that is fetched and executed following a hardware reset is located at
physical address FFFFFFF0H.

However, besides this, flash BIOS may occupy some other memory ranges
that are not contingent and may be specific to the motherboard, with
possible presence of these ranges indicated by bits in ‘BIOS decode
enable’ registers. If you want to see these ranges, you can check, for
example, ICH5 hub documentation, but please note that thing may be
different for other controllers. In other words, no matter how you look
at it, the whole thing is hardware-specific…

Anton Bassov


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


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


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

Hi,

The link:

http://www.geocities.com/mamanzip/Articles/Award_Bios_RE/Award_Bios_RE_guide.html#Bios_Chip_Addressing

should work.

In the previous email you have to “lump” the second line to the first
one because it’s divided into two lines instead of one :-(.
The link should end with :

Award_Bios_RE_guide.html#Bios_Chip_Addressing

That would take you to the right page in that website.

Cheers,
Darmawan Salihun

Mark Rodriquez wrote:

This link doesn’t work.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Darmawan Salihun
Sent: Wednesday, July 11, 2007 8:15 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Reading system BIOS?

A simplified but quite detailed explanation is at:

http://www.geocities.com/mamanzip/Articles/Award_Bios_RE/Award_Bios_RE_guide.html#Bios_Chip_Addressing

Cheers,

Darmawan Salihun

Ladkani, Neeraj wrote:

> Totally Agreed with you, Is chipset specific, the memory range I,e, BIOS
> range can be looked into Chipset Registers…
>
>
>
> Thanks & Regards
> ~ Neeraj
>
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com] On Behalf Of
> xxxxx@hotmail.com
> Sent: Wednesday, July 11, 2007 4:41 PM
> To: Windows System Software Devs Interest List
> Subject: RE:[ntdev] Reading system BIOS?
>
>
>
>> LPC Flash device is memory mapped in the space from 0xffffffff-SIZE
>> to 0xffffffff
>>
>>
> Actually, things are not as easy as you present them. Indeed, the range
> that you have mentioned is always enabled in memory ( for example, on
> ICH5 hub it is 0xFFF80000-0xFFFFFFFF), because the first instruction
> that is fetched and executed following a hardware reset is located at
> physical address FFFFFFF0H.
>
> However, besides this, flash BIOS may occupy some other memory ranges
> that are not contingent and may be specific to the motherboard, with
> possible presence of these ranges indicated by bits in ‘BIOS decode
> enable’ registers. If you want to see these ranges, you can check, for
> example, ICH5 hub documentation, but please note that thing may be
> different for other controllers. In other words, no matter how you look
> at it, the whole thing is hardware-specific…
>
> Anton Bassov
>
>
>
> —
> 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
>
> —
> 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

>
>


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


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

unavailable as in transfer limit exceeded for this month pleas try
again next month

Sorry, this GeoCities site is currently unavailable.
The GeoCities web site you were trying to view has temporarily
exceeded its data transfer limit. Please try again later.

Are you the site owner? Avoid service interruptions in the future by
increasing your data transfer limit! Find out how.

Learn more about data transfer.

On 7/11/07, Darmawan Salihun wrote:
> Hi,
>
> The link:
>
> http://www.geocities.com/mamanzip/Articles/Award_Bios_RE/Award_Bios_RE_guide.html#Bios_Chip_Addressing
>
> should work.
>
> In the previous email you have to “lump” the second line to the first
> one because it’s divided into two lines instead of one :-(.
> The link should end with :
>
> Award_Bios_RE_guide.html#Bios_Chip_Addressing
>
> That would take you to the right page in that website.
>
> Cheers,
> Darmawan Salihun
>
> Mark Rodriquez wrote:
> > This link doesn’t work.
> >
> > -----Original Message-----
> > From: xxxxx@lists.osr.com
> > [mailto:xxxxx@lists.osr.com] On Behalf Of Darmawan Salihun
> > Sent: Wednesday, July 11, 2007 8:15 AM
> > To: Windows System Software Devs Interest List
> > Subject: Re: [ntdev] Reading system BIOS?
> >
> > A simplified but quite detailed explanation is at:
> >
> > http://www.geocities.com/mamanzip/Articles/Award_Bios_RE/Award_Bios_RE_guide.html#Bios_Chip_Addressing
> >
> >
> > Cheers,
> >
> > Darmawan Salihun
> >
> >
> > Ladkani, Neeraj wrote:
> >
> >> Totally Agreed with you, Is chipset specific, the memory range I,e, BIOS
> >> range can be looked into Chipset Registers…
> >>
> >>
> >>
> >> Thanks & Regards
> >> ~ Neeraj
> >>
> >>
> >> -----Original Message-----
> >> From: xxxxx@lists.osr.com
> >> [mailto:xxxxx@lists.osr.com] On Behalf Of
> >> xxxxx@hotmail.com
> >> Sent: Wednesday, July 11, 2007 4:41 PM
> >> To: Windows System Software Devs Interest List
> >> Subject: RE:[ntdev] Reading system BIOS?
> >>
> >>
> >>
> >>> LPC Flash device is memory mapped in the space from 0xffffffff-SIZE
> >>> to 0xffffffff
> >>>
> >>>
> >> Actually, things are not as easy as you present them. Indeed, the range
> >> that you have mentioned is always enabled in memory ( for example, on
> >> ICH5 hub it is 0xFFF80000-0xFFFFFFFF), because the first instruction
> >> that is fetched and executed following a hardware reset is located at
> >> physical address FFFFFFF0H.
> >>
> >> However, besides this, flash BIOS may occupy some other memory ranges
> >> that are not contingent and may be specific to the motherboard, with
> >> possible presence of these ranges indicated by bits in ‘BIOS decode
> >> enable’ registers. If you want to see these ranges, you can check, for
> >> example, ICH5 hub documentation, but please note that thing may be
> >> different for other controllers. In other words, no matter how you look
> >> at it, the whole thing is hardware-specific…
> >>
> >> Anton Bassov
> >>
> >>
> >>
> >> —
> >> 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
> >>
> >> —
> >> 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
> >
> >>
> >>
> >
> >
> > —
> > 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
> >
> >
> > —
> > 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
> >
> >
>
>
> —
> 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
>

Darmawan Salihun wrote:

http://www.geocities.com/mamanzip/Articles/Award_Bios_RE/Award_Bios_RE_guide.html#Bios_Chip_Addressing
should work.

“The GeoCities web site you were trying to view has temporarily exceeded
its data transfer limit. Please try again later.”

It is not an address issue… :slight_smile:

Hi,

raj_r wrote:

unavailable as in transfer limit exceeded for this month pleas try
again next month

Sorry, this GeoCities site is currently unavailable.
The GeoCities web site you were trying to view has temporarily
exceeded its data transfer limit. Please try again later.

Are you the site owner? Avoid service interruptions in the future by
increasing your data transfer limit! Find out how.

Learn more about data transfer.

Yeah, I own it. I don’t know it previously because I was accessing the
page cache in the proxy server.

Anyway, this is the content of that point:


  1. Some Hardware Peculiarities

Due to its history, the x86 platform contains lots of hacks, especially
its BIOS. This is due to the backward compatiblity that should be
maintained by any x86 system. In this section I’ll try to explain couple
of stuff that I found during my BIOS disassembly journey that reveal
these peculiarities.
3.1. BIOS Chip Addressing

The most important chips which responsible for the BIOS code handling
are the southbridge and northbridge. In this respect, the northbridge is
responsible for the system address space management, i.e. BIOS
shadowing, handling accesses to RAM and forwarding transaction which
uses BIOS ROM as its target to the southbridge which then eventually
forwarded to BIOS ROM by southbridge. While the southbridge is
responsible for enabling the ROM decode control, which will forward (or
not) the memory addresses to be accessed to the BIOS ROM chip. The
addresses shown below can reside either in the system DRAM or in BIOS
ROM chip, depending on the southbridge and northbridge register setting
at the time the BIOS code is executed.
Physical Address Also Known As Used by Address Aliasing Note
000F_0000h - 000F_FFFFh F_seg / F_segment 1 Mbit, 2 MBit, and 4
MBit BIOS alias to FFFF_0000h - FFFF_FFFFh in all chipset just after
power-up
000E_0000h - 000E_FFFFh E_seg / E_segment 1 Mbit, 2 MBit, and 4
MBit BIOS alias to FFFE_0000h - FFFE_FFFFh in some chipset just
after power-up

The address ranges shown above contain the BIOS code and pretty much
system specific. So, you have to consult your chipset datasheets to
understand it. Also, note that the address above which will be occupied
by the BIOS code during runtime (after BIOS code executes) is only F_seg
i.e. F_0000h - F_FFFFh. However, certain operating system might “trash”
this address and use it for their own purposes. The addresses written
above only reflect the addressing of the BIOS ROM chip to the system
address space when it’s set to be accessed by the BIOS code or another
code that accesses the BIOS ROM chip directly. The mainboard chipsets
are responsible for the mapping of certain BIOS ROM chip area to the
system address space. As we will see later, this mapping can be changed
by programming certain chipset registers.

BIOS chip with capacity bigger than 1 Mbit, i.e. 2 Mbit and 4 Mbit chips
has a quite different addressing for their lower bios area, i.e. C_seg,
D_seg and other lower “segment(s)”. In most cases, this area is mapped
to near-4GB address range. This address range is handled by the
norhtbridge analogous to the PCI address range. In this scheme the
chipset behaves as follows:

* The northbridge acts as the address forwarder, meaning: it
responds to this “special” memory address in different fashion compared
to “normal” memory address which is forwarded directly to RAM. On the
contrary, this “special” memory address is forwarded by the northbridge
to the southbridge to be decoded.
* The southbridge acts as the address decoder, meaning: it decodes
this “special” memory addresses into the right chip “beneath” it, such
as the BIOS chip. In this respect, the southbridge will return “void”
(bus address cycle termination) if the address range is not being
enabled to be decoded in the southbridge configuration registers.

Below is an example:
Physical Address Also Known As Used by Address Aliasing Note
000F_0000h - 000F_FFFFh F_seg / F_segment 1 Mbit, 2 MBit, and 4
Mbit BIOS alias to FFFF_0000h - FFFF_FFFFh in all chipset just after
power-up
000E_0000h - 000E_FFFFh E_seg / E_segment 1 Mbit, 2 Mbit, and 4
Mbit BIOS alias to FFFE_0000h - FFFE_FFFFh in some chipset just
after power-up
FFFD_0000h - FFFD_FFFFh D_seg / D_segment 2 Mbit, and 4 Mbit
BIOS -
FFFC_0000h - FFFC_FFFFh C_seg / C_segment 2 Mbit, and 4 Mbit
BIOS -
FFF8_0000h - FFFB_FFFFh - 4 Mbit BIOS -

The conclusion is: modern day chipsets performs an “emulation” for F_seg
and E_seg handling. This is a proof that modern day x86 systems
maintains backward compatibility. However, this “kludge” sometimes
referred to as the thing of the past that vendors should’ve been removed
from x86 systems.

Below is the VIA693A chipset (Northbridge) system memory map just after
system power-up as written in its datasheet.

Table 4. System Memory Map
Space Start Size Address Range Comment
DOS 0 640K 00000000-0009FFFF Cacheable
VGA 640K 128K 000A0000-000BFFFF Used for SMM
BIOS 768K 16K 000C0000-000C3FFF Shadow Ctrl 1
BIOS 784K 16K 000C4000-000C7FFF Shadow Ctrl 1
BIOS 800K 16K 000C8000-000CBFFF Shadow Ctrl 1
BIOS 816K 16K 000CC000-000CFFFF Shadow Ctrl 1
BIOS 832K 16K 000D0000-000D3FFF Shadow Ctrl 2
BIOS 848K 16K 000D4000-000D7FFF Shadow Ctrl 2
BIOS 864K 16K 000D8000-000DBFFF Shadow Ctrl 2
BIOS 880K 16K 000DC000-000DFFFF Shadow Ctrl 2
BIOS 896K 64K 000E0000-000EFFFF Shadow Ctrl 3
BIOS 960K 64K 000F0000-000FFFFF Shadow Ctrl 3
Sys 1MB — 00100000-DRAM Top Can have hole
Bus D Top DRAM Top-FFFEFFFF
Init 4G-64K 64K FFFEFFFF-FFFFFFFF 000Fxxxx alias

The most important thing to take into account here is the address
aliasing, as you can see the FFFE_FFFFh- FFFF_FFFFh address range is an
alias into 000Fxxxxh, this is where the BIOS ROM chip address mapped (at
least in my mainboard, cross check with yours). But, we also have to
consider that this only applies at the very beginning of boot stage
(just after reset). After the chipset reprogrammed by the BIOS, this
address range will be mapped into system DRAM chips. We can consider
this as the Power-On default values. As a note, the majority of x86
chipsets use this address aliasing scheme, at least for the F-segment
address range.

Another fact that we have to take into account: most chipset only
provides default addressing scheme for F-segment just after power-up in
its configuration registers, other “BIOS ROM segment(s)” remains
inaccessible. The addressing scheme for these segments will be
configured later by the bootblock code by altering the related chipset
registers (in most cases the southbridge registers). The chipset that’s
being dissected here also belongs to this group.

Modern day systems connect the BIOS ROM chip to the southbridge through
LPC(Low Pin Count) interface. However, the southbridge described in this
article don’t have such a interface. It’s an old chipset and still uses
ISA BUS to interface with the BIOS ROM chip.

Anyway, more info regarding the BIOS stuff is in a book that I wrote
recently (I don’t mean to advertise it here only to help those who are
in need).

http://www.amazon.com/BIOS-Disassembly-Ninjutsu-Uncovered/dp/1931769605

The book comes with a CDROM. It contains the source code for a
command-line utility to probe BIOS contents directly in Windows 2000/XP.
It’s only a proof of concept and quick hack solution. Regard the source
code as a very rough template.
Anyway, the source code is explained in chapter 9 of the book.

Moreover, I haven’t got the time to setup a reliable website to host the
info’s. It’s too bad :frowning:

Cheers,
Darmawan Salihun

That was very interesting Darmawan. I actually ordered your book a few
months back, but haven’t gotten to it yet. It’s on my list.

In any case, just to make the picture even bleaker, let me throw in that
SMM/SMI usage in some motherboards/chipsets/BIOS can be used to warp
this picture further. In my opinion, without a vendor specification or
other information for your specific platform, it is very difficult to
trust what you might learn from probing IO ports or other ways of
determining configuration, for example, without monitoring the process
using some sort of JTAG emulator or LAI device. In the case of LPC,
there are some ports that have been documented as blocked (the RTC is
one, I believe), and there is a Microsoft document that I believe says
the documented way of accessing CMOS NVRAM is to issue an SMI with the
help of ACPI. I don’t know the details, or how realistic any of these
concerns are for your case, but I think there is some evidence that this
could be a problem for something like a checksum. This problem
potentially gets much worse when VT-x is considered, and goes up again
for VT-d and TXT.

mm

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Darmawan Salihun
Sent: Wednesday, July 11, 2007 09:33
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Reading system BIOS?

Hi,

raj_r wrote:

unavailable as in transfer limit exceeded for this month pleas try
again next month

Sorry, this GeoCities site is currently unavailable.
The GeoCities web site you were trying to view has temporarily
exceeded its data transfer limit. Please try again later.

Are you the site owner? Avoid service interruptions in the future by
increasing your data transfer limit! Find out how.

Learn more about data transfer.

Yeah, I own it. I don’t know it previously because I was accessing the
page cache in the proxy server.

Anyway, this is the content of that point:


  1. Some Hardware Peculiarities

Due to its history, the x86 platform contains lots of hacks, especially
its BIOS. This is due to the backward compatiblity that should be
maintained by any x86 system. In this section I’ll try to explain couple
of stuff that I found during my BIOS disassembly journey that reveal
these peculiarities.
3.1. BIOS Chip Addressing

The most important chips which responsible for the BIOS code handling
are the southbridge and northbridge. In this respect, the northbridge is
responsible for the system address space management, i.e. BIOS
shadowing, handling accesses to RAM and forwarding transaction which
uses BIOS ROM as its target to the southbridge which then eventually
forwarded to BIOS ROM by southbridge. While the southbridge is
responsible for enabling the ROM decode control, which will forward (or
not) the memory addresses to be accessed to the BIOS ROM chip. The
addresses shown below can reside either in the system DRAM or in BIOS
ROM chip, depending on the southbridge and northbridge register setting
at the time the BIOS code is executed.
Physical Address Also Known As Used by Address Aliasing Note
000F_0000h - 000F_FFFFh F_seg / F_segment 1 Mbit, 2 MBit, and 4
MBit BIOS alias to FFFF_0000h - FFFF_FFFFh in all chipset just after
power-up
000E_0000h - 000E_FFFFh E_seg / E_segment 1 Mbit, 2 MBit, and 4
MBit BIOS alias to FFFE_0000h - FFFE_FFFFh in some chipset just
after power-up

The address ranges shown above contain the BIOS code and pretty much
system specific. So, you have to consult your chipset datasheets to
understand it. Also, note that the address above which will be occupied
by the BIOS code during runtime (after BIOS code executes) is only F_seg
i.e. F_0000h - F_FFFFh. However, certain operating system might “trash”
this address and use it for their own purposes. The addresses written
above only reflect the addressing of the BIOS ROM chip to the system
address space when it’s set to be accessed by the BIOS code or another
code that accesses the BIOS ROM chip directly. The mainboard chipsets
are responsible for the mapping of certain BIOS ROM chip area to the
system address space. As we will see later, this mapping can be changed
by programming certain chipset registers.

BIOS chip with capacity bigger than 1 Mbit, i.e. 2 Mbit and 4 Mbit chips
has a quite different addressing for their lower bios area, i.e. C_seg,
D_seg and other lower “segment(s)”. In most cases, this area is mapped
to near-4GB address range. This address range is handled by the
norhtbridge analogous to the PCI address range. In this scheme the
chipset behaves as follows:

* The northbridge acts as the address forwarder, meaning: it
responds to this “special” memory address in different fashion compared
to “normal” memory address which is forwarded directly to RAM. On the
contrary, this “special” memory address is forwarded by the northbridge
to the southbridge to be decoded.
* The southbridge acts as the address decoder, meaning: it decodes
this “special” memory addresses into the right chip “beneath” it, such
as the BIOS chip. In this respect, the southbridge will return “void”
(bus address cycle termination) if the address range is not being
enabled to be decoded in the southbridge configuration registers.

Below is an example:
Physical Address Also Known As Used by Address Aliasing Note
000F_0000h - 000F_FFFFh F_seg / F_segment 1 Mbit, 2 MBit, and 4
Mbit BIOS alias to FFFF_0000h - FFFF_FFFFh in all chipset just after
power-up
000E_0000h - 000E_FFFFh E_seg / E_segment 1 Mbit, 2 Mbit, and 4
Mbit BIOS alias to FFFE_0000h - FFFE_FFFFh in some chipset just
after power-up
FFFD_0000h - FFFD_FFFFh D_seg / D_segment 2 Mbit, and 4 Mbit
BIOS -
FFFC_0000h - FFFC_FFFFh C_seg / C_segment 2 Mbit, and 4 Mbit
BIOS -
FFF8_0000h - FFFB_FFFFh - 4 Mbit BIOS -

The conclusion is: modern day chipsets performs an “emulation” for F_seg
and E_seg handling. This is a proof that modern day x86 systems
maintains backward compatibility. However, this “kludge” sometimes
referred to as the thing of the past that vendors should’ve been removed
from x86 systems.

Below is the VIA693A chipset (Northbridge) system memory map just after
system power-up as written in its datasheet.

Table 4. System Memory Map
Space Start Size Address Range Comment
DOS 0 640K 00000000-0009FFFF Cacheable
VGA 640K 128K 000A0000-000BFFFF Used for SMM
BIOS 768K 16K 000C0000-000C3FFF Shadow Ctrl 1
BIOS 784K 16K 000C4000-000C7FFF Shadow Ctrl 1
BIOS 800K 16K 000C8000-000CBFFF Shadow Ctrl 1
BIOS 816K 16K 000CC000-000CFFFF Shadow Ctrl 1
BIOS 832K 16K 000D0000-000D3FFF Shadow Ctrl 2
BIOS 848K 16K 000D4000-000D7FFF Shadow Ctrl 2
BIOS 864K 16K 000D8000-000DBFFF Shadow Ctrl 2
BIOS 880K 16K 000DC000-000DFFFF Shadow Ctrl 2
BIOS 896K 64K 000E0000-000EFFFF Shadow Ctrl 3
BIOS 960K 64K 000F0000-000FFFFF Shadow Ctrl 3
Sys 1MB - 00100000-DRAM Top Can have hole
Bus D Top DRAM Top-FFFEFFFF
Init 4G-64K 64K FFFEFFFF-FFFFFFFF 000Fxxxx alias

The most important thing to take into account here is the address
aliasing, as you can see the FFFE_FFFFh- FFFF_FFFFh address range is an
alias into 000Fxxxxh, this is where the BIOS ROM chip address mapped (at
least in my mainboard, cross check with yours). But, we also have to
consider that this only applies at the very beginning of boot stage
(just after reset). After the chipset reprogrammed by the BIOS, this
address range will be mapped into system DRAM chips. We can consider
this as the Power-On default values. As a note, the majority of x86
chipsets use this address aliasing scheme, at least for the F-segment
address range.

Another fact that we have to take into account: most chipset only
provides default addressing scheme for F-segment just after power-up in
its configuration registers, other “BIOS ROM segment(s)” remains
inaccessible. The addressing scheme for these segments will be
configured later by the bootblock code by altering the related chipset
registers (in most cases the southbridge registers). The chipset that’s
being dissected here also belongs to this group.

Modern day systems connect the BIOS ROM chip to the southbridge through
LPC(Low Pin Count) interface. However, the southbridge described in this
article don’t have such a interface. It’s an old chipset and still uses
ISA BUS to interface with the BIOS ROM chip.

Anyway, more info regarding the BIOS stuff is in a book that I wrote
recently (I don’t mean to advertise it here only to help those who are
in need).

http://www.amazon.com/BIOS-Disassembly-Ninjutsu-Uncovered/dp/1931769605

The book comes with a CDROM. It contains the source code for a
command-line utility to probe BIOS contents directly in Windows 2000/XP.
It’s only a proof of concept and quick hack solution. Regard the source
code as a very rough template.
Anyway, the source code is explained in chapter 9 of the book.

Moreover, I haven’t got the time to setup a reliable website to host the
info’s. It’s too bad :frowning:

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