2010/10/21 Carl-Daniel Hailfinger <span dir="ltr"><<a href="mailto:c-d.hailfinger.devel.2006@gmx.net">c-d.hailfinger.devel.2006@gmx.net</a>></span><br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
New version. This one should address most review comments.<br></blockquote><div><br>With -p nic3com: <br></div><div><br>Erase:<br>$ sudo ./flashrom -p nic3com -V -E<br>flashrom v0.9.3-r1216 on Linux 2.6.35-ARCH (i686), built with libpci 3.1.7, GCC 4.5.1, little endian<br>
flashrom is free software, get the source code at <a href="http://www.flashrom.org">http://www.flashrom.org</a><br><br>Calibrating delay loop... OS timer resolution is 1 usecs, 1936M loops per second, 10 myus = 10 us, 100 myus = 97 us, 1000 myus = 972 us, 10000 myus = 11516 us, 4 myus = 5 us, OK.<br>
Initializing nic3com programmer<br>Found "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200, BDF 01:01.0).<br>Requested BAR is IO<br>// snip<br>Found chip "Atmel AT49BV512" (64 KB, Parallel) at physical address 0xffff0000.<br>
//snip<br>===<br>This flash part has status UNTESTED for operations: PROBE READ ERASE WRITE<br>The test status of this chip may have been updated in the latest development<br>version of flashrom. If you are running the latest development version,<br>
please email a report to <a href="mailto:flashrom@flashrom.org">flashrom@flashrom.org</a> if any of the above operations<br>work correctly for you with this flash part. Please include the flashrom<br>output with the additional -V option for all operations you tested (-V, -Vr,<br>
-Vw, -VE), and mention which mainboard or programmer you tested.<br>Please mention your board in the subject line. Thanks for your help!<br>Erasing and writing flash chip... Looking at blockwise erase function 0... trying... 0x000000-0x00ffff:E<br>
<br>Done.<br> <br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div class="im"><br>
If anyone feels adventurous, I would love to see logs on Intel/VIA<br>
chipsets with SPI (preferably locked down chipsets or with r1193 reverted).<br></div></blockquote><div><br>On Intel hardware (abusing the wide concept of "chipset" :)):<br><br>Write (yes, I have a backup file):<br>
$ sudo ./flashrom -p nicintel_spi -w nicintel_spi.rom -c M25P10.RES -V<br>flashrom v0.9.3-r1216 on Linux 2.6.35-ARCH (i686), built with libpci 3.1.7, GCC 4.5.1, little endian<br>flashrom is free software, get the source code at <a href="http://www.flashrom.org">http://www.flashrom.org</a><br>
<br>Calibrating delay loop... OS timer resolution is 1 usecs, 1907M loops per second, 10 myus = 10 us, 100 myus = 96 us, 1000 myus = 1014 us, 10000 myus = 10801 us, 4 myus = 4 us, OK.<br>Initializing nicintel_spi programmer<br>
Found "Intel 82541PI Gigabit Ethernet Controller" (8086:107c, BDF 01:03.0).<br>Requested BAR is MEM, 32bit, not prefetchable<br>Probing for ST M25P10.RES, 128 KB: probe_spi_res1: id 0x10<br>Chip status register is 00<br>
Found chip "ST M25P10.RES" (128 KB, SPI) at physical address 0xfffe0000.<br>===<br>This flash part has status UNTESTED for operations: PROBE READ ERASE WRITE<br>The test status of this chip may have been updated in the latest development<br>
version of flashrom. If you are running the latest development version,<br>please email a report to <a href="mailto:flashrom@flashrom.org">flashrom@flashrom.org</a> if any of the above operations<br>work correctly for you with this flash part. Please include the flashrom<br>
output with the additional -V option for all operations you tested (-V, -Vr,<br>-Vw, -VE), and mention which mainboard or programmer you tested.<br>Please mention your board in the subject line. Thanks for your help!<br>Reading old flash chip contents...<br>
Erasing and writing flash chip... Looking at blockwise erase function 0... trying... 0x000000-0x007fff:S, 0x008000-0x00ffff:EW, 0x010000-0x017fff:EW, 0x018000-0x01ffff:S<br><br>Done.<br>Verifying flash... VERIFY FAILED at 0x00008000! Expected=0xc6, Read=0x15, failed byte count from 0x00000000-0x0001ffff: 0x872f<br>
Your flash chip is in an unknown state.<br>Get help on IRC at <a href="http://irc.freenode.net">irc.freenode.net</a> (channel #flashrom) or<br>mail <a href="mailto:flashrom@flashrom.org">flashrom@flashrom.org</a> with FAILED: your board name in the subject line!<br>
-------------------------------------------------------------------------------<br>DO NOT REBOOT OR POWEROFF!<br><br>Erase:<br>$ sudo ./flashrom -p nicintel_spi -E -c M25P10.RES -V<br>flashrom v0.9.3-r1216 on Linux 2.6.35-ARCH (i686), built with libpci 3.1.7, GCC 4.5.1, little endian<br>
flashrom is free software, get the source code at <a href="http://www.flashrom.org">http://www.flashrom.org</a><br><br>Calibrating delay loop... OS timer resolution is 1 usecs, 1833M loops per second, 10 myus = 9 us, 100 myus = 92 us, 1000 myus = 917 us, 10000 myus = 11106 us, 4 myus = 4 us, OK.<br>
Initializing nicintel_spi programmer<br>Found "Intel 82541PI Gigabit Ethernet Controller" (8086:107c, BDF 01:03.0).<br>Requested BAR is MEM, 32bit, not prefetchable<br>Probing for ST M25P10.RES, 128 KB: probe_spi_res1: id 0x10<br>
Chip status register is 00<br>Found chip "ST M25P10.RES" (128 KB, SPI) at physical address 0xfffe0000.<br>===<br>This flash part has status UNTESTED for operations: PROBE READ ERASE WRITE<br>The test status of this chip may have been updated in the latest development<br>
version of flashrom. If you are running the latest development version,<br>please email a report to <a href="mailto:flashrom@flashrom.org">flashrom@flashrom.org</a> if any of the above operations<br>work correctly for you with this flash part. Please include the flashrom<br>
output with the additional -V option for all operations you tested (-V, -Vr,<br>-Vw, -VE), and mention which mainboard or programmer you tested.<br>Please mention your board in the subject line. Thanks for your help!<br>Erasing and writing flash chip... Looking at blockwise erase function 0... trying... 0x000000-0x007fff:E, 0x008000-0x00ffff:E, 0x010000-0x017fff:E, 0x018000-0x01ffff:E<br>
<br>Done.<br><br><br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"><div class="im">
</div>Tests on boards which need a board enable and where you can lock down<br>
the whole chip or parts of it would be appreciated as well.<br></blockquote><div><br>Mainboard that needs a board enable:<br><br>Erase:<br>$ sudo ./flashrom -V -E<br>flashrom v0.9.3-r1216 on Linux 2.6.35-ARCH (i686), built with libpci 3.1.7, GCC 4.5.1, little endian<br>
flashrom is free software, get the source code at <a href="http://www.flashrom.org">http://www.flashrom.org</a><br><br>Calibrating delay loop... OS timer resolution is 1 usecs, 1945M loops per second, 10 myus = 10 us, 100 myus = 98 us, 1000 myus = 973 us, 10000 myus = 13546 us, 4 myus = 4 us, OK.<br>
Initializing internal programmer<br>No coreboot table found.<br>sh: dmidecode: command not found<br>dmidecode execution unsucessfull - continuing without DMI info<br>Found chipset "Intel ICH5/ICH5R", enabling flash write... chipset PCI ID is 8086:24d0,<br>
BIOS Lock Enable: disabled, BIOS Write Enable: enabled, BIOS_CNTL is 0x1<br>OK.<br>This chipset supports the following protocols: FWH.<br>Disabling flash write protection for board "ASRock P4i65GV"...<br>Intel ICH LPC Bridge: Raising GPIO23.<br>
OK.<br>// snip<br>Found chip "PMC Pm49FL004" (512 KB, LPC,FWH) at physical address 0xfff80000.<br>// snip<br>===<br>This flash part has status UNTESTED for operations: WRITE<br>The test status of this chip may have been updated in the latest development<br>
version of flashrom. If you are running the latest development version,<br>please email a report to <a href="mailto:flashrom@flashrom.org">flashrom@flashrom.org</a> if any of the above operations<br>work correctly for you with this flash part. Please include the flashrom<br>
output with the additional -V option for all operations you tested (-V, -Vr,<br>-Vw, -VE), and mention which mainboard or programmer you tested.<br>Please mention your board in the subject line. Thanks for your help!<br>Erasing and writing flash chip... Looking at blockwise erase function 0... trying... 0x000000-0x000fff:E, 0x001000-0x001fff:E, 0x002000-0x002fff:E, 0x003000-0x003fff:E, 0x004000-0x004fff:E, 0x005000-0x005fff:E, 0x006000-0x006fff:E, 0x007000-0x007fff:E, 0x008000-0x008fff:E, 0x009000-0x009fff:E, 0x00a000-0x00afff:E, 0x00b000-0x00bfff:E, 0x00c000-0x00cfff:E, 0x00d000-0x00dfff:E, 0x00e000-0x00efff:E, 0x00f000-0x00ffff:E, 0x010000-0x010fff:E, 0x011000-0x011fff:E, 0x012000-0x012fff:E, 0x013000-0x013fff:E, 0x014000-0x014fff:E, 0x015000-0x015fff:E, 0x016000-0x016fff:E, 0x017000-0x017fff:E, 0x018000-0x018fff:E, 0x019000-0x019fff:E, 0x01a000-0x01afff:E, 0x01b000-0x01bfff:E, 0x01c000-0x01cfff:E, 0x01d000-0x01dfff:E, 0x01e000-0x01efff:E, 0x01f000-0x01ffff:E, 0x020000-0x020fff:E, 0x021000-0x021fff:E, 0x022000-0x022fff:E, 0x023000-0x023fff:E, 0x024000-0x024fff:E, 0x025000-0x025fff:E, 0x026000-0x026fff:E, 0x027000-0x027fff:E, 0x028000-0x028fff:E, 0x029000-0x029fff:E, 0x02a000-0x02afff:E, 0x02b000-0x02bfff:E, 0x02c000-0x02cfff:E, 0x02d000-0x02dfff:E, 0x02e000-0x02efff:E, 0x02f000-0x02ffff:E, 0x030000-0x030fff:E, 0x031000-0x031fff:E, 0x032000-0x032fff:E, 0x033000-0x033fff:E, 0x034000-0x034fff:E, 0x035000-0x035fff:E, 0x036000-0x036fff:E, 0x037000-0x037fff:E, 0x038000-0x038fff:E, 0x039000-0x039fff:E, 0x03a000-0x03afff:E, 0x03b000-0x03bfff:E, 0x03c000-0x03cfff:E, 0x03d000-0x03dfff:E, 0x03e000-0x03efff:E, 0x03f000-0x03ffff:E, 0x040000-0x040fff:E, 0x041000-0x041fff:E, 0x042000-0x042fff:E, 0x043000-0x043fff:E, 0x044000-0x044fff:E, 0x045000-0x045fff:E, 0x046000-0x046fff:E, 0x047000-0x047fff:E, 0x048000-0x048fff:E, 0x049000-0x049fff:E, 0x04a000-0x04afff:E, 0x04b000-0x04bfff:E, 0x04c000-0x04cfff:E, 0x04d000-0x04dfff:E, 0x04e000-0x04efff:E, 0x04f000-0x04ffff:E, 0x050000-0x050fff:E, 0x051000-0x051fff:E, 0x052000-0x052fff:E, 0x053000-0x053fff:E, 0x054000-0x054fff:E, 0x055000-0x055fff:E, 0x056000-0x056fff:E, 0x057000-0x057fff:E, 0x058000-0x058fff:E, 0x059000-0x059fff:E, 0x05a000-0x05afff:E, 0x05b000-0x05bfff:E, 0x05c000-0x05cfff:E, 0x05d000-0x05dfff:E, 0x05e000-0x05efff:E, 0x05f000-0x05ffff:E, 0x060000-0x060fff:E, 0x061000-0x061fff:E, 0x062000-0x062fff:E, 0x063000-0x063fff:E, 0x064000-0x064fff:E, 0x065000-0x065fff:E, 0x066000-0x066fff:E, 0x067000-0x067fff:E, 0x068000-0x068fff:E, 0x069000-0x069fff:E, 0x06a000-0x06afff:E, 0x06b000-0x06bfff:E, 0x06c000-0x06cfff:E, 0x06d000-0x06dfff:E, 0x06e000-0x06efff:E, 0x06f000-0x06ffff:E, 0x070000-0x070fff:E, 0x071000-0x071fff:E, 0x072000-0x072fff:E, 0x073000-0x073fff:E, 0x074000-0x074fff:E, 0x075000-0x075fff:E, 0x076000-0x076fff:E, 0x077000-0x077fff:E, 0x078000-0x078fff:E, 0x079000-0x079fff:E, 0x07a000-0x07afff:E, 0x07b000-0x07bfff:E, 0x07c000-0x07cfff:E, 0x07d000-0x07dfff:E, 0x07e000-0x07efff:E, 0x07f000-0x07ffff:E<br>
<br>Done.<br><br><br>Write:<br>$ sudo ./flashrom -V -w ~/asrock_p4i65gv_512KB.rom          flashrom v0.9.3-r1216 on Linux 2.6.35-ARCH (i686), built with libpci 3.1.7, GCC 4.5.1, little endian<br>flashrom is free software, get the source code at <a href="http://www.flashrom.org">http://www.flashrom.org</a><br>
<br>Calibrating delay loop... OS timer resolution is 1 usecs, 1886M loops per second, 10 myus = 9 us, 100 myus = 95 us, 1000 myus = 1032 us, 10000 myus = 9180 us, 4 myus = 4 us, OK.<br>Initializing internal programmer<br>
No coreboot table found.<br>sh: dmidecode: command not found<br>dmidecode execution unsucessfull - continuing without DMI info<br>Found chipset "Intel ICH5/ICH5R", enabling flash write... chipset PCI ID is 8086:24d0,<br>
BIOS Lock Enable: disabled, BIOS Write Enable: enabled, BIOS_CNTL is 0x1<br>OK.<br>This chipset supports the following protocols: FWH.<br>Disabling flash write protection for board "ASRock P4i65GV"...<br>Intel ICH LPC Bridge: Raising GPIO23.<br>
OK.<br>// snip<br>Found chip "PMC Pm49FL004" (512 KB, LPC,FWH) at physical address 0xfff80000.<br>// snip<br>===<br>This flash part has status UNTESTED for operations: WRITE<br>The test status of this chip may have been updated in the latest development<br>
version of flashrom. If you are running the latest development version,<br>please email a report to <a href="mailto:flashrom@flashrom.org">flashrom@flashrom.org</a> if any of the above operations<br>work correctly for you with this flash part. Please include the flashrom<br>
output with the additional -V option for all operations you tested (-V, -Vr,<br>-Vw, -VE), and mention which mainboard or programmer you tested.<br>Please mention your board in the subject line. Thanks for your help!<br>Flash image seems to be a legacy BIOS. Disabling checks.<br>
Reading old flash chip contents...<br>Erasing and writing flash chip... Looking at blockwise erase function 0... trying... 0x000000-0x000fff:EW, 0x001000-0x001fff:EW, 0x002000-0x002fff:EW, 0x003000-0x003fff:EW, 0x004000-0x004fff:EW, 0x005000-0x005fff:EW, 0x006000-0x006fff:EW, 0x007000-0x007fff:EW, 0x008000-0x008fff:EW, 0x009000-0x009fff:EW, 0x00a000-0x00afff:EW, 0x00b000-0x00bfff:EW, 0x00c000-0x00cfff:EW, 0x00d000-0x00dfff:EW, 0x00e000-0x00efff:EW, 0x00f000-0x00ffff:EW, 0x010000-0x010fff:EW, 0x011000-0x011fff:EW, 0x012000-0x012fff:W, 0x013000-0x013fff:W, 0x014000-0x014fff:W, 0x015000-0x015fff:W, 0x016000-0x016fff:W, 0x017000-0x017fff:W, 0x018000-0x018fff:W, 0x019000-0x019fff:W, 0x01a000-0x01afff:W, 0x01b000-0x01bfff:W, 0x01c000-0x01cfff:W, 0x01d000-0x01dfff:W, 0x01e000-0x01efff:W, 0x01f000-0x01ffff:W, 0x020000-0x020fff:W, 0x021000-0x021fff:W, 0x022000-0x022fff:W, 0x023000-0x023fff:W, 0x024000-0x024fff:W, 0x025000-0x025fff:W, 0x026000-0x026fff:W, 0x027000-0x027fff:W, 0x028000-0x028fff:W, 0x029000-0x029fff:W, 0x02a000-0x02afff:W, 0x02b000-0x02bfff:W, 0x02c000-0x02cfff:W, 0x02d000-0x02dfff:W, 0x02e000-0x02efff:W, 0x02f000-0x02ffff:W, 0x030000-0x030fff:W, 0x031000-0x031fff:W, 0x032000-0x032fff:W, 0x033000-0x033fff:W, 0x034000-0x034fff:W, 0x035000-0x035fff:W, 0x036000-0x036fff:W, 0x037000-0x037fff:W, 0x038000-0x038fff:W, 0x039000-0x039fff:W, 0x03a000-0x03afff:W, 0x03b000-0x03bfff:W, 0x03c000-0x03cfff:W, 0x03d000-0x03dfff:W, 0x03e000-0x03efff:W, 0x03f000-0x03ffff:W, 0x040000-0x040fff:W, 0x041000-0x041fff:W, 0x042000-0x042fff:W, 0x043000-0x043fff:W, 0x044000-0x044fff:W, 0x045000-0x045fff:W, 0x046000-0x046fff:W, 0x047000-0x047fff:W, 0x048000-0x048fff:W, 0x049000-0x049fff:W, 0x04a000-0x04afff:W, 0x04b000-0x04bfff:W, 0x04c000-0x04cfff:W, 0x04d000-0x04dfff:W, 0x04e000-0x04efff:W, 0x04f000-0x04ffff:W, 0x050000-0x050fff:W, 0x051000-0x051fff:W, 0x052000-0x052fff:W, 0x053000-0x053fff:W, 0x054000-0x054fff:W, 0x055000-0x055fff:W, 0x056000-0x056fff:W, 0x057000-0x057fff:W, 0x058000-0x058fff:W, 0x059000-0x059fff:W, 0x05a000-0x05afff:W, 0x05b000-0x05bfff:W, 0x05c000-0x05cfff:W, 0x05d000-0x05dfff:W, 0x05e000-0x05efff:W, 0x05f000-0x05ffff:W, 0x060000-0x060fff:W, 0x061000-0x061fff:W, 0x062000-0x062fff:W, 0x063000-0x063fff:W, 0x064000-0x064fff:W, 0x065000-0x065fff:W, 0x066000-0x066fff:W, 0x067000-0x067fff:W, 0x068000-0x068fff:W, 0x069000-0x069fff:W, 0x06a000-0x06afff:W, 0x06b000-0x06bfff:W, 0x06c000-0x06cfff:W, 0x06d000-0x06dfff:W, 0x06e000-0x06efff:W, 0x06f000-0x06ffff:W, 0x070000-0x070fff:W, 0x071000-0x071fff:W, 0x072000-0x072fff:W, 0x073000-0x073fff:W, 0x074000-0x074fff:W, 0x075000-0x075fff:W, 0x076000-0x076fff:W, 0x077000-0x077fff:W, 0x078000-0x078fff:W, 0x079000-0x079fff:W, 0x07a000-0x07afff:W, 0x07b000-0x07bfff:W, 0x07c000-0x07cfff:W, 0x07d000-0x07dfff:W, 0x07e000-0x07efff:W, 0x07f000-0x07ffff:EW<br>
<br>Done.<br>Verifying flash... VERIFIED.<br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div class="im"><br>
If you're going to review this, make sure you keep a stack of bananas<br>
(quickly mobilized carbohydrates for your brain), a bucket of ice (to<br>
prevent brain overheating) and a bottle of aspirin handy. If any code is<br>
unclear, please tell me and I'll try to add comments to improve readability.<br>
<br>
This code has been tested. Testing erase (and checking with a separate<br>
readback that erase actually worked) and write (same test with separate<br>
readback) would be highly appreciated. Verbose logs are even more<br>
appreciated.<br>
<br>
I think the code is ready for merge if you trust write/erase to never<br>
fail. The error cases still need to be tested. Should we reread the<br>
whole chip if write/erase failed to make sure our current view of the<br>
chip contents is not stale?<br>
<br>
This patch makes flashrom use real partial writes. If you write an image<br>
full of 0xff, flashrom will erase and detect that no write is needed. If<br>
you write an image which differs only in some parts from the current<br>
flash contents, flashrom will detect that and not touch unchanged areas.<br>
<br>
Fix a long-standing bug in need_erase() for 256 byte granularity as well.<br>
<br>
Nice side benefit: Detailed progress printing.<br>
S means skipped<br>
E means erased<br>
W means written<br>
<br>
Thanks for Andrew Morgan for testing countless iterations of this patch.<br>
</div>Thanks to Richard A. Smith for testing on Dediprog.<br>
Thanks to David Hendricks for the review.<br>
<div><div></div><div class="h5"><br>
Signed-off-by: Carl-Daniel Hailfinger <<a href="mailto:c-d.hailfinger.devel.2006@gmx.net">c-d.hailfinger.devel.2006@gmx.net</a>><br>
<br>
Index: flashrom-partial_write_rolling_erase_write/flashrom.c<br>
===================================================================<br>
--- flashrom-partial_write_rolling_erase_write/flashrom.c       (Revision 1215)<br>
+++ flashrom-partial_write_rolling_erase_write/flashrom.c       (Arbeitskopie)<br>
@@ -793,6 +793,7 @@<br>
  * Check if the buffer @have can be programmed to the content of @want without<br>
  * erasing. This is only possible if all chunks of size @gran are either kept<br>
  * as-is or changed from an all-ones state to any other state.<br>
+ *<br>
  * The following write granularities (enum @gran) are known:<br>
  * - 1 bit. Each bit can be cleared individually.<br>
  * - 1 byte. A byte can be written once. Further writes to an already written<br>
@@ -803,10 +804,12 @@<br>
  *   this function.<br>
  * - 256 bytes. If less than 256 bytes are written, the contents of the<br>
  *   unwritten bytes are undefined.<br>
+ * Warning: This function assumes that @have and @want point to naturally<br>
+ * aligned regions.<br>
  *<br>
  * @have        buffer with current content<br>
  * @want        buffer with desired content<br>
- * @len         length of the verified area<br>
+ * @len                length of the checked area<br>
  * @gran       write granularity (enum, not count)<br>
  * @return      0 if no erase is needed, 1 otherwise<br>
  */<br>
@@ -838,7 +841,7 @@<br>
                                continue;<br>
                        /* have needs to be in erased state. */<br>
                        for (i = 0; i < limit; i++)<br>
-                               if (have[i] != 0xff) {<br>
+                               if (have[j * 256 + i] != 0xff) {<br>
                                        result = 1;<br>
                                        break;<br>
                                }<br>
</div></div>@@ -846,10 +849,85 @@<br>
<div class="im">                                break;<br>
                }<br>
                break;<br>
+       default:<br>
+               msg_cerr("%s: Unsupported granularity! Please report a bug at "<br>
+                        "<a href="mailto:flashrom@flashrom.org">flashrom@flashrom.org</a>\n", __func__);<br>
        }<br>
        return result;<br>
 }<br>
