Patchwork [7/7] atapi: introducing atapi pass through

login
register
mail settings
Submitter Ian Jackson
Date Aug. 12, 2009, 4:56 p.m.
Message ID <E1MbHTh-0007lf-BJ@mariner.uk.xensource.com>
Download mbox | patch
Permalink /patch/31229/
State Superseded
Headers show

Comments

Ian Jackson - Aug. 12, 2009, 4:56 p.m.
This patch introduces atapi pass through. The pass through code is used
by default when the underlying block device is a scsi device.

This brings one new option to the command line interface:
  -cdrom-reject-fw-upgrade
which blocks firmware upgrades by the guest.  By default these are
*allowed* which could be a security problem in some setups. See the
WRITE_BUFFER command for more details.

Signed-off-by: Alexandre Bique <alexandre.bique@citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
---
 Makefile.target |    9 +++--
 hw/ide.c        |   31 +++++++---------
 hw/ide.h        |  104 ++++++++++++++++++++++++++++++++++++++++++++++---------
 qemu-options.hx |    7 ++++
 sysemu.h        |    1 +
 vl.c            |    6 +++
 6 files changed, 121 insertions(+), 37 deletions(-)

Patch

diff --git a/Makefile.target b/Makefile.target
index 3f5d24a..a035e64 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -184,6 +184,7 @@  obj-y += wdt_ib700.o wdt_i6300esb.o
 
 # Hardware support
 obj-i386-y = ide.o pckbd.o vga.o $(sound-obj-y) dma.o isa-bus.o
+obj-i386-y += atapi-pt.o atapi-data.o
 obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
 obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
 obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
@@ -191,6 +192,7 @@  obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o
 
 # shared objects
 obj-ppc-y = ppc.o ide.o vga.o $(sound-obj-y) dma.o isa-bus.o openpic.o
+obj-ppc-y += atapi-pt.o atapi-data.o
 # PREP target
 obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o
 obj-ppc-y += prep_pci.o ppc_prep.o
@@ -212,6 +214,7 @@  obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o
 obj-mips-y += g364fb.o jazz_led.o dp8393x.o
 obj-mips-y += ide.o gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
+obj-mips-y += atapi-pt.o atapi-data.o
 obj-mips-y += piix_pci.o parallel.o cirrus_vga.o isa-bus.o pcspk.o $(sound-obj-y)
 obj-mips-y += mipsnet.o
 obj-mips-y += pflash_cfi01.o
@@ -242,7 +245,7 @@  obj-cris-y += etraxfs_ser.o
 obj-cris-y += pflash_cfi02.o
 
 ifeq ($(TARGET_ARCH), sparc64)
-obj-sparc-y = sun4u.o ide.o isa-bus.o pckbd.o vga.o apb_pci.o
+obj-sparc-y = sun4u.o ide.o atapi-pt.o atapi-data.o isa-bus.o pckbd.o vga.o apb_pci.o
 obj-sparc-y += fdc.o mc146818rtc.o serial.o
 obj-sparc-y += cirrus_vga.o parallel.o
 else
@@ -261,7 +264,7 @@  obj-arm-y += arm-semi.o
 obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
 obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
 obj-arm-y += pflash_cfi01.o gumstix.o
-obj-arm-y += zaurus.o ide.o serial.o spitz.o tosa.o tc6393xb.o
+obj-arm-y += zaurus.o ide.o atapi-pt.o atapi-data.o serial.o spitz.o tosa.o tc6393xb.o
 obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
 obj-arm-y += omap2.o omap_dss.o soc_dma.o
 obj-arm-y += omap_sx1.o palm.o tsc210x.o
@@ -275,7 +278,7 @@  obj-arm-y += syborg_virtio.o
 
 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
-obj-sh4-y += ide.o
+obj-sh4-y += ide.o atapi-pt.o atapi-data.o
 
 obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
 obj-m68k-y += m68k-semi.o dummy_m68k.o
diff --git a/hw/ide.c b/hw/ide.c
index 83d7acc..78c0d79 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -22,21 +22,8 @@ 
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "hw.h"
-#include "pc.h"
-#include "pci.h"
-#include "scsi-disk.h"
-#include "pcmcia.h"
-#include "block.h"
-#include "block_int.h"
-#include "qemu-timer.h"
-#include "sysemu.h"
-#include "ppc_mac.h"
-#include "mac_dbdma.h"
-#include "sh.h"
-#include "dma.h"
 #include "ide.h"
-#include "atapi-defines.h"
+#include "atapi-pt.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
@@ -44,6 +31,7 @@ 
 //#define DEBUG_AIO
 #define USE_DMA_CDROM
 
