Subject: reading/writing CMOS beyond 256 bytes?


sorry this may be OT:

I wrote a little brogram to read/write the CMOS settings to a file on an
Intel L440GX motherboard using the outb() to ports 0x70 and 0x71. The idea
is to save the BIOS settings I like and then be able to blast them from
within Linux without having to tinker with BIOS setup.

Unfortunately, it seems that some settings are not in the 128 (or 256)
bytes accessible this way, so they must be stored elsewhere.

Does anyone know where I should look for the remaining parts of CMOS
(short of having to sign some NDA with Intel?)?

Any advice/pointers is highly appreciated,

Grisha



2001-07-06 12:47:42

by Peter Svensson

[permalink] [raw]
Subject: Re: reading/writing CMOS beyond 256 bytes?

On Fri, 6 Jul 2001, Gregory (Grisha) Trubetskoy wrote:

> I wrote a little brogram to read/write the CMOS settings to a file on an
> Intel L440GX motherboard using the outb() to ports 0x70 and 0x71. The idea
> is to save the BIOS settings I like and then be able to blast them from
> within Linux without having to tinker with BIOS setup.
>
> Unfortunately, it seems that some settings are not in the 128 (or 256)
> bytes accessible this way, so they must be stored elsewhere.

the L440GX has a lot of stuff attached to ipmi. Perhaps some of it is
stored there? Just a thought.

Peter
--
Peter Svensson ! Pgp key available by finger, fingerprint:
<[email protected]> ! 8A E9 20 98 C1 FF 43 E3 07 FD B9 0A 80 72 70 AF
------------------------------------------------------------------------
Remember, Luke, your source will be with you... always...


2001-07-06 14:30:44

by Richard B. Johnson

[permalink] [raw]
Subject: Re: reading/writing CMOS beyond 256 bytes?

On Fri, 6 Jul 2001, Gregory (Grisha) Trubetskoy wrote:

>
> sorry this may be OT:
>
> I wrote a little brogram to read/write the CMOS settings to a file on an
> Intel L440GX motherboard using the outb() to ports 0x70 and 0x71. The idea
> is to save the BIOS settings I like and then be able to blast them from
> within Linux without having to tinker with BIOS setup.
>
> Unfortunately, it seems that some settings are not in the 128 (or 256)
> bytes accessible this way, so they must be stored elsewhere.
>
> Does anyone know where I should look for the remaining parts of CMOS
> (short of having to sign some NDA with Intel?)?
>
> Any advice/pointers is highly appreciated,
>
> Grisha

The CMOS in the timer-chip, whether or not it provides usable storage,
is accessed as an index byte at 0x70 which sets the offset to read/write
in 0x71. Therefore, no more than 256 bytes will ever be accessible
in this manner.

Motherboard manufacturers who have rewritable BIOS chips now leave
one page (typically 64k) for startup parameters. This is erased
and written using the magic provided by the chip vendors. This
is typically a sequence such as:

(The AMD Am29LV800B)

OFFSET DATA (short)
Erase sector:
0x0555 0x00AA
0x02AA 0x0055
0x0555 0x0080
0x0555 0x00AA
0x02AA 0x0055
0x0555 0x0010

Loop on the sector until all bits are set. This is the erased condition.
You need to erase before you write because writes can only reset bits to
zero, and not set them to one.

Program:

0x0555 0x00AA
0x02AA 0x0055
0x0555 0x00A0
OFFSET WORD to WRITE

Loop on OFFSET until it is exactly what you wrote. This sequence
is repeated for every word.

You need to do this at the address where the ROM BIOS actually exists.
It does NOT exist at 0x000F0000 where it appears to be. This is RAM
by the time you see it. It will exist at the top of 32-bit address space,
usually like this:


128k NVRAM
-----------------------------------------
| 64k of scratch and/or setup menu stuff |
------------------------------------------
| The main ROM BIOS |
|________________________________________|
| | offset 0xffffffff
|__ jump vector 0xfffffff0

This assumes a 128k chip (usually).

