My name is Stefan Tauner and I am the one GSoC student working on flashrom this summer. I live in Vienna/Austria where i am studying computer engineering since 2005 (almost done, I only need to find someone writing my thesis for me… should ask some politicians where they got their ghostwriters…).
Since I started playing around with flashrom and proposed my GSoC project in March I have been quite active in the small flashrom universe. The current main maintainers and contributers – Carl-Daniel Hailfinger, Stefan Reinauer and Michael Karcher – were all very busy and so i was drawn into handling the daily support with the help of other regulars (most outstandingly Idwer Vollering, thank you!). This proved to offer very good opportunities to dive into the code base to answer the questions of others and to get familiar with the overall design. It also led to numerous (mostly tiny) patches authored by me which can be viewed on our patchwork site.
Although I think this was all quite fruitful and also in the best interest of flashrom the main objective is something else: Add support to unlock flash regions on newer Intel chipsets. Many details can be read on the thread leading to my GSoC application here. In this post i will focus on a tiny related bit, that i have already implemented and is currently under review: Hardware Sequencing.
Two weeks ago I wrote a lengthy mail to our mailing list (which you certainly should follow if you are interested in our work!) about my plans to implement hardware sequencing for Intel chipsets and some related questions. You can read it at our mail archive site too, but i will republish it here almost in full (please forgive me the left out capitalization etc.).
newer intel chipsets allow two modes of operation when talking to spi flashes: software and hw sequencing. in sw sequencing the software needs to provide the spi opcodes (or use the predefined ones if applicable) in a table that it can later invoke. to do so the id of the opcode, data lengths and data content is written to some ich registers and a bit is flipped to trigger the execution. the opcodes can be reprogrammed by the software at any time (which allows pretty much everything – as long as there is no locking/protection activated, but that’s another story). sw sequencing is already fully supported by flashrom.
in hw sequencing the list of opcodes is fixed (with the exception of the erase command). this does of course only work if the flash chip adheres to strict specifications which are documented in the datasheets (erase sector size, write enable procedures/status register semantics etc). if ME or GbE firmware should be supported then the restrictions are even more severe (and HW seq is required for those features).
another requirement for hw seq is that the flash must contain a valid descriptor section. in that data structure the layout of the flash contents it described among other things. this way the ME and the GbE processors can find their firmware at startup (my guess). the descriptors also define the locking of the flash regions we had so much trouble in the past. it is also possible to use more than one flash chip to store bios and firmware information with descriptors. this is transparent to the software when using hw seq (and sw seq is not able to speak to the second chip/toggle the second CS at all afaik).
requirements for hw seq (besides the reqs for sw seq like unlocked regions and the properties mentioned in “SPI Based BIOS Requirements” in the data sheets etc.):
- a compatible flash device as defined in “Hardware Sequencing Requirements” in intel’s ICH/PCH datasheets. that is not easy to check right now, but we probably do not care anyway (or is anyone interested in using ICHs as general purpose flashing devices? actually this would be possible with the second chip select and hardware sequencing… :)).
- HSFS.FDV=1 i.e. a valid flash descriptor signature is found at the bottom of the flash (some steppings seem to have an offset of 0x10, but that’s not our problem when we are using HSFS.FDV).
limitations of hw seq:
- only read, write and erase operations can be committed. this has lots of implications for an integration into flashrom; see IMPLEMENTATION below.
other interesting bits:
- there is support for shadowing two flash chips into one contiguous address space. the use of multiple flash chips can be checked in flash descriptor bit FLMAP0.NC. there is limited support for chips with different attributes: different sizes are no problem (defined in fd FCBA). other attributes can be assigned to two parts of the SPI address space by the lower and upper VSCC (Host Lower/Upper Vendor Specific Component Capabilities Register). the border between them is defined by register FPB.FPBA. this can be used for flash chips that differ for example in the erase opcode. NB: this also allows the use of a single flash chip with different erase granularities in different address spaces. the two attribute registers (LVSCC and UVSCC) can be locked independently from each other and from the FLOCKDN bit.
- there is a table of jedec ids and the (erase/write (enable)) abilities of associated flash chips in the flash descriptor (unreachable via ICH/PCH registers). the ability words have the same semantic as the VSCC mentioned above. quoting the (confidential) ibex peak SPI programming guide AN: “The Intel® ME VSCC Table defines how the Intel® ME will communicate with the installed SPI flash. This table is defined in the descriptor and is the responsibility of who puts together the NVM image. LVSCC and/or UVSCC registers are defined in memory space and must be set by BIOS. This table must define every flash part that is intended to be used.”
the very simple access model of hw seq is too simple for flashrom, or put in another way: flashrom is too sophisticated to integrate hw seq easily. in hw seq the target device is not a single flashchip from the flashchips table, but a contiguous address space which we can access by just setting an address, filling in the data (like in sw seq) and then committing the command by setting the read/write or erase mode and the go-flag in HSFC. i had two main problems to solve:
- “dynamic” target device. we dont have one single flash chip with certain fixed attributes (which would be saved just like real hardware in flashchips.c), but various possible combinations of attributes (total size, erase block sizes for currently up to two address spaces). we could theoretically add all possible combinations to the constant array of known chips and fake a probing function that returns only true if this combination is found, but that would be very ugly. Instead i have added a generic “Hardware Sequence” flash chip which gets modified when it is probed. This is possible because the probing functions get a pointer to a copy of the constant flashchip struct (whose original version is stored in the text section and is not modifiable).
- different programmer function semantics. there are no SPI opcodes to deal with, so the existing spi functions in ichspi.c are not useful for hwseq, but new functions are necessary. also, the existing methods should not be called when we are in hwseq mode so that for example the first SPI chip is not detected to be accessible by software sequencing. to accomplish this i have added a new struct spi_programmer spi_programmer_ich_hwseq which gets registered instead of the normal software sequencing programmer named spi_programmer_ich9.
so to sum my implementation up: i have added hwseq with a kind of hybrid flashchip/spi_programmer, which can be integrated with very few changed to the existing code. (i was pretty surprised by this, look at the patch yourself!)
the only thing that remains is to decide when hwseq should be used instead of swseq. this has not been discussed yet but should not be a big problem.
in my proposed patch i decide based on two properties: i use hwseq if either there are >=2 SPI chips attached or if the SPI configuration is locked down (as indicated by the FLOCKDN bit in HSFS).
if you made it this far without skipping anything: congrats! (or should i feel sorry for you? ;))