+
 /* XXX: DVDs that could fit on a CD will be reported as a CD */
 static inline int media_present(IDEState *s)
 {
@@ -62,7 +50,6 @@  static inline int media_is_cd(IDEState *s)
 
 static void ide_dma_restart(IDEState *s);
 static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
-static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc);
 
 static void padstr(char *str, const char *src, int len)
 {
@@ -1978,7 +1965,7 @@  static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             /* ATAPI commands */
         case WIN_PIDENTIFY:
             if (s->is_cdrom) {
-                ide_atapi_identify(s);
+                s->atapi_identify(s);
                 s->status = READY_STAT | SEEK_STAT;
                 ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
             } else {
@@ -2016,7 +2003,7 @@  static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             s->atapi_dma = s->feature & 1;
             s->nsector = 1;
             ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
-                               ide_atapi_cmd);
+                               s->atapi_cmd);
             break;
         /* CF-ATA commands */
         case CFA_REQ_EXT_ERROR_CODE:
@@ -2355,6 +2342,16 @@  static void ide_init2(IDEState *ide_state,
 
             if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
                 s->is_cdrom = 1;
+                if (!bdrv_is_sg(s->bs)) {
+                    s->atapi_cmd = ide_atapi_cmd;
+                    s->atapi_identify = ide_atapi_identify;
+                }
+#if CONFIG_ATAPI_PT
+                else {
+                    s->atapi_cmd = ide_atapi_pt_cmd;
+                    s->atapi_identify = ide_atapi_pt_identify;
+                }
+#endif /* CONFIG_ATAPI_PT */
 		bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
             }
         }
diff --git a/hw/ide.h b/hw/ide.h
index 2c24e08..ffefeb1 100644
--- a/hw/ide.h
+++ b/hw/ide.h
@@ -40,7 +40,20 @@ 
 #include "dma.h"
 #include "atapi-defines.h"
 
+
 #include <stdint.h>
+#include <limits.h>
+#include <asm/byteorder.h>
+#include <assert.h>
+
+#ifdef __linux__
+# include <linux/hdreg.h>
+# define CONFIG_ATAPI_PT 1
+#else
+# define CONFIG_ATAPI_PT 0
+#endif /* __linux__ */
+
+#include <scsi/sg.h>
 
 /* Bits of HD_STATUS */
 #define ERR_STAT		0x01
@@ -419,6 +432,50 @@  struct IDEState;
 
 typedef void EndTransferFunc(struct IDEState *);
 