Since you have to erase a whole sector (64k), you copy the stuff from
the sector that you want to save to RAM. Erase the sector, modify your
copy, then write it back. Each ROM BIOS setup and parameter stuff is
different for each BIOS vendor. You can almost always find some unused
place in the chip to save/restore your parameters, even within the
BIOS portion of NVRAM. Since bits not programmed are set to 0xff, you
can readily find unused space:

000F5D00 00 01 17 02 00 00 46 4C-4F 50 50 59 00 46 4C 4F ......FLOPPY.FLO
000F5D10 50 50 59 00 00 09 0C 17-00 01 06 05 04 04 0C 00 PPY.............
000F5D20 02 50 43 49 20 53 6C 6F-74 31 00 00 09 0C 18 00 .PCI Slot1......
000F5D30 01 06 05 04 04 0B 00 02-50 43 49 20 53 6C 6F 74 ........PCI Slot
000F5D40 32 00 00 09 0C 19 00 01-06 05 04 04 0A 00 02 50 2..............P
000F5D50 43 49 20 53 6C 6F 74 33-00 00 09 0C 1A 00 01 06 CI Slot3........
000F5D60 05 04 04 09 00 02 50 43-49 20 53 6C 6F 74 34 00 ......PCI Slot4.
000F5D70 00 09 0C 1B 00 01 03 04-02 04 00 00 0A 49 53 41 .............ISA
000F5D80 20 53 6C 6F 74 31 00 00-09 0C 1C 00 01 03 04 02 Slot1..........
000F5D90 04 00 00 02 49 53 41 20-53 6C 6F 74 32 00 00 0B ....ISA Slot2...
000F5DA0 05 1D 00 01 4F 45 4D 20-53 74 72 69 6E 67 00 00 ....OEM String..
000F5DB0 0C 05 1E 00 01 53 79 73-74 65 6D 20 53 74 72 69 .....System Stri
000F5DC0 6E 67 00 00 0D 16 1F 00-01 00 00 00 00 00 00 00 ng..............
000F5DD0 00 00 00 00 00 00 00 00-00 01 45 4E 47 4C 49 53 ..........ENGLIS
000F5DE0 48 00 00 FF FF FF FF FF-FF FF FF FF FF FF FF FF H...............
000F5DF0 FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................
000F5E00 FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................
000F5E10 FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................
000F5E20 FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................
000F5E30 FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................


