Hi all, I'm currently reading the source code of flashrom (linux version). I found this linuxbios_init(void) function. What is the purpose of this function? I see that it checks the lb_header and lb_record of the BIOS binary in the flash ROM chip. I suppose that this function works particularly for motherboards already equipped with linuxbios. Am I right? And for motherboard that contains other vendor BIOS, it plainly "returns". Is that correct?
TIA, Darmawan
I see that it's to initializes motherboard-specific flash enable sequence. However, the details is still too vague for me.
Rgds, Darmawan
Darmawan Salihun wrote:
Hi all, I'm currently reading the source code of flashrom (linux version). I found this linuxbios_init(void) function. What is the purpose of this function? I see that it checks the lb_header and lb_record of the BIOS binary in the flash ROM chip. I suppose that this function works particularly for motherboards already equipped with linuxbios. Am I right? And for motherboard that contains other vendor BIOS, it plainly "returns". Is that correct?
TIA, Darmawan
On Wed, Jun 06, 2007 at 08:04:54PM +0700, Darmawan Salihun wrote:
I see that it's to initializes motherboard-specific flash enable sequence. However, the details is still too vague for me.
Yeah, I think the idea is that if there is a lb_header, i.e. if this machine already runs LinuxBIOS, flashrom can figure out exactly which mainboard it is much more easily. For machines running a proprietary BIOS, this is much more difficult - you have to look at pci ids etc, and they are not always unique (vendors like to reuse them....).
This is just my 10,000 feet view, without actually looking at that code ;)
Thanks, Ward.
On Wed, Jun 06, 2007 at 09:09:45AM -0400, Ward Vandewege wrote:
On Wed, Jun 06, 2007 at 08:04:54PM +0700, Darmawan Salihun wrote:
I see that it's to initializes motherboard-specific flash enable sequence. However, the details is still too vague for me.
Yeah, I think the idea is that if there is a lb_header, i.e. if this machine already runs LinuxBIOS, flashrom can figure out exactly which mainboard it is much more easily. For machines running a proprietary BIOS, this is much more difficult - you have to look at pci ids etc, and they are not always unique (vendors like to reuse them....).
This is just my 10,000 feet view, without actually looking at that code ;)
Still spot on.
If there is LB in flash already, the mainboard model and flash enable sequence is determined from that.
Note that this needs an override with -m if the LB chip is being reflashed in a different board than it's intended to be used with.
//Peter
* Peter Stuge stuge-linuxbios@cdy.org [070606 15:24]:
Still spot on.
If there is LB in flash already, the mainboard model and flash enable sequence is determined from that.
Note that this needs an override with -m if the LB chip is being reflashed in a different board than it's intended to be used with.
I think you have to say -f, not -m. Since -m is the board specific enable sequence and the type is determined from ram, not the image.
Stefan
Hi all, I attach the device driver code for my experimental flashrom port to windows back then. It's buggy, too much direct access, etc. But, it works at some points during my brief testing phase. It's based on the old flashrom version 1.23. I know, it's not a good example of software engineering practice. Nonetheless, I want to discuss, on which API that I should be removing from user mode application accesses and which one to retain.
Regards, Darmawan
Sorry, I forgot the attachment previously.
Darmawan Salihun wrote:
Hi all, I attach the device driver code for my experimental flashrom port to windows back then. It's buggy, too much direct access, etc. But, it works at some points during my brief testing phase. It's based on the old flashrom version 1.23. I know, it's not a good example of software engineering practice. Nonetheless, I want to discuss, on which API that I should be removing from user mode application accesses and which one to retain.
Regards, Darmawan
#ifndef __BIOS_PROBE_H__ #define __BIOS_PROBE_H__
#include <ntddk.h> #include "../interfaces.h"
// Debugging macros
#if DBG #define BIOS_PROBE_KDPRINT(_x_) \ DbgPrint("BIOS_PROBE.SYS: ");\ DbgPrint _x_; #else
#define BIOS_PROBE_KDPRINT(_x_)
#endif
#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]; ULONG rtl8139IoBase; // quick hack! }DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING registryPath );
NTSTATUS DispatchCreate( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS DispatchClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
VOID DispatchUnload( IN PDRIVER_OBJECT DriverObject );
NTSTATUS DispatchRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS DispatchWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS DispatchIoControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
#endif //__BIOS_PROBE_H__
/*++
Module Name: bios_probe.c
Abstract: The main file of the BIOS probing utility device driver
Author: Darmawan Salihun (Aug 27, 2006)
Environment: Kernel mode
Revision History:
- Originated from the CancelSafeIrq Win_XP DDK sample by Eliyas Yakub
- (August 27, 2006) BIOS Probing device driver constructed by Darmawan Salihun
- (Sept. 9th, 2006) Device driver architecture reworked to accomodate up to 256 memory mapped I/O (MMIO) range to be mapped by the driver. Systematic comments added.
TODO: - Add routines to check if a requested physical address range __overlaps__ with the currently allocated mapZone in the device extension. Do this in MapMmio function!
--*/
#include "bios_probe.h" #include <devioctl.h> #include "../interfaces.h" #include "rtl8139_hack.h"
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; } pDevExt->rtl8139IoBase = 0; // quick hack !
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 ReadPortByte(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_READ_PORT_BYTE code. This routine reads a byte from the designated port, and returns the value to usermode application through pointer to the locked-down usermode buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_BYTE* pUsermodeMem = (IO_BYTE*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx,[ebx].port8 ;// fetch input port addr in al,dx ;// read the byte from the device mov [ebx].value8, al ;// write probing result directly to user-mode memory
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
return status; }
NTSTATUS ReadPortWord(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_READ_PORT_WORD code. This routine reads a word from the designated port, and returns the value to usermode application through pointer to the locked-down usermode buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_WORD* pUsermodeMem = (IO_WORD*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx, [ebx].port16 ;// fetch input port addr in ax, dx ;// read the bytes from the device mov [ebx].value16, ax ;// write probing result directly to user-mode memory
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
return status; }
NTSTATUS ReadPortLong(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_READ_PORT_LONG code. This routine reads a DWORD from the designated port, and returns the value to usermode application through pointer to the locked-down usermode buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_LONG* pUsermodeMem = (IO_LONG*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx, [ebx].port32 ;// fetch input port addr in eax, dx ;// read the bytes from the device mov [ebx].value32, eax ;// write probing result directly to user-mode memory
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
return status; }
NTSTATUS WritePortByte(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_WRITE_PORT_BYTE code. This routine writes a byte to the designated port. The value of the byte and the port address are obtained through pointer to the locked-down buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_BYTE* pUsermodeMem = (IO_BYTE*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx, [ebx].port8 ;// fetch input port addr mov al, [ebx].value8 ;// read the value to be written directly from user-mode memory out dx, al ;// write the byte to the device
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
return status; }
NTSTATUS WritePortWord(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_WRITE_PORT_WORD code. This routine writes a word to the designated port. The value of the word and the port address are obtained through pointer to the locked-down buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_WORD* pUsermodeMem = (IO_WORD*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx, [ebx].port16 ;// fetch input port addr mov ax, [ebx].value16 ;// read the value to be written directly from user-mode memory out dx, ax ;// write the bytes to the device
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
return status; }
NTSTATUS WritePortLong(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_WRITE_PORT_LONG code. This routine writes a dword to the designated port. The value of the dword and the port address are obtained through pointer to the locked-down buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_LONG* pUsermodeMem = (IO_LONG*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx, [ebx].port32 ;// fetch input port addr mov eax, [ebx].value32 ;// read the value to be written directly from user-mode memory out dx, eax ;// write the bytes to the device
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
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); ULONG * pIoBase = NULL; ULONG bufLength, i; UCHAR * buf; PDEVICE_EXTENSION pDevExt; switch(irpStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_READ_PORT_BYTE: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_BYTE)) { status = ReadPortByte(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_READ_PORT_WORD: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_WORD)) { status = ReadPortWord(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_READ_PORT_LONG: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_LONG)) { status = ReadPortLong(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_WRITE_PORT_BYTE: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_BYTE)) { status = WritePortByte(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_WRITE_PORT_WORD: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_WORD)) { status = WritePortWord(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_WRITE_PORT_LONG: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_LONG)) { status = WritePortLong(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
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; case IOCTL_RTL8139_IOBASE_HACK: // must be called prior to IOCTL_RTL8139_ROM_WRITE_HACK // (writing into RTL8139 ROM) { if(irpStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ULONG)) { pIoBase = (ULONG*) MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); pDevExt = (PDEVICE_EXTENSION) pDO->DeviceExtension; pDevExt->rtl8139IoBase = *pIoBase; } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_RTL8139_ROM_WRITE_HACK: // must be called __after__ IOCTL_RTL8139_IOBASE_HACK { bufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
DbgPrint("IOCTL_RTL8139_ROM_WRITE_HACK: buffer length = %d\n", bufLength); buf = (UCHAR*) MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
/* for( i = 0; i < bufLength; i+=4) { DbgPrint("IOCTL_RTL8139_ROM_WRITE_HACK: buf[%04X] = %08X\n", i,*((ULONG*)&buf[i])); } */
pDevExt = (PDEVICE_EXTENSION) pDO->DeviceExtension;
DbgPrint("IOCTL_RTL8139_ROM_WRITE_HACK: pDevExt->rtl8139IoBase = %X\n", pDevExt->rtl8139IoBase); WriteRtl8139RomHack(pDevExt->rtl8139IoBase, bufLength, buf); }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; }
NTSTATUS DispatchRead( IN PDEVICE_OBJECT pDO, IN PIRP pIrp ) /*++ Routine Description: Read dispatch routine
Arguments: DeviceObject - pointer to a device object. Irp - pointer to current Irp
Return Value: NT status code.
Note: This function does nothing. It's merely a place holder to satisfy the need of the user mode code to open the driver with a GENERIC_READ parameter. --*/ { // Just complete the I/O request right away pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return STATUS_SUCCESS; }
NTSTATUS DispatchWrite( IN PDEVICE_OBJECT pDO, IN PIRP pIrp ) /*++ Routine Description: Write dispatch routine
Arguments: DeviceObject - pointer to a device object. Irp - pointer to current Irp
Return Value: NT status code.
Note: This function does nothing. It's merely a place holder to satisfy the need of the user mode code to open the driver with a GENERIC_WRITE parameter. --*/ { // Just complete the I/O request right away pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return STATUS_SUCCESS; }
NTSTATUS DispatchClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Process the close IRPs sent to this device.
Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet.
Return Value: NT Status code
Note: This function clean-up the mapped MMIO ranges that haven't been cleaned-up by a "buggy" usermode application. --*/ { PDEVICE_EXTENSION pDevExt; ULONG i; NTSTATUS status = STATUS_SUCCESS;
BIOS_PROBE_KDPRINT(("DispatchClose Enter\n"));
pDevExt = DeviceObject->DeviceExtension ;
// // Clean-up the mapped MMIO space in case the usermode // application forget to call UnmapMmio for some MMIO zone. // This is to guard against some buggy usermode application. // for(i = 0; i < MAX_MAPPED_MMIO; i++) { if(pDevExt->mapZone[i].sysAddrBase != NULL) { CleanupMmioMapping(pDevExt, i); } }
// // The IRP_MJ_CLOSE dispatch routine is called when a file object // opened on the driver is being removed from the system; that is, // all file object handles have been closed and the reference count // of the file object is down to 0. // BIOS_PROBE_KDPRINT(("IRP_MJ_CLOSE\n")); Irp->IoStatus.Information = 0;
// // Save Status for return and complete Irp // Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT);
BIOS_PROBE_KDPRINT((" DispatchClose Exit = %x\n", status));
return status; }
VOID DispatchUnload( IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: Free all the allocated resources, etc.
Arguments: DriverObject - pointer to a driver object.
Return Value: VOID --*/ { PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; UNICODE_STRING uniWin32NameString;
BIOS_PROBE_KDPRINT(("DispatchUnload Enter\n"));
// // Create counted string version of our Win32 device name. //
RtlInitUnicodeString( &uniWin32NameString, BIOS_PROBE_DOS_DEVICE_NAME_U );
IoDeleteSymbolicLink( &uniWin32NameString );
ASSERT(!deviceObject->AttachedDevice);
IoDeleteDevice( deviceObject );
BIOS_PROBE_KDPRINT(("DispatchUnload Exit\n")); return; }
On Wed, Jun 06, 2007 at 10:47:59PM +0700, Darmawan Salihun wrote:
I know, it's not a good example of software engineering practice. Nonetheless, I want to discuss, on which API that I should be removing from user mode application accesses and which one to retain.
I couldn't make out much of it.
Again, I think the evolution goes like this:
1. Kernel driver allowing unrestricted reads and writes to top 16MB.
2. Kernel driver implementing the lowest level flash chip API. Possibly using some macro language so that reboot isn't neccessary to upgrade flash support.
API details can't really be that complicated until (2) but I don't think we can get away from doing (1) first so no need to worry about (2) yet.
//Peter
Peter Stuge wrote:
On Wed, Jun 06, 2007 at 10:47:59PM +0700, Darmawan Salihun wrote:
I know, it's not a good example of software engineering practice. Nonetheless, I want to discuss, on which API that I should be removing from user mode application accesses and which one to retain.
I couldn't make out much of it.
Again, I think the evolution goes like this:
- Kernel driver allowing unrestricted reads and writes to top 16MB.
The current version of the driver code is capable of mapping *anywhere* within the 4GB physical address space. It shouldn't be a problem to restrict it to the top 16MB. Anyway, the "mapZone" in the previous attached driver code represents a single contiguous physical memory range. The logic of the mapping process is as follows: a. The physical memory address range is mapped into the kernel's virtual memory address range b. The kernel's virtual memory address range is then mapped to the "requesting" user mode virtual memory address range.
- Kernel driver implementing the lowest level flash chip API.
Possibly using some macro language so that reboot isn't neccessary to upgrade flash support.
Can you please elaborate more on this idea?
--Darmawan MS
On Wed, Jun 06, 2007 at 11:16:03PM +0700, Darmawan Salihun wrote:
- Kernel driver allowing unrestricted reads and writes to top 16MB.
The current version of the driver code is capable of mapping *anywhere* within the 4GB physical address space. It shouldn't be a problem to restrict it to the top 16MB.
We should make that 2MB until we actually support larger flash parts btw.
The logic of the mapping process is as follows: a. The physical memory address range is mapped into the kernel's virtual memory address range b. The kernel's virtual memory address range is then mapped to the "requesting" user mode virtual memory address range.
Sounds good.
- Kernel driver implementing the lowest level flash chip API.
Possibly using some macro language so that reboot isn't neccessary to upgrade flash support.
Can you please elaborate more on this idea?
Still a hard limit of 2MB space in the kernel driver.
The application would "upload" a protocol description to the kernel driver so that the kernel driver does not have to change just because timing parameters or special byte values used in programming sequences change for a newly added flash chips. In practise this idea may turn out to allow just as much damage as (1) and in that case we should just stick with (1).
//Peter
Peter Stuge wrote:
On Wed, Jun 06, 2007 at 11:16:03PM +0700, Darmawan Salihun wrote:
- Kernel driver allowing unrestricted reads and writes to top 16MB.
The current version of the driver code is capable of mapping *anywhere* within the 4GB physical address space. It shouldn't be a problem to restrict it to the top 16MB.
We should make that 2MB until we actually support larger flash parts btw.
ok, no problem.
The logic of the mapping process is as follows: a. The physical memory address range is mapped into the kernel's virtual memory address range b. The kernel's virtual memory address range is then mapped to the "requesting" user mode virtual memory address range.
Sounds good.
For those interested in the driver code attached previously. The bulk of the work is carried out in two functions, i.e.
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. --*/
and
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 --*/
That's all for now.
--Darmawan Salihun
On Thu, Jun 07, 2007 at 12:12:45AM +0700, Darmawan Salihun wrote:
NTSTATUS MapMmio(PDEVICE_OBJECT pDO, PIRP pIrp)
[..]
pDO - pointer to the device object of this driver. pIrp - pointer to an I/O Request Packet.
Uff. What's wrong with void * ? I guess it's not the Windows way.
//Peter
Peter Stuge wrote:
On Thu, Jun 07, 2007 at 12:12:45AM +0700, Darmawan Salihun wrote:
NTSTATUS MapMmio(PDEVICE_OBJECT pDO, PIRP pIrp)
[..]
pDO - pointer to the device object of this driver. pIrp - pointer to an I/O Request Packet.
Uff. What's wrong with void * ? I guess it's not the Windows way.
Yeah. That's how it is. So much Microsoft-defined data structures in the device driver. It's just not save to use void * because of it. Almost everything has their "accessor" functions, i.e. predefined way of using. If we don't conform it may not work.
--Darmawan Salihun
I've thought about this a fair bit, going way back a year or more ago, to when I started porting the DevBIOS project to Linux MTD framework.
Overall I disagree with flashrom being in userspace.
There is the issue of mapping PCI roms to free areas, locking (can you use the EEPROM socket on a NIC while it's receiving a frame?).
I have an idea of how the #2 layer would go, with the hardware access done in the kernel. My first guess is that the library of flash parts would be in the kernel (yuck), or at least the current chip's parameters could be loaded into the kernel driver with an IOCTL which stops kernel bloat and eases updates for new flash parts. This would let whole chip/sector erase, sector program of varying sector sizes, and any other chip specific functions be supported safely.
A simple whole-chip programming could be done with
# cat bios.rom > /dev/bios
style command, while the flashrom2 userspace tool could read the current chip's sector sizes, and selectively program with simple read()/write() calls.
With the hardware access moved into the kernel, the userspace tool(s) could focus on partial updates of code (boot block vs fallback vs normal images), userspace initramfs, kernels (on 2MB flash parts).
One thing that should really drive this home, is that using this architecture on Linux *and* Windows, the same userspace tool could be used on both, so the fancy code for incremental updates, writing parameter blocks, etc., wouldn't have to be duplicated.
Isn't MTD framework capable of handling most of this already?
Regards,
Jeremy
On Wed, 2007-06-06 at 18:00 +0200, Peter Stuge wrote:
On Wed, Jun 06, 2007 at 10:47:59PM +0700, Darmawan Salihun wrote:
I know, it's not a good example of software engineering practice. Nonetheless, I want to discuss, on which API that I should be removing from user mode application accesses and which one to retain.
I couldn't make out much of it.
Again, I think the evolution goes like this:
Kernel driver allowing unrestricted reads and writes to top 16MB.
Kernel driver implementing the lowest level flash chip API.
Possibly using some macro language so that reboot isn't neccessary to upgrade flash support.
API details can't really be that complicated until (2) but I don't think we can get away from doing (1) first so no need to worry about (2) yet.
Oh I love playing advocatus diaboli ;-)
* Jeremy Jackson jerj@coplanar.net [070611 16:58]:
Overall I disagree with flashrom being in userspace.
I have mixed feelings about the approach. As a hardware driver, it strictly belongs to the kernel. Oh, wait, in modern systems hardware drivers strictly belong into userspace, but Linux is not one of them.
At some point more than 50% of my effort went into keeping up with minor and major interface changes in the driver and while I thought I was maintaining it well, it suffered from bitrot and features like pci card flashing broke away since things in the kernel changed.
There is the issue of mapping PCI roms to free areas, locking (can you use the EEPROM socket on a NIC while it's receiving a frame?).
This depends very well on the card. The PCI standard forbids this anyways. Either the ROM or MEM/IO must be enabled, not both at the same time. Nonetheless, you can make sure it does not happen by unloading the network card module.
bloat and eases updates for new flash parts. This would let whole chip/sector erase, sector program of varying sector sizes, and any other chip specific functions be supported safely.
One rule of thumb you have to follow is: Do not run flashrom on an otherwise loaded machine. Then the timing is uncritical.
A simple whole-chip programming could be done with
# cat bios.rom > /dev/bios
cat for example always uses 4k blocks, which might lead to early destruction of the chip. dd bs=512k ... is much better.
With the hardware access moved into the kernel, the userspace tool(s) could focus on partial updates of code (boot block vs fallback vs normal images), userspace initramfs, kernels (on 2MB flash parts).
At what gain? And at what loss?
If you want to block other hw completely like /dev/bios did, you can just do cli/sti in a userspace program as well. That keeps timing issues away.
I agree flashrom should set itself to running with realtime policy enabled.
One thing that should really drive this home, is that using this architecture on Linux *and* Windows, the same userspace tool could be used on both, so the fancy code for incremental updates, writing parameter blocks, etc., wouldn't have to be duplicated.
It should not be duplicated anyways. The Windows driver currently only takes care of mapping memory into user space if I remember correctly.
Isn't MTD framework capable of handling most of this already?
Yes, it is. And it is incredibly complicated and complex for such a simple task. ie. it can be done, but MTD is designed for larger flash parts with filesystems on them. For BIOS chips it is a bit of a PITA.
Stefan
On Mon, 2007-06-11 at 18:17 +0200, Stefan Reinauer wrote:
There is the issue of mapping PCI roms to free areas, locking (can you use the EEPROM socket on a NIC while it's receiving a frame?).
This depends very well on the card. The PCI standard forbids this anyways. Either the ROM or MEM/IO must be enabled, not both at the same time. Nonetheless, you can make sure it does not happen by unloading the network card module.
Well unloading the driver seems a bit clumsy, and a contradiction really. (unloading a driver to use hardware). I would add the flash ROM functionality to the NIC driver, and have it export an MTD map. The space.c stub implementation would just return EBUSY if the interface is up, but specific drivers could enable interleaved access as they are able.
Regards,
Jeremy
Jeremy Jackson schrieb:
Well unloading the driver seems a bit clumsy, and a contradiction really. (unloading a driver to use hardware). I would add the flash ROM functionality to the NIC driver, and have it export an MTD map. The space.c stub implementation would just return EBUSY if the interface is up, but specific drivers could enable interleaved access as they are able.
so who puts exactly the same chunk of code in all the 50-or-so network drivers (not to speak of all the other devices that might be flashable) and maintains it?
From a maintenance perspective, this proposal is a nightmare - in this case, just unloading the driver is preferred imho. Hmm.. I'm not sure how the suspend stuff works on linux, but maybe you could fake a suspend signal to the driver from your driver, so it detaches properly (and can attach again once you're done)?
Regards, Patrick Georgi
* Jeremy Jackson jerj@coplanar.net [070611 19:36]:
Nonetheless, you can make sure it does not happen by unloading the network card module.
Well unloading the driver seems a bit clumsy, and a contradiction really. (unloading a driver to use hardware). I would add the flash ROM functionality to the NIC driver, and have it export an MTD map. The space.c stub implementation would just return EBUSY if the interface is up, but specific drivers could enable interleaved access as they are able.
Still, it has to disable all it's memory and io resources before the rom resource can be used reliably. This is equal to unloading the module, no matter whether you really unload or not.
Adding this to the NIC driver sounds like an interesting approach.
Stefan Reinauer wrote:
Oh I love playing advocatus diaboli ;-)
- Jeremy Jackson jerj@coplanar.net [070611 16:58]:
One thing that should really drive this home, is that using this architecture on Linux *and* Windows, the same userspace tool could be used on both, so the fancy code for incremental updates, writing parameter blocks, etc., wouldn't have to be duplicated.
It should not be duplicated anyways. The Windows driver currently only takes care of mapping memory into user space if I remember correctly.
The current experimental windows driver is capable of _mapping_ the entire 4GB physical address space to user mode application and doing a direct IO transcation (which is bad :-( ). I'm currently working to limit the mapping to the top 16MB below the 4GB limit. It should be trivial. And other thing is to remove the direct IO routine because it's too dangerous and replace it with "Windows driver setup API" instead because what flashrom need is only the PCI id's and some other stuff that I think can be found in windows device configuration information through the setup API. (i.e. CM_xxx function in PnP "manager" or the SetupDi family of API). FYI, I haven't managed to complete a version that can be tested because of my exam last week. Hopefully there will be significant progress this week.
--Darmawan
Okay, I hate to sound naive, but what Windows versions can/will this support? I'm assuming 2000 and XP, what about Vista and 98? Also, where this is going to be a driver, will there be any problem with Vista complaining about it not being signed? Vista can be a real pain with drivers that aren't signed, the beta I was running had a workaround to allow you to boot, but I think that was removed from the retail release, which I have (free of charge, the only way I'd have it) but haven't installed yet.
And last (but not least), flashing the BIOS while running Windows always seems to have been a tricky beast, I bricked a couple boards using windows-based flash tools back in the day. Will there be any ill side effects and/or potential issues with this?
BTW, good work!
-Corey
Darmawan Salihun wrote:
Stefan Reinauer wrote:
Oh I love playing advocatus diaboli ;-)
- Jeremy Jackson jerj@coplanar.net [070611 16:58]:
One thing that should really drive this home, is that using this architecture on Linux *and* Windows, the same userspace tool could be used on both, so the fancy code for incremental updates, writing parameter blocks, etc., wouldn't have to be duplicated.
It should not be duplicated anyways. The Windows driver currently only takes care of mapping memory into user space if I remember correctly.
The current experimental windows driver is capable of _mapping_ the entire 4GB physical address space to user mode application and doing a direct IO transcation (which is bad :-( ). I'm currently working to limit the mapping to the top 16MB below the 4GB limit. It should be trivial. And other thing is to remove the direct IO routine because it's too dangerous and replace it with "Windows driver setup API" instead because what flashrom need is only the PCI id's and some other stuff that I think can be found in windows device configuration information through the setup API. (i.e. CM_xxx function in PnP "manager" or the SetupDi family of API). FYI, I haven't managed to complete a version that can be tested because of my exam last week. Hopefully there will be significant progress this week.
--Darmawan
Hi, Corey Osgood wrote:
Okay, I hate to sound naive, but what Windows versions can/will this support? I'm assuming 2000 and XP,
Yes, indeed. The current driver is still on 2000/XP because I only have the DDK for that version of Windows right now. I haven't evaluate the WDK that's used for Vista yet.
what about Vista and 98? Also, where this is going to be a driver, will there be any problem with Vista complaining about it not being signed? Vista can be a real pain with drivers that aren't signed, the beta I was running had a workaround to allow you to boot, but I think that was removed from the retail release, which I have (free of charge, the only way I'd have it) but haven't installed yet.
I'm still trying to figure out how to support Vista in the future because it has a quite different architecture for "native" Vista driver. IIRC it's the "KMDF" model. "KMDF" is still a big question mark for me :-(. As for Windows 98. I'm not sure yet whether I will be able to "backport" the driver to support it or not. But, Vista support will surely become a priority in the future. Anyway, I have no Vista platform for testing for the moment. I'm focusing on 2000/XP right now. Beside, I heard that there will be service pack for Vista in the near future. Maybe, it's better to wait for it before trying to do anything with Vista because sometimes a new improved version of the Kernel API function is coming down the road. As for the driver signing. I'm also thinking about it. But, IIRC there is a way to generate the "signing" related stuff just enough to make it capable to be loaded in Vista. I'm not sure but I guess it's in one of my OSR magazine sent a few months ago. I'll try digging up on them ;-).
And last (but not least), flashing the BIOS while running Windows always seems to have been a tricky beast, I bricked a couple boards using windows-based flash tools back in the day. Will there be any ill side effects and/or potential issues with this?
This issue will need more testing to be solved because I have no problem at all doing it in two different motherboards. I successfully carry out the flashing even in motherboard that not officially supports windows-based flashing program. I'm using the very early beta version of my program to flash a modified BIOS and it works flawlessly (It's a VIA693A motherboard).
BTW, good work!
Thanks.
--Darmawan
On Sun, Jun 17, 2007 at 11:43:14AM +0700, Darmawan Salihun wrote:
And other thing is to remove the direct IO routine because it's too dangerous and replace it with "Windows driver setup API" instead because what flashrom need is only the PCI id's and some other stuff that I think can be found in windows device configuration information through the setup API.
The direct memory access is still needed of course. But I suppose this is about the PCI config access, which definately needs to go away and use the native PCI API.
//Peter
Hi, Stefan Reinauer wrote:
One thing that should really drive this home, is that using this architecture on Linux *and* Windows, the same userspace tool could be used on both, so the fancy code for incremental updates, writing parameter blocks, etc., wouldn't have to be duplicated.
It should not be duplicated anyways. The Windows driver currently only takes care of mapping memory into user space if I remember correctly.
I've read most of flashrom code and I found that instead of mapping the memory_space_near_the_4GB_limit, flashrom also maps the low 1MB for certain purposes. Therefore, I decided to modify the driver to support both address range. I think it should be acceptable, isn't it?
Anyway, my "loose" target for this week is to have a "testable" version even though the PCI access would still be direct access. My old program is based on flashrom version 1.23. Therefore, I need quite sometime to grasp the current flashrom code. It seems not too much thing changed. The basic logic stays the same, only some linuxBIOS specific routine here and there and more chipset+flash_chip support ofcourse. If there's anything I missed, please inform me.
--Darmawan
On Tue, Jun 19, 2007 at 07:45:15PM +0700, Darmawan Salihun wrote:
flashrom also maps the low 1MB for certain purposes.
Do you know why?
Therefore, I decided to modify the driver to support both address range. I think it should be acceptable, isn't it?
Sure, if there's really a need for it.
Anyway, my "loose" target for this week is to have a "testable" version even though the PCI access would still be direct access.
I would request that this is addressed before you ask anyone else to test the software since it could easily lead to system corruption.
//Peter
* Peter Stuge stuge-linuxbios@cdy.org [070621 01:00]:
On Tue, Jun 19, 2007 at 07:45:15PM +0700, Darmawan Salihun wrote:
flashrom also maps the low 1MB for certain purposes.
Do you know why?
For reading the LinuxBIOS table.
I unified memory mapping in LinuxBIOS a bit a while ago. There are a lot less places in the code where this happens now. Hope that's of some use for your project.
Stefan
Hi all,
Stefan Reinauer wrote:
- Peter Stuge stuge-linuxbios@cdy.org [070621 01:00]:
On Tue, Jun 19, 2007 at 07:45:15PM +0700, Darmawan Salihun wrote:
flashrom also maps the low 1MB for certain purposes.
Do you know why?
For reading the LinuxBIOS table. I unified memory mapping in LinuxBIOS a bit a while ago. There are a lot less places in the code where this happens now. Hope that's of some use for your project.
I see. I'll have a look at it more closely.
Anyway, what is the zlib library used for?
Is the binary from LinuxBIOS build (presumably the payload) compressed using some functions in zlib?
--Darmawan
* Darmawan Salihun darmawan.salihun@gmail.com [070624 11:42]:
Anyway, what is the zlib library used for?
compression of pci.ids for libpci.
Is the binary from LinuxBIOS build (presumably the payload) compressed using some functions in zlib?
No, flashrom does not do any of that "intelligent" stuff. It just writes whatever image it gets.
Hi, Is it acceptable to do direct port I/O through driver for I/O port accesses (other than the PCI bus accesses). I still couldn't figure out the solution for this kind of problem. It will require fair amount of changes to the current flashrom code base for that :-(.
--Darmawan
Stefan Reinauer wrote:
- Darmawan Salihun darmawan.salihun@gmail.com [070624 11:42]:
Anyway, what is the zlib library used for?
compression of pci.ids for libpci.
Is the binary from LinuxBIOS build (presumably the payload) compressed using some functions in zlib?
No, flashrom does not do any of that "intelligent" stuff. It just writes whatever image it gets.
Hi,
On Mon, Jun 25, 2007 at 11:02:50PM +0700, Darmawan Salihun wrote:
Is it acceptable to do direct port I/O through driver for I/O port accesses (other than the PCI bus accesses). I still couldn't figure out the solution for this kind of problem.
Ahh - for enabling flash writes. Well - the alternative is to have all flash enabling code and logic within the kernel driver but that's not very attractive.
Do you know if the IO can be limited to just a few explicitly allowed ports?
//Peter
Hi,
Peter Stuge wrote:
Hi,
On Mon, Jun 25, 2007 at 11:02:50PM +0700, Darmawan Salihun wrote:
Is it acceptable to do direct port I/O through driver for I/O port accesses (other than the PCI bus accesses). I still couldn't figure out the solution for this kind of problem.
Ahh - for enabling flash writes. Well - the alternative is to have all flash enabling code and logic within the kernel driver but that's not very attractive.
Do you know if the IO can be limited to just a few explicitly allowed ports?
Well, that shouldn't be a problem. I mean it can be easily implemented in the driver. But, I need to know which I/O address range that would be ;-). All I know in detail right now is Winbond_I/O_chip-specific because I've only been working with it.
--Darmawan
//Peter
Hi,
I've been trying to build the code using MinGW. But, apparently the GCC (and it's related tools I'm using) is unstable. And it's really annoying because I can't develop anything successfully. Out of 10 build, only 4 or 5 will proceed and even then it will stuck at some points. I've tried building sample application but the end result is still the same. I'm using the latest MinGW and MSys from:
http://sourceforge.net/project/showfiles.php?group_id=2435&package_id=82...
I've reinstalled MSys and MinGW about three times and it still stuck at the same problem, i.e. failure in the build process. The gcc (sometime as.exe) stuck in compiling one file where in another occasion, it compiles perfectly fine. I'm sure the code is just fine because it can compile in my Slackware linux 10.0 just fine.
Is anyone here can give advice on a stable MinGW and/or MSys to use?
TIA, Darmawan
Hi all,
It may sound weird but the fact is: that a logitech camera "daemon" somewhere within my system cause this random crashes. Problem solved. Next time I need more RTFM :(.
Cheers, Darmawan
Darmawan Salihun wrote:
Hi,
I've been trying to build the code using MinGW. But, apparently the
GCC (and it's related tools I'm using) is unstable. And it's really annoying because I can't develop anything successfully. Out of 10 build, only 4 or 5 will proceed and even then it will stuck at some points. I've tried building sample application but the end result is still the same. I'm using the latest MinGW and MSys from:
http://sourceforge.net/project/showfiles.php?group_id=2435&package_id=82...
I've reinstalled MSys and MinGW about three times and it still stuck at the same problem, i.e. failure in the build process. The gcc (sometime as.exe) stuck in compiling one file where in another occasion, it compiles perfectly fine. I'm sure the code is just fine because it can compile in my Slackware linux 10.0 just fine.
Is anyone here can give advice on a stable MinGW and/or MSys to use?
TIA, Darmawan
Darmawan Salihun wrote:
Hi all,
It may sound weird but the fact is: that a logitech camera "daemon" somewhere within my system cause this random crashes. Problem solved. Next time I need more RTFM :(.
Cheers, Darmawan
God bless windows (and logitech) :D Good to hear you worked it out, that sounded like the weirdest problem I'd ever heard of, and the only answer I could come up with was hardware failure.
-Corey
Hi all, I want to report the progress that I made so far. Here they are:
1. The client (user mode) code is compilable with MinGW (currently carried-out in Msys console). However, there are a few drawbacks: a. PCI accesses (libpci) is implemented using direct-I/O access through the driver. b. Other variations of in/out routine is also still direct-I/O access through the driver. c. Memory mapping is already implemented. I'm still finishing the limit of the physical memory ranges that should be "map-able" in the driver. d. The user mode code and the driver hasn't been integrated into one executable file yet. Note that it used to be unified in a single executable file with the driver integrated as a binary resource and loaded dynamically at runtime in my experimental code that was built with Microsoft VC++.
2. There is a possibility to use _only_ MinGW to build all of the components, including the driver. The driver can be built by using winpooch methodology: http://sourceforge.net/docman/?group_id=122629
OK. So that's the general overview for now.
Anyway, I want to ask a few details regarding the source code. 1.) Because there is _no_ reliable functions for sleep() and usleep() that works seamlessly (portable with no logic differences) between the Windows version and the *NIX version. I'm using myusec_delay() instead to replace those function to provide delay. Is that acceptable? or should I try using high resolution timer in Windows NT/2K/XP instead? Note that Sleep() in Windows uses a different measure of time (in milliseconds) compared to sleep() in *NIX (which is measured in seconds).
2.) Is there any "definitive" or "semi-definitive" I/O port address ranges that I suppose to give an R/W access? I mean, right now the 64K I/O space is opened for access in the driver :-(. It should be easy to limit the I/O port address range. However, I need to know those ranges.
OK. That's it. I plan to sign-off/submit the changes this week to mailing list on saturday or sunday. Just for evaluation ;-). It shouldn't be ack-ed because the driver is still troublesome as is the libpci and some others. Nonetheless, I need feedback on the real code. That's why I think it's important to do that ASAP. It should've been last week. But, I have some local issues here that I must take care :-(.
And some info: The mmap function in Unix is compatible with memory-mapped file in Windows. Nonetheless, because there is no such an analogy for /dev/mem in Windows. It's useless to use the windows port of mmap() because it won't be able to map the physical address range. Therefore, we still need the driver that I've used for some time now.
Cheers, Darmawan
Darmawan Salihun wrote:
Hi all, I want to report the progress that I made so far. Here they are:
- The client (user mode) code is compilable with MinGW (currently
carried-out in Msys console). However, there are a few drawbacks: a. PCI accesses (libpci) is implemented using direct-I/O access through the driver. b. Other variations of in/out routine is also still direct-I/O access through the driver. c. Memory mapping is already implemented. I'm still finishing the limit of the physical memory ranges that should be "map-able" in the driver. d. The user mode code and the driver hasn't been integrated into one executable file yet. Note that it used to be unified in a single executable file with the driver integrated as a binary resource and loaded dynamically at runtime in my experimental code that was built with Microsoft VC++.
- There is a possibility to use _only_ MinGW to build all of the
components, including the driver. The driver can be built by using winpooch methodology: http://sourceforge.net/docman/?group_id=122629
OK. So that's the general overview for now.
Anyway, I want to ask a few details regarding the source code. 1.) Because there is _no_ reliable functions for sleep() and usleep() that works seamlessly (portable with no logic differences) between the Windows version and the *NIX version. I'm using myusec_delay() instead to replace those function to provide delay. Is that acceptable? or should I try using high resolution timer in Windows NT/2K/XP instead? Note that Sleep() in Windows uses a different measure of time (in milliseconds) compared to sleep() in *NIX (which is measured in seconds).
I forgot to say that it's possible to use high resolution timer from Windows API instead.
2.) Is there any "definitive" or "semi-definitive" I/O port address ranges that I suppose to give an R/W access? I mean, right now the 64K I/O space is opened for access in the driver :-(. It should be easy to limit the I/O port address range. However, I need to know those ranges.
OK. That's it. I plan to sign-off/submit the changes this week to mailing list on saturday or sunday. Just for evaluation ;-). It shouldn't be ack-ed because the driver is still troublesome as is the libpci and some others. Nonetheless, I need feedback on the real code. That's why I think it's important to do that ASAP. It should've been last week. But, I have some local issues here that I must take care :-(.
And some info: The mmap function in Unix is compatible with memory-mapped file in Windows. Nonetheless, because there is no such an analogy for /dev/mem in Windows. It's useless to use the windows port of mmap() because it won't be able to map the physical address range. Therefore, we still need the driver that I've used for some time now.
Cheers, Darmawan
A 16MB top window seems to be a generic window, most APIC/IOAPIC are mapped at 4GB - 20MB IIRC
My dream is to have a chip specific driver (map driver in MTD terms) which knows the window size the BIOS hardware decoder supports, including the optional enable bits.
The chip driver also interacts with Linux /dev/iomem to reflect the current setting of the optional enables.
It should also update the below 1MB (and maybe below 16MB) aliases in /proc/iomem, according to their actual status in the hardware. For example, the K8 northbridge fixed MTRRs could be disabled, rendering any aliasing of the southbridge or LPC/FWH parts moot (from the processor's perspective at least)
There is a similar (lack of) infrastructure issue with lmsensors ATM, might be interesting to watch progress there
Regards,
Jeremy
On Wed, 2007-06-06 at 18:00 +0200, Peter Stuge wrote:
On Wed, Jun 06, 2007 at 10:47:59PM +0700, Darmawan Salihun wrote:
I know, it's not a good example of software engineering practice. Nonetheless, I want to discuss, on which API that I should be removing from user mode application accesses and which one to retain.
I couldn't make out much of it.
Again, I think the evolution goes like this:
- Kernel driver allowing unrestricted reads and writes to top 16MB.
* Jeremy Jackson jerj@coplanar.net [070611 17:17]:
My dream is to have a chip specific driver (map driver in MTD terms) which knows the window size the BIOS hardware decoder supports, including the optional enable bits.
One kernel driver per supported chipset? Ouch. That does not make things easy at all.
The chip driver also interacts with Linux /dev/iomem to reflect the current setting of the optional enables.
In the kernel you don't have to use /dev/iomem, you can just inb/outb directly (which is what /dev/iomem does)
It should also update the below 1MB (and maybe below 16MB) aliases in /proc/iomem, according to their actual status in the hardware. For example, the K8 northbridge fixed MTRRs could be disabled, rendering any aliasing of the southbridge or LPC/FWH parts moot (from the processor's perspective at least)
How is this thing done today? Is it part of the e820 table? Or does Linux hardcode that area?
Stefan
Presently at least for amd64 (the early init stuff is copied from i386 so it's probably the same), Linux kernel hard codes the below 1M bios area. I'm looking for a way to pass that info to the kernel (from linuxbios table?) similar to e820, so that can be used as RAM. (keyword: legacy removal)
I'm curious to know what depends on the below 1MB alias, and could they be adjusted to use the high BIOS area. Is the low 1MB alias where the standards put $PIR and other tables read from the BIOS by the OS?
Jeremy
It should also update the below 1MB (and maybe below 16MB) aliases in /proc/iomem, according to their actual status in the hardware. For example, the K8 northbridge fixed MTRRs could be disabled, rendering any aliasing of the southbridge or LPC/FWH parts moot (from the processor's perspective at least)
How is this thing done today? Is it part of the e820 table? Or does Linux hardcode that area?
Stefan
On Mon, Jun 11, 2007 at 01:27:17PM -0400, Jeremy Jackson wrote:
I'm curious to know what depends on the below 1MB alias,
DMA IIRC.
//Peter
* Peter Stuge stuge-linuxbios@cdy.org [070611 19:36]:
On Mon, Jun 11, 2007 at 01:27:17PM -0400, Jeremy Jackson wrote:
I'm curious to know what depends on the below 1MB alias,
DMA IIRC.
Is ISA DMA still being used?
* Jeremy Jackson jerj@coplanar.net [070611 19:27]:
area. I'm looking for a way to pass that info to the kernel (from linuxbios table?) similar to e820, so that can be used as RAM. (keyword: legacy removal)
GOOOD idea!
I'm curious to know what depends on the below 1MB alias, and could they be adjusted to use the high BIOS area. Is the low 1MB alias where the standards put $PIR and other tables read from the BIOS by the OS?
PIR and co can be anywhere in the low ram too I think.
On Mon, 2007-06-11 at 18:23 +0200, Stefan Reinauer wrote:
- Jeremy Jackson jerj@coplanar.net [070611 17:17]:
My dream is to have a chip specific driver (map driver in MTD terms) which knows the window size the BIOS hardware decoder supports, including the optional enable bits.
One kernel driver per supported chipset? Ouch. That does not make things easy at all.
Well flashrom has numerous per-chipset and per-motherboard drivers for the write-enable, the quantity of those would remain the same for an in-kernel driver. The benefit would be that the drivers would tell the kernel (/proc/iomem /proc/ioports) what is going on. Consider also that there are per-chipset drivers in Linux for EDAC that flash rom functions could be merged into.
There is always the option of the generic 4G - 16MB window for not-yet-written drivers.
Stefan
On Mon, 2007-06-11 at 18:23 +0200, Stefan Reinauer wrote:
The chip driver also interacts with Linux /dev/iomem to reflect the current setting of the optional enables.
I meant to say /proc/iomem here, how about a do-over?
In the kernel you don't have to use /dev/iomem, you can just inb/outb directly (which is what /dev/iomem does)
It should also update the below 1MB (and maybe below 16MB) aliases in /proc/iomem, according to their actual status in the hardware. For example, the K8 northbridge fixed MTRRs could be disabled, rendering any aliasing of the southbridge or LPC/FWH parts moot (from the processor's perspective at least)
How is this thing done today? Is it part of the e820 table? Or does Linux hardcode that area?
Stefan