<br>
+/**<br>
+ * Check if the buffer @have needs to be programmed to get the content of @want.<br>
+ * If yes, return 1 and fill in first_start with the start address of the<br>
+ * write operation and first_len with the length of the first to-be-written<br>
+ * chunk. If not, return 0 and leave first_start and first_len undefined.<br>
+ *<br>
+ * Warning: This function assumes that @have and @want point to naturally<br>
+ * aligned regions.<br>
+ *<br>
+ * @have       buffer with current content<br>
+ * @want       buffer with desired content<br>
+ * @len                length of the checked area<br>
+ * @gran       write granularity (enum, not count)<br>
</div>+ * @first_start        offset of the first byte which needs to be written (passed in<br>
+               value is discarded, new value is written when get_next_write<br>
+               returns)<br>
+ * @return     length of the first contiguous area which needs to be written<br>
+ *             0 if no write is needed<br>
<div class="im">+ *<br>
+ * FIXME: This function needs a parameter which tells it about coalescing<br>
+ * in relation to the max write length of the programmer and the max write<br>
+ * length of the chip.<br>
+ */<br>
+static int get_next_write(uint8_t *have, uint8_t *want, int len,<br>
</div>+                         int *first_start, enum write_granularity gran)<br>
+{<br>
+       int need_write = 0;<br>
+       int first_len = 0;<br>
+       int i, limit, stride;<br>
<div class="im">+<br>
+       switch (gran) {<br>
+       case write_gran_1bit:<br>
+       case write_gran_1byte:<br>
</div>+               stride = 1;<br>
<div class="im">+               break;<br>
+       case write_gran_256bytes:<br>
</div>+               stride = 256;<br>
+               break;<br>
<div class="im">+       default:<br>
+               msg_cerr("%s: Unsupported granularity! Please report a bug at "<br>
+                        "<a href="mailto:flashrom@flashrom.org">flashrom@flashrom.org</a>\n", __func__);<br>
</div>+               /* Claim that no write was needed. A write with unknown<br>
+                * granularity is too dangerous to try.<br>
+               */<br>
+               return 0;<br>
+       }<br>
+       for (i = 0; i < len / stride; i++) {<br>
+               limit = min(stride, len - i * stride);<br>
<div class="im">+               /* Are 'have' and 'want' identical? */<br>
</div>+               if (memcmp(have + i * stride, want + i * stride, limit)) {<br>
+                       if (!need_write) {<br>
+                               /* First location where have and want differ. */<br>
+                               need_write = 1;<br>
+                               *first_start = i * stride;<br>
+                       }<br>
+               } else {<br>
+                       if (need_write) {<br>
<div class="im">+                               /* First location where have and want<br>
+                                * do not differ anymore.<br>
+                                */<br>
</div>+                               first_len = i * stride - *first_start;<br>
<div class="im">+                               break;<br>
+                       }<br>
+               }<br>
+       }<br>
+       /* Did the loop terminate without setting first_len? */<br>
</div>+       if (need_write && ! first_len)<br>
+               first_len = min(i * stride - *first_start, len);<br>
+<br>
+       return first_len;<br>
<div class="im">+}<br>
+<br>
 /* This function generates various test patterns useful for testing controller<br>
  * and chip communication as well as chip behaviour.<br>
  *<br>
</div>@@ -1203,7 +1281,8 @@<br>
<div class="im">        return ret;<br>
 }<br>
<br>
-/* This function shares a lot of its structure with erase_flash().<br>
+/* This function shares a lot of its structure with erase_and_write_flash() and<br>
+ * walk_eraseregions().<br>
  * Even if an error is found, the function will keep going and check the rest.<br>
  */<br>
 static int selfcheck_eraseblocks(struct flashchip *flash)<br>
