From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:40065) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qm6BU-00025Q-9J for qemu-devel@nongnu.org; Wed, 27 Jul 2011 11:38:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Qm6BS-0006op-LI for qemu-devel@nongnu.org; Wed, 27 Jul 2011 11:38:08 -0400 Received: from mail-gw0-f45.google.com ([74.125.83.45]:55865) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qm6BS-0006oY-GU for qemu-devel@nongnu.org; Wed, 27 Jul 2011 11:38:06 -0400 Received: by gwb19 with SMTP id 19so1356610gwb.4 for ; Wed, 27 Jul 2011 08:38:05 -0700 (PDT) MIME-Version: 1.0 In-Reply-To: <4E2FDAB0.8080404@siemens.com> References: <1311629692-5734-1-git-send-email-jordan.l.justen@intel.com> <4E2FDAB0.8080404@siemens.com> Date: Wed, 27 Jul 2011 08:38:05 -0700 Message-ID: From: Jordan Justen Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [PATCH 1/2] pflash: Support read-only mode List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Jan Kiszka Cc: Jordan Justen , Anthony Liguori , "qemu-devel@nongnu.org" , Aurelien Jarno On Wed, Jul 27, 2011 at 02:30, Jan Kiszka wrote: > On 2011-07-25 23:34, Jordan Justen wrote: >> Read-only mode is indicated by bdrv_is_read_only >> >> When read-only mode is enabled, no changes will be made >> to the flash image in memory, and no bdrv_write calls will be >> made. >> >> Signed-off-by: Jordan Justen >> Cc: Jan Kiszka >> Cc: Aurelien Jarno >> Cc: Anthony Liguori >> --- >> =A0blockdev.c =A0 =A0 =A0 =A0| =A0 =A03 +- >> =A0hw/pflash_cfi01.c | =A0 36 ++++++++++++++--------- >> =A0hw/pflash_cfi02.c | =A0 82 ++++++++++++++++++++++++++++--------------= ---------- >> =A03 files changed, 68 insertions(+), 53 deletions(-) >> >> diff --git a/blockdev.c b/blockdev.c >> index 0b8d3a4..566a502 100644 >> --- a/blockdev.c >> +++ b/blockdev.c >> @@ -521,7 +521,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to= _scsi) >> =A0 =A0 =A0 =A0 =A0/* CDROM is fine for any interface, don't check. =A0*= / >> =A0 =A0 =A0 =A0 =A0ro =3D 1; >> =A0 =A0 =A0} else if (ro =3D=3D 1) { >> - =A0 =A0 =A0 =A0if (type !=3D IF_SCSI && type !=3D IF_VIRTIO && type != =3D IF_FLOPPY && type !=3D IF_NONE) { >> + =A0 =A0 =A0 =A0if (type !=3D IF_SCSI && type !=3D IF_VIRTIO && type != =3D IF_FLOPPY && >> + =A0 =A0 =A0 =A0 =A0 =A0type !=3D IF_NONE && type !=3D IF_PFLASH) { >> =A0 =A0 =A0 =A0 =A0 =A0 =A0error_report("readonly not supported by this = bus type"); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0goto err; >> =A0 =A0 =A0 =A0 =A0} >> diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c >> index 90fdc84..11ac490 100644 >> --- a/hw/pflash_cfi01.c >> +++ b/hw/pflash_cfi01.c >> @@ -284,8 +284,10 @@ static void pflash_write(pflash_t *pfl, target_phys= _addr_t offset, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0TARGET_FMT_plx "\n", >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0__func__, offset, pfl->sector= _len); >> >> - =A0 =A0 =A0 =A0 =A0 =A0memset(p + offset, 0xff, pfl->sector_len); >> - =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, pfl->sector_len); >> + =A0 =A0 =A0 =A0 =A0 =A0if (!pfl->ro) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0memset(p + offset, 0xff, pfl->sector_le= n); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, pfl->sector_= len); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->status |=3D 0x80; /* Ready! */ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> =A0 =A0 =A0 =A0 =A0case 0x50: /* Clear status bits */ >> @@ -324,8 +326,10 @@ static void pflash_write(pflash_t *pfl, target_phys= _addr_t offset, >> =A0 =A0 =A0 =A0 =A0case 0x10: /* Single Byte Program */ >> =A0 =A0 =A0 =A0 =A0case 0x40: /* Single Byte Program */ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: Single Byte Program\n", __func__= ); >> - =A0 =A0 =A0 =A0 =A0 =A0pflash_data_write(pfl, offset, value, width, be= ); >> - =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, width); >> + =A0 =A0 =A0 =A0 =A0 =A0if (!pfl->ro) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_data_write(pfl, offset, value, w= idth, be); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, width); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->status |=3D 0x80; /* Ready! */ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->wcycle =3D 0; >> =A0 =A0 =A0 =A0 =A0break; >> @@ -373,7 +377,9 @@ static void pflash_write(pflash_t *pfl, target_phys_= addr_t offset, >> =A0 =A0 =A0case 2: >> =A0 =A0 =A0 =A0 =A0switch (pfl->cmd) { >> =A0 =A0 =A0 =A0 =A0case 0xe8: /* Block write */ >> - =A0 =A0 =A0 =A0 =A0 =A0pflash_data_write(pfl, offset, value, width, be= ); >> + =A0 =A0 =A0 =A0 =A0 =A0if (!pfl->ro) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_data_write(pfl, offset, value, w= idth, be); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->status |=3D 0x80; >> >> @@ -383,8 +389,10 @@ static void pflash_write(pflash_t *pfl, target_phys= _addr_t offset, >> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: block write finished\n",= __func__); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->wcycle++; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Flush the entire write buffer onto b= acking storage. =A0*/ >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset & mask, pfl->= writeblock_size); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (!pfl->ro) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Flush the entire write buffe= r onto backing storage. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset & mas= k, pfl->writeblock_size); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->counter--; >> @@ -621,13 +629,13 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t= base, ram_addr_t off, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0return NULL; >> =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0} >> -#if 0 /* XXX: there should be a bit to set up read-only, >> - =A0 =A0 =A0 * =A0 =A0 =A0the same way the hardware does (with WP pin). >> - =A0 =A0 =A0 */ >> - =A0 =A0pfl->ro =3D 1; >> -#else >> - =A0 =A0pfl->ro =3D 0; >> -#endif >> + >> + =A0 =A0if (pfl->bs) { >> + =A0 =A0 =A0 =A0pfl->ro =3D bdrv_is_read_only(pfl->bs); >> + =A0 =A0} else { >> + =A0 =A0 =A0 =A0pfl->ro =3D 0; >> + =A0 =A0} >> + >> =A0 =A0 =A0pfl->timer =3D qemu_new_timer_ns(vm_clock, pflash_timer, pfl)= ; >> =A0 =A0 =A0pfl->base =3D base; >> =A0 =A0 =A0pfl->sector_len =3D sector_len; >> diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c >> index 725cd1e..920209d 100644 >> --- a/hw/pflash_cfi02.c >> +++ b/hw/pflash_cfi02.c >> @@ -315,35 +315,37 @@ static void pflash_write (pflash_t *pfl, target_ph= ys_addr_t offset, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: write data offset " TARGET_FMT_p= lx " %08x %d\n", >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0__func__, offset, value, widt= h); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0p =3D pfl->storage; >> - =A0 =A0 =A0 =A0 =A0 =A0switch (width) { >> - =A0 =A0 =A0 =A0 =A0 =A0case 1: >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset] &=3D value; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, 1); >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> - =A0 =A0 =A0 =A0 =A0 =A0case 2: >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (be) { >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset] &=3D value >> 8; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 1] &=3D value; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} else { >> + =A0 =A0 =A0 =A0 =A0 =A0if (!pfl->ro) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0switch (width) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0case 1: >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset] &=3D value; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 1] &=3D value >> 8; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, 1); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0case 2: >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (be) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset] &=3D value >>= 8; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 1] &=3D valu= e; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} else { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset] &=3D value; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 1] &=3D valu= e >> 8; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, 2); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0case 4: >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (be) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset] &=3D value >>= 24; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 1] &=3D valu= e >> 16; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 2] &=3D valu= e >> 8; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 3] &=3D valu= e; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} else { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset] &=3D value; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 1] &=3D valu= e >> 8; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 2] &=3D valu= e >> 16; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 3] &=3D valu= e >> 24; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, 4); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, 2); >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> - =A0 =A0 =A0 =A0 =A0 =A0case 4: >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (be) { >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset] &=3D value >> 24; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 1] &=3D value >> 16; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 2] &=3D value >> 8; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 3] &=3D value; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} else { >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset] &=3D value; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 1] &=3D value >> 8; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 2] &=3D value >> 16; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p[offset + 3] &=3D value >> 24; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, 4); >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->status =3D 0x00 | ~(value & 0x80); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Let's pretend write is immediate */ >> @@ -389,9 +391,11 @@ static void pflash_write (pflash_t *pfl, target_phy= s_addr_t offset, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Chip erase */ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: start chip erase\n", __func__); >> - =A0 =A0 =A0 =A0 =A0 =A0memset(pfl->storage, 0xFF, pfl->chip_len); >> + =A0 =A0 =A0 =A0 =A0 =A0if (!pfl->ro) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0memset(pfl->storage, 0xFF, pfl->chip_le= n); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, 0, pfl->chip_len); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->status =3D 0x00; >> - =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, 0, pfl->chip_len); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Let's wait 5 seconds before chip erase is = done */ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0qemu_mod_timer(pfl->timer, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qemu_get_clock_n= s(vm_clock) + (get_ticks_per_sec() * 5)); >> @@ -402,8 +406,10 @@ static void pflash_write (pflash_t *pfl, target_phy= s_addr_t offset, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0offset &=3D ~(pfl->sector_len - 1); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: start sector erase at " TARGET_F= MT_plx "\n", __func__, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0offset); >> - =A0 =A0 =A0 =A0 =A0 =A0memset(p + offset, 0xFF, pfl->sector_len); >> - =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, pfl->sector_len); >> + =A0 =A0 =A0 =A0 =A0 =A0if (!pfl->ro) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0memset(p + offset, 0xFF, pfl->sector_le= n); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, pfl->sector_= len); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->status =3D 0x00; >> =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Let's wait 1/2 second before sector erase = is done */ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0qemu_mod_timer(pfl->timer, >> @@ -644,13 +650,13 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t= base, ram_addr_t off, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0return NULL; >> =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0} >> -#if 0 /* XXX: there should be a bit to set up read-only, >> - =A0 =A0 =A0 * =A0 =A0 =A0the same way the hardware does (with WP pin). >> - =A0 =A0 =A0 */ >> - =A0 =A0pfl->ro =3D 1; >> -#else >> - =A0 =A0pfl->ro =3D 0; >> -#endif >> + >> + =A0 =A0if (pfl->bs) { >> + =A0 =A0 =A0 =A0pfl->ro =3D bdrv_is_read_only(pfl->bs); >> + =A0 =A0} else { >> + =A0 =A0 =A0 =A0pfl->ro =3D 0; >> + =A0 =A0} >> + >> =A0 =A0 =A0pfl->timer =3D qemu_new_timer_ns(vm_clock, pflash_timer, pfl)= ; >> =A0 =A0 =A0pfl->sector_len =3D sector_len; >> =A0 =A0 =A0pfl->width =3D width; > > Looks good in general. I'm just wondering if real hw gives any feedback > on writes to flashes in read-only mode or silently ignores them as > above? Or am I missing the feedback bits? I have the same concern. Unfortunately, I don't have access to real hardware to investigate. I tried looking for something in the CFI specification, but I found no guidance there. -Jordan