+typedef struct request_sense {
+#if defined(__BIG_ENDIAN_BITFIELD)
+    uint8_t valid      : 1;
+    uint8_t error_code : 7;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+    uint8_t error_code : 7;
+    uint8_t valid      : 1;
+#endif
+    uint8_t segment_number;
+#if defined(__BIG_ENDIAN_BITFIELD)
+    uint8_t reserved1 : 2;
+    uint8_t ili       : 1;
+    uint8_t reserved2 : 1;
+    uint8_t sense_key : 4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+    uint8_t sense_key : 4;
+    uint8_t reserved2 : 1;
+    uint8_t ili       : 1;
+    uint8_t reserved1 : 2;
+#endif
+    uint8_t information[4];
+    uint8_t add_sense_len;
+    uint8_t command_info[4];
+    uint8_t asc;
+    uint8_t ascq;
+    uint8_t fruc;
+    uint8_t sks[3];
+    uint8_t asb[46];
+} request_sense;
+
+#if CONFIG_ATAPI_PT
+typedef struct ATAPIPassThroughState
+{
+    uint8_t              request[ATAPI_PACKET_SIZE];
+    struct sg_io_hdr     cmd;
+    struct request_sense sense;
+    void                 (*cmd_sent)(struct IDEState *);
+
+    uint32_t             reply_size_init;   // initial value
+    uint32_t             reply_size_offset; // offset in s->io_buffer
+    uint32_t             reply_size_len;    // length in byte (0, 1, 2, 3 or 4)
+} ATAPIPassThroughState;
+#endif /* CONFIG_ATAPI_PT */
+
 /* NOTE: IDEState represents in fact one drive */
 typedef struct IDEState {
     /* ide config */
@@ -468,6 +525,11 @@  typedef struct IDEState {
     int lba;
     int cd_sector_size;
     int atapi_dma; /* true if dma is requested for the packet cmd */
+#if CONFIG_ATAPI_PT
+    ATAPIPassThroughState atapi_pt;
+#endif /* CONFIG_ATAPI_PT */
+    void (*atapi_identify)(struct IDEState *); // the ATAPI identify
+    void (*atapi_cmd)(struct IDEState *); // the ATAPI cmd handler
     /* ATA DMA state */
     int io_buffer_size;
     QEMUSGList sg;
@@ -489,27 +551,27 @@  typedef struct IDEState {
     int is_read;
 } IDEState;
 
-#define BM_STATUS_DMAING 0x01
-#define BM_STATUS_ERROR  0x02
-#define BM_STATUS_INT    0x04
-#define BM_STATUS_DMA_RETRY  0x08
-#define BM_STATUS_PIO_RETRY  0x10
+#define BM_STATUS_DMAING        0x01
+#define BM_STATUS_ERROR         0x02
+#define BM_STATUS_INT           0x04
+#define BM_STATUS_DMA_RETRY     0x08
+#define BM_STATUS_PIO_RETRY     0x10
 
-#define BM_CMD_START     0x01
-#define BM_CMD_READ      0x08
+#define BM_CMD_START            0x01
+#define BM_CMD_READ             0x08
 
-#define IDE_TYPE_PIIX3   0
-#define IDE_TYPE_CMD646  1
-#define IDE_TYPE_PIIX4   2
+#define IDE_TYPE_PIIX3          0
+#define IDE_TYPE_CMD646         1
+#define IDE_TYPE_PIIX4          2
 
 /* CMD646 specific */
-#define MRDMODE		0x71
-#define   MRDMODE_INTR_CH0	0x04
-#define   MRDMODE_INTR_CH1	0x08
-#define   MRDMODE_BLK_CH0	0x10
-#define   MRDMODE_BLK_CH1	0x20
-#define UDIDETCR0	0x73
-#define UDIDETCR1	0x7B
+#define MRDMODE                 0x71
+#define MRDMODE_INTR_CH0	0x04
+#define MRDMODE_INTR_CH1	0x08
+#define MRDMODE_BLK_CH0         0x10
+#define MRDMODE_BLK_CH1         0x20
+#define UDIDETCR0               0x73
+#define UDIDETCR1               0x7B
 
 typedef struct BMDMAState {
     uint8_t cmd;
@@ -569,6 +631,14 @@  static inline int ube16_to_cpu(const uint8_t *buf)
     return (buf[0] << 8) | buf[1];
 }
 
+#if CONFIG_ATAPI_PT /* only atapi-pt uses it so let's avoid unused
+                            * warning */
+static inline int ube24_to_cpu(const uint8_t *buf)
+{
+    return (buf[0] << 16) | (buf[1] << 8) | buf[2];
+}
+#endif /* CONFIG_ATAPI_PT */
+
 static inline int ube32_to_cpu(const uint8_t *buf)
 {
     return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
diff --git a/qemu-options.hx b/qemu-options.hx
index 38989f1..4992bf9 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -91,6 +91,13 @@  Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and
 using @file{/dev/cdrom} as filename (@pxref{host_drives}).
 ETEXI
 
+DEF("cdrom-reject-fw-upgrade", 0, QEMU_OPTION_cdrom_reject_fw_upgrade,
+    "-cdrom-reject-fw-upgrade     prevent the guest from upgrading cdrom firmware.\n")
+STEXI
+@item -cdrom-reject-fw-upgrade
+Prevent Qemu from passing through ATAPI firmware upgrade command.
+ETEXI
+
 DEF("drive", HAS_ARG, QEMU_OPTION_drive,
     "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
     "       [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
diff --git a/sysemu.h b/sysemu.h
index dffb2f1..9904c82 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -122,6 +122,7 @@  extern int no_quit;
 extern int semihosting_enabled;
 extern int old_param;
 extern int boot_menu;
+extern int atapi_pt_reject_fw_upgrade;
 
 #ifdef CONFIG_KQEMU
 extern int kqemu_allowed;
diff --git a/vl.c b/vl.c
index 8b2b289..28cd424 100644
--- a/vl.c
+++ b/vl.c
@@ -142,6 +142,7 @@  int main(int argc, char **argv)
 #include "hw/smbios.h"
 #include "hw/xen.h"
 #include "hw/qdev.h"
+#include "hw/atapi-pt.h"
 #include "bt-host.h"
 #include "net.h"
 #include "monitor.h"
@@ -248,6 +249,7 @@  unsigned int nb_prom_envs = 0;
 const char *prom_envs[MAX_PROM_ENVS];
 #endif
 int boot_menu;
+int atapi_pt_reject_fw_upgrade;
 
 int nb_numa_nodes;
 uint64_t node_mem[MAX_NODES];
@@ -1793,6 +1795,7 @@  static int bt_parse(const char *opt)
 
 #define HD_ALIAS "index=%d,media=disk"
 #define CDROM_ALIAS "index=2,media=cdrom"
+#define CDROM_PT_ALIAS "index=2,media=cdrompt"
 #define FD_ALIAS "index=%d,if=floppy"
 #define PFLASH_ALIAS "if=pflash"
 #define MTD_ALIAS "if=mtd"
@@ -5068,6 +5071,9 @@  int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_cdrom:
                 drive_add(optarg, CDROM_ALIAS);
                 break;
+            case QEMU_OPTION_cdrom_reject_fw_upgrade:
+                atapi_pt_reject_fw_upgrade = 1;
+                break;
             case QEMU_OPTION_boot:
                 {
                     static const char * const params[] = {