</div>@@ -1271,10 +1350,68 @@<br>
<div><div></div><div class="h5">        return ret;<br>
 }<br>
<br>
+static int erase_and_write_block_helper(struct flashchip *flash,<br>
+                                       unsigned int start, unsigned int len,<br>
+                                       uint8_t *oldcontents,<br>
+                                       uint8_t *newcontents,<br>
+                                       int (*erasefn) (struct flashchip *flash,<br>
+                                                       unsigned int addr,<br>
+                                                       unsigned int len))<br>
+{<br>
+       int starthere = 0;<br>
+       int lenhere = 0;<br>
+       int ret = 0;<br>
+       int skip = 1;<br>
+       int writecount = 0;<br>
+       enum write_granularity gran = write_gran_256bytes; /* FIXME */<br>
+<br>
+       /* oldcontents and newcontents are opaque to walk_eraseregions, and<br>
+        * need to be adjusted here to keep the impression of proper abstraction<br>
+        */<br>
+       oldcontents += start;<br>
+       newcontents += start;<br>
+       msg_cdbg(":");<br>
+       /* FIXME: Assume 256 byte granularity for now to play it safe. */<br>
+       if (need_erase(oldcontents, newcontents, len, gran)) {<br>
+               msg_cdbg("E");<br>
+               ret = erasefn(flash, start, len);<br>
+               if (ret)<br>
+                       return ret;<br>
+               /* Erase was successful. Adjust oldcontents. */<br>
+               memset(oldcontents, 0xff, len);<br>
+               skip = 0;<br>
+       }<br>
</div></div>+       /* get_next_write() sets starthere to a new value after the call. */<br>
+       while ((lenhere = get_next_write(oldcontents + starthere,<br>
<div class="im">+                                        newcontents + starthere,<br>
+                                        len - starthere, &starthere,<br>
</div>+                                        gran))) {<br>
<div><div></div><div class="h5">+               if (!writecount++)<br>
+                       msg_cdbg("W");<br>
+               /* Needs the partial write function signature. */<br>
+               ret = flash->write(flash, newcontents + starthere,<br>
+                                  start + starthere, lenhere);<br>
+               if (ret)<br>
+                       return ret;<br>
+               starthere += lenhere;<br>
+               skip = 0;<br>
+       }<br>
+       if (skip)<br>
+               msg_cdbg("S");<br>
+       return ret;<br>
+}<br>
+<br>
 static int walk_eraseregions(struct flashchip *flash, int erasefunction,<br>
                             int (*do_something) (struct flashchip *flash,<br>
                                                  unsigned int addr,<br>
-                                                 unsigned int len))<br>
+                                                 unsigned int len,<br>
+                                                 uint8_t *param1,<br>
+                                                 uint8_t *param2,<br>
+                                                 int (*erasefn) (<br>
+                                                       struct flashchip *flash,<br>
+                                                       unsigned int addr,<br>
+                                                       unsigned int len)),<br>
+                            void *param1, void *param2)<br>
 {<br>
        int i, j;<br>
        unsigned int start = 0;<br>
</div></div>@@ -1286,21 +1423,34 @@<br>
<div><div></div><div class="h5">                 */<br>
                len = eraser.eraseblocks[i].size;<br>
                for (j = 0; j < eraser.eraseblocks[i].count; j++) {<br>
-                       msg_cdbg("0x%06x-0x%06x, ", start,<br>
+                       /* Print this for every block except the first one. */<br>
+                       if (i || j)<br>
+                               msg_cdbg(", ");<br>
+                       msg_cdbg("0x%06x-0x%06x", start,<br>
                                     start + len - 1);<br>
-                       if (do_something(flash, start, len))<br>
+                       if (do_something(flash, start, len, param1, param2,<br>
+                                        eraser.block_erase)) {<br>
+                               msg_cdbg("\n");<br>
                                return 1;<br>
+                       }<br>
                        start += len;<br>
                }<br>
        }<br>
+       msg_cdbg("\n");<br>
        return 0;<br>
 }<br>