I would use 0x000F5DF0 on up for private parameters. (offset 0x5dF0 in
the ROM BIOS or offset 0x5dF0 + 0x10000 = 0x15df0 into the chip.

Copying/erasing/writing back 64k takes about 1 second. Mucking with
the NVRAM ROM BIOS can leave you with an unbootable system if you
screw up. If your BIOS is in a socket, no problem. Just copy it first.
If it's not, don't do this at home!!!

Cheers,
Dick Johnson

Penguin : Linux version 2.4.1 on an i686 machine (799.53 BogoMips).

I was going to compile a list of innovations that could be
attributed to Microsoft. Once I realized that Ctrl-Alt-Del
was handled in the BIOS, I found that there aren't any.


2001-07-06 15:07:04

by Alan

[permalink] [raw]
Subject: Re: reading/writing CMOS beyond 256 bytes?

> Unfortunately, it seems that some settings are not in the 128 (or 256)
> bytes accessible this way, so they must be stored elsewhere.

Large numbers of BIOS settings are in the NVRAM ESCD area in modern systems
(EISA config, ISAPNP config, etc)

> Does anyone know where I should look for the remaining parts of CMOS
> (short of having to sign some NDA with Intel?)?

The PnPBIOS and ESCD specs are publically available if a little impenetrable

2001-07-08 18:27:49

by Gunther.Mayer

[permalink] [raw]
Subject: ESCD Support for 2.4.6-ac1/PNPBIOS (was: reading/writing CMOS beyond 256 bytes?)

Hi,
with a litte patch to linux-2.4.6ac1 (which includes PNPBIOS)
the ESCD data is easily accessible.

Then "lsescd" will verbosely decode /proc/bus/pnp/escd.

This lets you access important info which would be beneficial for correctly
configuring PnP in Linux (e.g. when you set an IRQ to "reserved for legacy ISA"
in your BIOS setup or you can see what's the difference between selecting
"_PNP OS_" to yes/no in your BIOS setup screen).

Regards, Gunther

P.S. There is an additional potential benefit for ISAPNP: you can
get the PNP Port configured by your BIOS. Previously all cards had
to be reset to use a new port. Linux suffers serverly from not
doing PnP failsafe, burdening configuration tasks onto the user.

cat /proc/bus/pnp/pnpconfig_info
Revision=1 No_Csn=1 ISAPNP_Port=0x20b
^^^

Download from:
http://home.t-online.de/home/gunther.mayer/lsescd-0.10.tar.bz2



Alan Cox wrote:
>
> > Unfortunately, it seems that some settings are not in the 128 (or 256)
> > bytes accessible this way, so they must be stored elsewhere.
>
> Large numbers of BIOS settings are in the NVRAM ESCD area in modern systems
> (EISA config, ISAPNP config, etc)
>
> > Does anyone know where I should look for the remaining parts of CMOS
> > (short of having to sign some NDA with Intel?)?
>
> The PnPBIOS and ESCD specs are publically available if a little impenetrable
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2001-07-08 18:36:00

by Jeff Garzik

[permalink] [raw]
Subject: Re: ESCD Support for 2.4.6-ac1/PNPBIOS (was: reading/writing CMOS beyond 256 bytes?)

#ifndef __ESCD_H__
#define __ESCD_H__

/***********************************************************************
Standard EISA format definitions
***********************************************************************/
/* Bytes #0 and #1 of ID and Slot Information */
struct eisa_id_slot_info {
u8 dup_cfg_num_id : 4; /* Byte # 0: Bits 0-3 id for duplicate CFG filenames
0000 - No duplicate CFG filenames
0001 - 1st duplicate(1ACE0105)
.....
1111 - 15th duplicate(FACE0105) */
u8 slot_type : 2; /* Byte # 0: Bits 4-5
00 - Expansion Slot
01 - embedded slot
10 - virtual slot
11 - reserved(0) */
u8 id_readable : 1; /* Byte # 0: Bit 6
0 - ID reabable
1 - ID not reabable */
u8 dup_id_present : 1; /* Byte # 0: Bit 7
0 - no duplicate ID present
1 - duplicate ID present */

u8 board_eisa_enable_supp : 1; /* Byte # 1: Bit 0 - board can be disabled = 1 */
u8 board_iochkerr : 1; /* Byte # 1: Bit 1 - IOCHKERR supported = 1 */
u8 board_or_entry_lock : 1; /* Byte # 1: Bit 2 - board or entries locked = 1 */
u8 id_slot_resvrd : 3; /* Byte # 1: Bit 3-5 - reserved */
u8 id_slot_no_cfg_file : 1; /* Byte # 1: Bit 6 - Board doesn't have/need cfg file = 1 */
u8 board_config_stat : 1; /* Byte # 1: Bit 7 - config is completed = 0 */
/* - config is not completed = 1 */
};

/* Function Information Byte #0 */
struct eisa_func_entry_info {
u8 type_sub_type_entry : 1; /* Bit 0 - type subtype data = 1 */
u8 memory_entry : 1; /* Bit 1 - mem entry data = 1 */
u8 irq_entry : 1; /* Bit 2 - IRQ data = 1 */
u8 dma_entry : 1; /* Bit 3 - DMA entry data = 1 */
u8 port_range_entry : 1; /* Bit 4 - port range data = 1 */
u8 port_init_entry : 1; /* Bit 5 - port init data = 1 */
u8 freeform_entry : 1; /* Bit 6 - free form data = 1 */
u8 eisa_func_disabled : 1; /* Bit 7 - enabled = 0, disabled = 1 */
};

/* Memory Info struct Bytes #0-6 */
struct eisa_mem_info {
u8 mem_rdwr : 1; /* Bit 0 - 0 = ROM, 1 = RAM */
u8 mem_cached : 1; /* Bit 1 - 0 = not cached */
u8 mem_ch_type : 1; /* Bit 2 - 1 = WB cache, 0=WT cache */
u8 mem_type : 2; /* Bits3-4 -00=sys, 01=exp, 10=vir,11=oth */
u8 mem_shared : 1; /* Bit 5 - 0 not=shared */
u8 mem_reserved1 : 1; /* Bit 6 - 0 = reserved */
u8 mem_more_entries : 1; /* Bit 7 - last entry = 0, more = 1 */
/* _mem data size byte */
u8 mem_data_size : 2; /* Bit 0-1 -00=byte,01=word,10=dwrd,11=rsv */
u8 mem_decode_size : 2; /* Bit 2-3 -00=20,01=24,10=32,11=rsv */
u8 mem_reserved2 : 4; /* Bit 4-7 -0 = reserved */
/* memory start addr */
u8 mem_start_addr0; /* LSByte (divided by 0x100) mem start */
u8 mem_start_addr1; /* Middle Byte memory start */
u8 mem_start_addr2; /* MSByte memory start */
/* memory size */
u8 mem_size0; /* LSByte (divided by 0x400) mem size */
u8 mem_size1; /* LSByte=MSByte=0 means 64MB */
};

/* IRQ Info struct Bytes #0-1 */
struct eisa_irq_info {
u8 irq_number : 4; /* Bit 0-3 - IRQ Number */
u8 irq_rsvrd : 1; /* Bit 4 - must be 0 */
u8 irq_trigger : 1; /* Bit 5 - 0=Edge , 1=Level */
u8 irq_type : 1; /* Bit 6 - 0=Non-shared, 1=Sharable */
u8 irq_more_entries : 1;/* Bit 7 - 0=Last Entry, 1=More entires follow */

u8 irq_reserved; /* Reserved (set to 0) */
};

/* DMA Info struct Bytes #0-1 */
struct eisa_dma_info {
u8 dma_number : 3; /* Bits 0-2 - DMA Number(0-7) */
u8 dma_reserved1 : 3; /* Bits 3-5 Reserved (set to 0) */
u8 dma_type : 1; /* Bit 6 - 0=Non-Sharable, 1=Sharable */
u8 dma_more_entries : 1; /* Bit 7 - 0=Last Entry, 1=more entires follow */

u8 dma_reserved2 : 2; /* Bit 0-1 Reserved (set to 0) */
u8 dma_xfer_size : 2; /* Bits 2-3
00 = 8bit transfer
01 = 16bit transfer
10 = 32bit transfer
11 = 16bit transfer with byte count */
u8 dma_timing : 2; /* Bits 4-5
00 = Isa Compatible timing
01 = Type "A"
10 = Type "B"
11 = Type "C"(Burst) */
u8 dma_reserved3 : 2; /* Bits 6-7 Reserved (set to 0) */
};

/* I/O ports Info struct Bytes #0-2 */
struct eisa_port_info {
u8 port_count:5; /* Bit 0-4 Number of Ports
0000 = 1Port
0001 = 2Sequential Ports (and so on)
1111 = 32Sequential Ports */
u8 port_rsvrd : 1; /* Bit 5 Reserved (set to 0) */
u8 port_shared : 1; /* Bit 6 0=Non-shared, 1=Sharable */
u8 port_more_entries : 1;/* Bit 7 - 0=Last Entry, 1=More entires follow */

u16 port_addr; /* I/O Port Address */
};

/* Init ports Info struct Bytes #0-2 */
struct eisa_init_data {
u8 access_type : 2; /* Bit 0-1
00 - Byte address(8-bit)
01 - Word address(16-bit)
10 - Dword address(32-bit)
11 - Reserved(0) */
u8 port_mask_set : 1; /* Bit 2
0 - Write value to Port(no mask)
1 - Use mask and value */
u8 init_reserved : 4; /* Reserved(0) */
u8 more_entries : 1; /* 0 = Last Entry
1 = More entries follow */
};

/* EISA free format data definition */
struct eisa_freeform_data {
u8 data_size; /* Length of following data block */
u8 data[203]; /* 203 bytes */
};

/* eisa slot function config 320 bytes structure layout definition */
struct eisa_func_cfg_info {
u8 comp_board_id1; /* first byte of compressed board ID */
u8 comp_board_id2; /* second byte of compressed board ID */
u8 comp_board_id3; /* third byte of compressed board ID */
u8 comp_board_id4; /* forth byte of compressed board ID */
struct eisa_id_slot_info s_id_slot_info; /* bit specific slot ID and slot info */
u8 cfg_minor_rev_num; /* minor revision of CFG file extension */
u8 cfg_major_rev_num; /* major revision of CFG file extension */
u8 selections[26]; /* 26 bytes of selection information */
struct eisa_func_entry_info s_func_entry_info; /* Func status and resources stat */
u8 type_sub_type[80]; /* 80 character type/subtype field */
union {
struct {
struct eisa_mem_info as_mem_data[9]; /* 63 bytes mem cfg data */
struct eisa_irq_info as_irq_data[7]; /* 14 bytes IRQ config data */
struct eisa_dma_info as_dma_data[4]; /* 8 bytes DMA channel info */
struct eisa_port_info as_port_data[20]; /* 60 bytes I/O port info */
u8 init_data[60]; /* 60 bytes init. data */
} res_data;
struct eisa_freeform_data ff_data; /* Free format data */
} u_func_data;
};

/***********************************************************************
End of Standard EISA format definitions
***********************************************************************/

/***********************************************************************/
/***********************************************************************/
/* Layout of the whole storage for the ESCD.img file */
/*
1) Escd_CFGHDR. This contains the ESCD size, signature,
version#, and the number of slot entries.

2) This is followed by board records that contain a board header
and board data. Board header contains the size of the board record
and the slot number for the board. The board header is specific
to ISA systems only.

3) The packed data for each slot is preceeded by ESCD_brd_hdr
that contains the size and the slot# for the slot data that
immediately follows.

4) EISA format data for slot zero, the Mother-board: data
for functions 0-n describing MB resources

5) EISA data for slots 1-15 describe EXP EISA and ISA boards:
data in standard format for functions 0-n corresponding to devices
associated with the expansion boards.

6) ESCD data for slots 1-15 describing the PnP ISA boards:
data for functions 0-n corresponding to devices on the expansion
board. Unlocked PnP ISA devices are described as disabled
functions; locked PnP devices on the board are enabled functions.
disbled function n+1 describing extentions specific to PnP board
type. The data uses free format spec.

7) ESCD data for slots 16-64 (Virtual slots) describe the
PCI devices, one PCI board (device) per one slot: one or more
standard EISA function(s) corresponding to the PCI function(s)
0-7 for the PCI device that is located at Bus#,Dev# and Fun#0
address in the system. If the configuration for this device is
unlocked, the standard EISA format function(s) will be disabled;
locked PCI function(s)will be enabled. a last function, the ECD
describing the PCI specific information for the PCI function(s) 0-7.

8) There is a checksum at the end of the storage.

*/
/***********************************************************************/

/* The following structures describe the ESCD extensions. */

struct escd_cfg_hdr {
u16 escd_size; /* Total Size of File/NVRAM */
u32 signature; /* Initialized to "ACFG" */
u8 ver_minor; /* Minor #, should be >= 0 */
u8 ver_major; /* Major #, should be >= 2 */
u8 board_count;
u8 escd_hdr_reserved[3];
};

struct escd_board_hdr {
u16 board_rec_size; /* Including this word */
u8 slot_num;
u8 escdb_hdr_reserved;
};

#define ESCD_SIGNATURE 0x47464341 /* ACFG characters */

/* Free format last funct Board Header ecd extensions */
struct escd_ff_board_hdr {
/* Total size of 16 bytes */
u32 signature; /* Initialized to "ACFG" */
u8 ver_minor; /* should be >= 00 */
u8 ver_major; /* Must be set to 0x02 */
u8 board_type; /* Board Type as in CM defintion */
/* 0x01=isa, 0x02=eisa, 0x04=pci */
/* 0x08=pcmcia, 0x10=PnP Isa, 0x20=mca */
u8 escd_hdr_reserved1; /* Reserved */
u16 pnp_funcs_disabled; /* 16 PnP functions disabled bit-map */
u16 pnp_funcs_cfg_err; /* 16 PnP functions config error status bit-map */
/* This reserved field will now be used u8 abEcd_hdr_reserved2[4]; _reserved */
u16 pnp_funcs_cannot_config; /* 16 PnP funct bit-map to indicate *
/* if the device is reconfigurable */
/* For each bit 0 - Reconfigurable 1- Not reconfigurable */
u8 escd_hdr_reserved[2]; /* Reserved */
};

/* Free Fmt PCI device identifier and data */
struct escd_pci_dev {
u8 bus_num; /* PCI Bus Number (0-255) */
u8 dev_func_num; /* PCI defined Device (0-31) and Func 0-7) num*/
/* Device # in bits 7:3, Function # in bits 2:0 */
u16 device_id; /* PCI device ID */
u16 vendor_id; /* PCI vendor ID */
u8 pci_board_reserved[2]; /* Reserved */
};

/* Free Fmt PnP ISA board identifier */
struct escd_isapnp_dev {
u32 vendor_id; /* PnP ISA vendor ID, 4 char */
u32 pnp_serial_num; /* Board/Device serial # identifier */
};

/* PnP ISA ECD extention function, a last function per board */
struct escd_pnp_ext {
u16 func_size; /* Size set to 28 */
u8 selection_size; /* initialize to 1 */
u8 selection_data; /* initialize to 0 */
u8 func_info; /* FreeFormat, disabled bit set (set to 0xC0) */
u8 freeform_size; /* Size of following free fmt data, excl this
* byte Size set to 24: sizeof
* escd_ff_board_hdr + PnP specific data */
struct escd_ff_board_hdr struct_sz; /* sizeof struct = 16 bytes */
struct escd_isapnp_dev pnp_dev; /* sizeof struct =8 bytes */
};

/* PCI ECD extention function, a last function per board/device */
struct escd_pci_ext {
u16 func_size; /* set to min of 28 for single PCI function */
/* and to 86 for eight functions PCI card */
u8 selection_size; /* initialize to 1 */
u8 selection_data; /* initialize to 0 */
u8 func_info; /* FreeFormat, disabled bit set (set to 0xC0) */
u8 freeform_size; /* Size of following free fmt data, excl this byte
Size set to max of 80: sizeof struct escd_ff_board_hdr
+ PnP specific data allowed intry is 24 or 32 or 40 .. 80 */
struct escd_ff_board_hdr struct_sz; /* sizeof struct = 16 bytes */
struct escd_pci_dev pci_dev[8]; /* sizeof struct = Maximum of 8*8 bytes */
/* There will be only one pci_dev entry for each function on
a multi-function PCI card */
};

/* End of the ECD extensions. */
/***********************************************************************/

#endif /* __ESCD_H__ */


Attachments:
escd.h (11.81 kB)

2001-07-09 11:49:06

by David Woodhouse

[permalink] [raw]
Subject: Re: reading/writing CMOS beyond 256 bytes?



[email protected] said:
> Motherboard manufacturers who have rewritable BIOS chips now leave one
> page (typically 64k) for startup parameters. This is erased and
> written using the magic provided by the chip vendors.

You often have to do chipset-specific magic to enable the WE and Vpp lines
to BIOS flash chips. See drivers/mtd/maps/l440gx.c in my working tree for
an example.

Don't try this at home, kids. :)

--
dwmw2


2001-07-09 14:35:28

by Christer Weinigel

[permalink] [raw]
Subject: Re: reading/writing CMOS beyond 256 bytes?

In article <[email protected]> you write:
>[email protected] said:
>> Motherboard manufacturers who have rewritable BIOS chips now leave one
>> page (typically 64k) for startup parameters. This is erased and
>> written using the magic provided by the chip vendors.
>
>You often have to do chipset-specific magic to enable the WE and Vpp lines
>to BIOS flash chips. See drivers/mtd/maps/l440gx.c in my working tree for
>an example.

Another way might be to use the PnP BIOS to read and write the
ESCD tables. I wrote some code to do this a few years ago and
after beating up the code a bit more I can at least read the ESCD
tables from the BIOS. If anyone is interested in doing something
with the code it can be found at:

http://acolyte.hack.org/~wingel/escd/

The advantage of using the PnP BIOS is that the PnP BIOS knows
about the format of the data in BIOS and how to do all the
chipset specific stuff. The disadantage is as usual that a lot
of BIOSes are buggy.

/Christer

--
"Just how much can I get away with and still go to heaven?"