<br>
-int erase_flash(struct flashchip *flash)<br>
+int erase_and_write_flash(struct flashchip *flash, uint8_t *oldcontents, uint8_t *newcontents)<br>
 {<br>
        int k, ret = 0, found = 0;<br>
+       uint8_t *curcontents;<br>
+       unsigned long size = flash->total_size * 1024;<br>
<br>
-       msg_cinfo("Erasing flash chip... ");<br>
+       curcontents = (uint8_t *) malloc(size);<br>
+       /* Copy oldcontents to curcontents to avoid clobbering oldcontents. */<br>
+       memcpy(curcontents, oldcontents, size);<br>
+<br>
+       msg_cinfo("Erasing and writing flash chip... ");<br>
        for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {<br>
                struct block_eraser eraser = flash->block_erasers[k];<br>
<br>
</div></div>@@ -1324,12 +1474,14 @@<br>
<div class="im">                }<br>
                found = 1;<br>
                msg_cdbg("trying... ");<br>
-               ret = walk_eraseregions(flash, k, eraser.block_erase);<br>
+               ret = walk_eraseregions(flash, k, &erase_and_write_block_helper, curcontents, newcontents);<br>
                msg_cdbg("\n");<br>
                /* If everything is OK, don't try another erase function. */<br>
                if (!ret)<br>
                        break;<br>
        }<br>
+       /* Free the scratchpad. */<br>
+       free(curcontents);<br>
        if (!found) {<br>
                msg_cerr("ERROR: flashrom has no erase function for this flash chip.\n");<br>
                return 1;<br>
</div>@@ -1338,7 +1490,7 @@<br>
        if (ret) {<br>
                msg_cerr("FAILED!\n");<br>
        } else {<br>
-               msg_cinfo("SUCCESS.\n");<br>
+               msg_cinfo("Done.\n");<br>
        }<br>
        return ret;<br>
 }<br>
@@ -1637,6 +1789,19 @@<br>
<div class="im">                programmer_shutdown();<br>
                return ret;<br>
        }<br>
+<br>
+       oldcontents = (uint8_t *) malloc(size);<br>
+       /* Assume worst case: All bits are 0. */<br>
+       memset(oldcontents, 0x00, size);<br>
+       newcontents = (uint8_t *) malloc(size);<br>
+       /* Assume best case: All bits should be 1. */<br>
+       memset(newcontents, 0xff, size);<br>
+       /* Side effect of the assumptions above: Default write action is erase<br>
+        * because newcontents looks like a completely erased chip, and<br>
+        * oldcontents being completely 0x00 means we have to erase everything<br>
+        * before we can write.<br>
+        */<br>
+<br>
        if (erase_it) {<br>
                /* FIXME: Do we really want the scary warning if erase failed?<br>
                 * After all, after erase the chip is either blank or partially<br>
</div>@@ -1644,15 +1809,14 @@<br>
<div class="im">                 * so if the user wanted erase and reboots afterwards, the user<br>
                 * knows very well that booting won't work.<br>
                 */<br>
-               if (erase_flash(flash)) {<br>
+               if (erase_and_write_flash(flash, oldcontents, newcontents)) {<br>
                        emergency_help_message();<br>
-                       programmer_shutdown();<br>
-                       return 1;<br>
</div>+                       ret = 1;<br>
                }<br>
+               programmer_shutdown();<br>
+               return ret;<br>
<div class="im">        }<br>
<br>
-       newcontents = (uint8_t *) calloc(size, sizeof(char));<br>
-<br>
        if (write_it || verify_it) {<br>
                if (read_buf_from_file(newcontents, size, filename)) {<br>
                        programmer_shutdown();<br>
</div>@@ -1665,8 +1829,6 @@<br>
<div class="im"> #endif<br>
        }<br>
<br>
-       oldcontents = (uint8_t *) calloc(size, sizeof(char));<br>
-<br>
        /* Read the whole chip to be able to check whether regions need to be<br>
         * erased and to give better diagnostics in case write fails.<br>
         * The alternative would be to read only the regions which are to be<br>
</div>@@ -1686,9 +1848,9 @@<br>
<div class="im">        // ////////////////////////////////////////////////////////////<br>
<br>
        if (write_it) {<br>
-               if (erase_flash(flash)) {<br>
-                       msg_cerr("Uh oh. Erase failed. Checking if anything "<br>
-                                "changed.\n");<br>
+               if (erase_and_write_flash(flash, oldcontents, newcontents)) {<br>
+                       msg_cerr("Uh oh. Erase/write failed. Checking if "<br>
+                                "anything changed.\n");<br>
                        if (!flash->read(flash, newcontents, 0, size)) {<br>
                                if (!memcmp(oldcontents, newcontents, size)) {<br>
                                        msg_cinfo("Good. It seems nothing was "<br>
</div>@@ -1702,26 +1864,6 @@<br>
<div class="im">                        programmer_shutdown();<br>
                        return 1;<br>
                }<br>
-               msg_cinfo("Writing flash chip... ");<br>
-               ret = flash->write(flash, newcontents, 0, size);<br>
-               if (ret) {<br>
-                       msg_cerr("Uh oh. Write failed. Checking if anything "<br>
-                                "changed.\n");<br>
-                       if (!flash->read(flash, newcontents, 0, size)) {<br>
-                               if (!memcmp(oldcontents, newcontents, size)) {<br>
-                                       msg_cinfo("Good. It seems nothing was "<br>
-                                                 "changed.\n");<br>
-                                       nonfatal_help_message();<br>
-                                       programmer_shutdown();<br>
-                                       return 1;<br>
-                               }<br>
-                       }<br>
-                       emergency_help_message();<br>
-                       programmer_shutdown();<br>
-                       return 1;<br>
-               } else {<br>
-                       msg_cinfo("COMPLETE.\n");<br>
-               }<br>
        }<br>
<br>
</div>        if (verify_it) {<br>
<div><div></div><div class="h5"><br>
<br>
--<br>
<a href="http://www.hailfinger.org/" target="_blank">http://www.hailfinger.org/</a><br>
<br>
<br>
_______________________________________________<br>
flashrom mailing list<br>
<a href="mailto:flashrom@flashrom.org">flashrom@flashrom.org</a><br>
<a href="http://www.flashrom.org/mailman/listinfo/flashrom" target="_blank">http://www.flashrom.org/mailman/listinfo/flashrom</a><br>
</div></div></blockquote></div><br>