From: Jack Lange Date: Wed, 18 Mar 2009 17:16:05 +0000 (-0500) Subject: initial commit of IDE layer X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=bb102eef875adf3e667e4e3ffe7e6412b167b14e initial commit of IDE layer --- diff --git a/palacios/build/Makefile b/palacios/build/Makefile index de62095..ebd751b 100644 --- a/palacios/build/Makefile +++ b/palacios/build/Makefile @@ -63,7 +63,7 @@ endif ifeq ($(DEBUG_ALL),1) DEBUG_SECTIONS:= $(DEBUG_SECTIONS) -DDEBUG_SHADOW_PAGING -DDEBUG_CTRL_REGS -DDEBUG_INTERRUPTS -DDEBUG_KEYBOARD -DDEBUG_PIC -DDEBUG_PIT -DDEBUG_NVRAM -DDEBUG_EMULATOR -DDEBUG_XED -DDEBUG_HALT -DDEBUG_DEV_MGR -# -DDEBUG_IO -DDEBUG_GENERIC -DDEBUG_RAMDISK +# -DDEBUG_IO -DDEBUG_GENERIC -DDEBUG_IDE endif @@ -147,19 +147,11 @@ DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_EMULATOR endif endif -ifeq ($(DEBUG_RAMDISK),1) -DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DDEBUG_RAMDISK +ifeq ($(DEBUG_IDE),1) +DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DDEBUG_IDE else -ifeq ($(DEBUG_RAMDISK),0) -DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_RAMDISK -endif -endif - -ifeq ($(TRACE_RAMDISK),1) -DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DTRACE_RAMDISK -else -ifeq ($(TRACE_RAMDSK),0) -DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UTRACE_RAMDISK +ifeq ($(DEBUG_IDE),0) +DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_IDE endif endif @@ -322,15 +314,17 @@ DEVICES_OBJS := \ devices/8259a.o \ devices/8254.o \ devices/serial.o \ - devices/ramdisk.o \ - devices/cdrom.o \ devices/bochs_debug.o \ devices/os_debug.o \ devices/apic.o \ devices/io_apic.o \ devices/pci.o \ devices/para_net.o \ + devices/ide.o \ + +# devices/cdrom.o \ +# devices/ramdisk.o \ # devices/vnic.o \ $(DEVICES_OBJS) :: EXTRA_CFLAGS = \ diff --git a/palacios/include/devices/ide.h b/palacios/include/devices/ide.h index b667a03..ee6f2c5 100644 --- a/palacios/include/devices/ide.h +++ b/palacios/include/devices/ide.h @@ -1,242 +1,30 @@ /* - * Copyright (C) 2002 MandrakeSoft S.A. + * This file is part of the Palacios Virtual Machine Monitor developed + * by the V3VEE Project with funding from the United States National + * Science Foundation and the Department of Energy. * - * MandrakeSoft S.A. - * 43, rue d'Aboukir - * 75002 Paris - France - * http://www.linux-mandrake.com/ - * http://www.mandrakesoft.com/ - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Major modifications made for the V3VEE project - * * The V3VEE Project is a joint project between Northwestern University * and the University of New Mexico. You can find out more at * http://www.v3vee.org - * - * Copyright (c) 2008, Zheng Cui - * Copyright (c) 2008, Jack Lange + * + * Copyright (c) 2008, Jack Lange * Copyright (c) 2008, The V3VEE Project - * All rights reserved for original changes - * + * All rights reserved. + * + * Author: Jack Lange + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". */ #ifndef __DEVICES_IDE_H__ #define __DEVICES_IDE_H__ #ifdef __V3VEE__ - - -#include #include -typedef long off_t; -typedef sint32_t ssize_t; -typedef unsigned int rd_bool; -typedef uchar_t Bit8u; -typedef ushort_t Bit16u; -typedef uint32_t Bit32u; -typedef uint64_t Bit64u; - - - -#define MAX_ATA_CHANNEL 4 - -typedef enum _sense { - SENSE_NONE = 0, - SENSE_NOT_READY = 2, - SENSE_ILLEGAL_REQUEST = 5, - SENSE_UNIT_ATTENTION = 6 -} sense_t ; - -typedef enum _asc { - ASC_INV_FIELD_IN_CMD_PACKET = 0x24, - ASC_MEDIUM_NOT_PRESENT = 0x3a, - ASC_SAVING_PARAMETERS_NOT_SUPPORTED = 0x39, - ASC_LOGICAL_BLOCK_OOR = 0x21 -} asc_t ; - - - -typedef struct { - unsigned cylinders; - unsigned heads; - unsigned sectors; -} device_image_t; - - - - -struct interrupt_reason_t { - unsigned c_d : 1; - unsigned i_o : 1; - unsigned rel : 1; - unsigned tag : 5; -}; - - -struct controller_status { - rd_bool busy; - rd_bool drive_ready; - rd_bool write_fault; - rd_bool seek_complete; - rd_bool drq; - rd_bool corrected_data; - rd_bool index_pulse; - unsigned int index_pulse_count; - rd_bool err; -}; - - - - - -struct sense_info_t { - sense_t sense_key; - - struct { - Bit8u arr[4]; - } information; - - struct { - Bit8u arr[4]; - } specific_inf; - - struct { - Bit8u arr[3]; - } key_spec; - - Bit8u fruc; - Bit8u asc; - Bit8u ascq; -}; - - -struct error_recovery_t { - unsigned char data[8]; -}; - -struct cdrom_t { - rd_bool ready; - rd_bool locked; - - struct cdrom_ops * cd; - - uint32_t capacity; - int next_lba; - int remaining_blocks; - - struct currentStruct { - struct error_recovery_t error_recovery; - } current; - -}; - -struct atapi_t { - uint8_t command; - int drq_bytes; - int total_bytes_remaining; -}; - - -typedef enum { IDE_NONE, IDE_DISK, IDE_CDROM } device_type_t; - -struct controller_t { - struct controller_status status; - Bit8u error_register; - Bit8u head_no; - - union { - Bit8u sector_count; - struct interrupt_reason_t interrupt_reason; - }; - - - Bit8u sector_no; - - union { - Bit16u cylinder_no; - Bit16u byte_count; - }; - - Bit8u buffer[2048]; - Bit32u buffer_index; - Bit32u drq_index; - Bit8u current_command; - Bit8u sectors_per_block; - Bit8u lba_mode; - - struct vm_device * pci; - - struct { - rd_bool reset; // 0=normal, 1=reset controller - rd_bool disable_irq; // 0=allow irq, 1=disable irq - } control; - - Bit8u reset_in_progress; - Bit8u features; -}; - - - - -struct drive_t { - device_image_t hard_drive; - device_type_t device_type; - // 512 byte buffer for ID drive command - // These words are stored in native word endian format, as - // they are fetched and returned via a return(), so - // there's no need to keep them in x86 endian format. - Bit16u id_drive[256]; - - struct controller_t controller; - struct cdrom_t cdrom; - struct sense_info_t sense; - struct atapi_t atapi; - - /* JRL */ - void * private_data; - - Bit8u model_no[41]; -}; - - -// FIXME: -// For each ATA channel we should have one controller struct -// and an array of two drive structs -struct channel_t { - struct drive_t drives[2]; - unsigned drive_select; - - Bit16u ioaddr1; - Bit16u ioaddr2; - Bit8u irq; -}; - - - -struct ramdisk_t { - struct channel_t channels[MAX_ATA_CHANNEL]; -}; - - - - - +struct vm_device * v3_create_ide(); @@ -245,29 +33,3 @@ struct ramdisk_t { #endif -#if 0 - -// FLAT MODE -// Open a image. Returns non-negative if successful. -//int open (const char* pathname); - -// Open an image with specific flags. Returns non-negative if successful. -int rd_open (const char* pathname, int flags); - -// Close the image. -void rd_close (); - -// Position ourselves. Return the resulting offset from the -// beginning of the file. -off_t rd_lseek (off_t offset, int whence); - -// Read count bytes to the buffer buf. Return the number of -// bytes read (count). -ssize_t rd_read (void* buf, size_t count); - -// Write count bytes from buf. Return the number of bytes -// written (count). -ssize_t rd_write (const void* buf, size_t count); - - -#endif diff --git a/palacios/src/devices/ide-types.h b/palacios/src/devices/ide-types.h new file mode 100644 index 0000000..5509a96 --- /dev/null +++ b/palacios/src/devices/ide-types.h @@ -0,0 +1,108 @@ +/* + * This file is part of the Palacios Virtual Machine Monitor developed + * by the V3VEE Project with funding from the United States National + * Science Foundation and the Department of Energy. + * + * The V3VEE Project is a joint project between Northwestern University + * and the University of New Mexico. You can find out more at + * http://www.v3vee.org + * + * Copyright (c) 2008, Jack Lange + * Copyright (c) 2008, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + + +#ifndef __DEVICES_IDE_TYPES_H__ +#define __DEVICES_IDE_TYPES_H__ + +#ifdef __V3VEE__ + +#include + + +struct ide_error_reg { + union { + uint8_t val; + struct { + uint_t addr_mark_nf : 1; + uint_t track0_nf : 1; + uint_t abort : 1; + uint_t rsvd0 : 1; + uint_t ID_nf : 1; + uint_t rsvd1 : 1; + uint_t data_error : 1; + uint_t bad_block : 1; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + + +struct ide_drive_head_reg { + union { + uint8_t val; + struct { + uint_t head_num : 4; + uint_t drive_sel : 1; + uint_t rsvd1 : 1; + uint_t lba_mode : 1; + uint_t rsvd2 : 1; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + +struct ide_status_reg { + union { + uint8_t val; + struct { + uint_t error : 1; + uint_t index : 1; + uint_t corrected : 1; + uint_t data_req : 1; + uint_t seek_complete : 1; + uint_t write_fault : 1; + uint_t ready : 1; + uint_t busy : 1; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + + +struct ide_drive_ctrl_reg { + union { + uint8_t val; + struct { + uint_t rsvd0 : 1; + uint_t irq_enable : 1; + uint_t soft_reset : 1; + uint_t rsvd1 : 5; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + + + +typedef enum { + READ_SECT_W_RETRY = 0x20, + READ_SECT = 0x21, + READ_LONG_W_RETRY = 0x22, + READ_LONG = 0x23, + READ_VRFY_SECT_W_RETRY = 0x40, + READ_VRFY_SECT = 0x41, + FORMAT_TRACK = 0x50, + EXEC_DRV_DIAG = 0x90, + INIT_DRIVE_PARAM = 0x91, + +} ide_cmd_t; + + + + +#endif // ! __V3VEE__ + +#endif diff --git a/palacios/src/devices/ide.c b/palacios/src/devices/ide.c new file mode 100644 index 0000000..283d699 --- /dev/null +++ b/palacios/src/devices/ide.c @@ -0,0 +1,366 @@ +/* + * This file is part of the Palacios Virtual Machine Monitor developed + * by the V3VEE Project with funding from the United States National + * Science Foundation and the Department of Energy. + * + * The V3VEE Project is a joint project between Northwestern University + * and the University of New Mexico. You can find out more at + * http://www.v3vee.org + * + * Copyright (c) 2008, Jack Lange + * Copyright (c) 2008, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + +#include +#include +#include "ide-types.h" + + + +#define PRI_DATA_PORT 0x1f0 +#define PRI_FEATURES_PORT 0x1f1 +#define PRI_SECT_CNT_PORT 0x1f2 +#define PRI_SECT_NUM_PORT 0x1f3 +#define PRI_CYL_LOW_PORT 0x1f4 +#define PRI_CYL_HIGH_PORT 0x1f5 +#define PRI_DRV_SEL_PORT 0x1f6 +#define PRI_CMD_PORT 0x1f7 +#define PRI_CTRL_PORT 0x3f6 +#define PRI_ADDR_REG_PORT 0x3f7 + +#define SEC_DATA_PORT 0x170 +#define SEC_FEATURES_PORT 0x171 +#define SEC_SECT_CNT_PORT 0x172 +#define SEC_SECT_NUM_PORT 0x173 +#define SEC_CYL_LOW_PORT 0x174 +#define SEC_CYL_HIGH_PORT 0x175 +#define SEC_DRV_SEL_PORT 0x176 +#define SEC_CMD_PORT 0x177 +#define SEC_CTRL_PORT 0x376 +#define SEC_ADDR_REG_PORT 0x377 + + +typedef enum {IDE_DISK, IDE_CDROM, IDE_NONE} ide_dev_type_t; +static const char * ide_dev_type_strs[] = {"HARDDISK", "CDROM", "NONE"}; + + +static inline const char * device_type_to_str(ide_dev_type_t type) { + if (type > 2) { + return NULL; + } + + return ide_dev_type_strs[type]; +} + + + + + +struct ide_drive { + // Command Registers + uint8_t data_port; // 0x1f0,0x170 + struct ide_error_reg error_reg; // [read] 0x1f1,0x171 + uint8_t sector_count; // 0x1f2,0x172 + uint8_t sector_num; // 0x1f3,0x173 + + union { + uint16_t cylinder; + struct { + uint8_t cylinder_low; // 0x1f4,0x174 + uint8_t cylinder_high; // 0x1f5,0x175 + } __attribute__((packed)); + } __attribute__((packed)); + + struct ide_drive_head_reg drive_head; // 0x1f6,0x176 + + struct ide_status_reg status; // [read] 0x1f7,0x177 + uint8_t command_reg; // [write] 0x1f7,0x177 + + + // Control Registers + struct ide_drive_ctrl_reg ctrl_reg; // [write] 0x3f6,0x376 + + + + ide_dev_type_t drive_type; + +}; + + + +struct ide_channel { + struct ide_drive drives[2]; + + int drive_sel; +}; + + + +struct ide_internal { + struct ide_channel channels[2]; +}; + + + + +static inline int get_channel_index(ushort_t port) { + if (((port & 0xfff8) == 0x1f0) || + ((port & 0xfffe) == 0x3f6)) { + return 0; + } else if (((port & 0xfff8) == 0x170) || + ((port & 0xfffe) == 0x376)) { + return 1; + } + + return -1; +} + +static inline struct ide_channel * get_selected_channel(struct ide_internal * ide, ushort_t port) { + int channel_idx = get_channel_index(port); + return &(ide->channels[channel_idx]); +} + +static inline struct ide_drive * get_selected_drive(struct ide_channel * channel) { + return &(channel->drives[channel->drive_sel]); +} + + + +static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) { + PrintDebug("IDE: Writing Command Port %x (val=%x)\n", port, *(uint8_t *)src); + return -1; +} + + +static int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) { + PrintDebug("IDE: Writing Data Port %x (val=%x)\n", port, *(uint8_t *)src); + return -1; +} + + +static int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) { + PrintDebug("IDE: Reading Data Port %x\n", port); + return -1; +} + +static int write_port_std(ushort_t port, void * src, uint_t length, struct vm_device * dev) { + PrintDebug("IDE: Writing Standard Port %x (val=%x)\n", port, *(uint8_t *)src); + return -1; +} + + +static int read_port_std(ushort_t port, void * dst, uint_t length, struct vm_device * dev) { + struct ide_internal * ide = (struct ide_internal *)(dev->private_data); + struct ide_channel * channel = get_selected_channel(ide, port); + struct ide_drive * drive = get_selected_drive(channel); + + if (length != 1) { + PrintError("Invalid Read length on IDE port %x\n", port); + return -1; + } + + PrintDebug("IDE: Reading Standard Port %x\n", port); + + + if ((port == PRI_ADDR_REG_PORT) || + (port == SEC_ADDR_REG_PORT)) { + // unused, return 0xff + *(uint8_t *)dst = 0xff; + return length; + } + + + // if no drive is present just return 0 + reserved bits + if (drive->drive_type == IDE_NONE) { + if ((port == PRI_DRV_SEL_PORT) || + (port == SEC_DRV_SEL_PORT)) { + *(uint8_t *)dst = 0xa0; + } else { + *(uint8_t *)dst = 0; + } + + return length; + } + + switch (port) { + + // This is really the error register. + case PRI_FEATURES_PORT: + case SEC_FEATURES_PORT: + *(uint8_t *)dst = drive->error_reg.val; + break; + + case PRI_SECT_CNT_PORT: + case SEC_SECT_CNT_PORT: + *(uint8_t *)dst = drive->sector_count; + break; + + case PRI_SECT_NUM_PORT: + case SEC_SECT_NUM_PORT: + *(uint8_t *)dst = drive->sector_num; + break; + + case PRI_CYL_LOW_PORT: + case SEC_CYL_LOW_PORT: + *(uint8_t *)dst = drive->cylinder_low; + break; + + + case PRI_CYL_HIGH_PORT: + case SEC_CYL_HIGH_PORT: + *(uint8_t *)dst = drive->cylinder_high; + break; + + case PRI_DRV_SEL_PORT: + case SEC_DRV_SEL_PORT: // hard disk drive and head register 0x1f6 + *(uint8_t *)dst = drive->drive_head.val; + break; + + case PRI_CTRL_PORT: + case SEC_CTRL_PORT: + case PRI_CMD_PORT: + case SEC_CMD_PORT: + // Something about lowering interrupts here.... + *(uint8_t *)dst = drive->status.val; + break; + + default: + PrintError("Invalid Port: %x\n", port); + return -1; + } + + return length; +} + + + +static void init_drive(struct ide_drive * drive) { + drive->data_port = 0x00; + drive->error_reg.val = 0x01; + drive->sector_count = 0x01; + drive->sector_num = 0x01; + drive->cylinder = 0x0000; + drive->drive_head.val = 0x00; + + drive->status.val = 0x00; + drive->command_reg = 0x00; + + drive->ctrl_reg.val = 0x08; + + drive->drive_type = IDE_NONE; + +} + +static void init_channel(struct ide_channel * channel) { + int i = 0; + + for (i = 0; i < 2; i++) { + init_drive(&(channel->drives[i])); + } + + channel->drive_sel = 0; +} + +static void init_ide_state(struct ide_internal * ide) { + int i; + + for (i = 0; i < 2; i++) { + init_channel(&(ide->channels[i])); + } +} + + + +static int init_ide(struct vm_device * dev) { + struct ide_internal * ide = (struct ide_internal *)(dev->private_data); + + PrintDebug("IDE: Initializing IDE\n"); + + init_ide_state(ide); + + + v3_dev_hook_io(dev, PRI_CTRL_PORT, + &read_port_std, &write_port_std); + + v3_dev_hook_io(dev, PRI_DATA_PORT, + &read_data_port, &write_data_port); + v3_dev_hook_io(dev, PRI_FEATURES_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, PRI_SECT_CNT_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, PRI_SECT_NUM_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, PRI_CYL_LOW_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, PRI_CYL_HIGH_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, PRI_DRV_SEL_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, PRI_CMD_PORT, + &read_port_std, &write_cmd_port); + + + v3_dev_hook_io(dev, SEC_CTRL_PORT, + &read_port_std, &write_port_std); + + v3_dev_hook_io(dev, SEC_DATA_PORT, + &read_data_port, &write_data_port); + v3_dev_hook_io(dev, SEC_FEATURES_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, SEC_SECT_CNT_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, SEC_SECT_NUM_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, SEC_CYL_LOW_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, SEC_CYL_HIGH_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, SEC_DRV_SEL_PORT, + &read_port_std, &write_port_std); + v3_dev_hook_io(dev, SEC_CMD_PORT, + &read_port_std, &write_cmd_port); + + + + v3_dev_hook_io(dev, SEC_ADDR_REG_PORT, + &read_port_std, &write_port_std); + + v3_dev_hook_io(dev, PRI_ADDR_REG_PORT, + &read_port_std, &write_port_std); + + return 0; +} + + +static int deinit_ide(struct vm_device * dev) { + // unhook io ports.... + // deregister from PCI? + return 0; +} + + +static struct vm_device_ops dev_ops = { + .init = init_ide, + .deinit = deinit_ide, + .reset = NULL, + .start = NULL, + .stop = NULL, +}; + + +struct vm_device * v3_create_ide() { + struct ide_internal * ide = (struct ide_internal *)V3_Malloc(sizeof(struct ide_internal)); + struct vm_device * device = v3_create_device("IDE", &dev_ops, ide); + + // ide->pci = pci; + + PrintDebug("IDE: Creating IDE bus x 2\n"); + + return device; +} diff --git a/palacios/src/palacios/vmm_config.c b/palacios/src/palacios/vmm_config.c index 631fe5c..38d7210 100644 --- a/palacios/src/palacios/vmm_config.c +++ b/palacios/src/palacios/vmm_config.c @@ -33,8 +33,8 @@ #include #include #include -#include -#include +#include +//#include #include #include #include @@ -277,8 +277,8 @@ static int setup_memory_map(struct guest_info * info, struct v3_vm_config * conf static int setup_devices(struct guest_info * info, struct v3_vm_config * config_ptr) { - struct vm_device * ramdisk = NULL; - struct vm_device * cdrom = NULL; + struct vm_device * ide = NULL; + // struct vm_device * cdrom = NULL; #ifdef DEBUG_PCI struct vm_device * pci = v3_create_pci(); #endif @@ -299,11 +299,11 @@ static int setup_devices(struct guest_info * info, struct v3_vm_config * config_ int use_ramdisk = config_ptr->use_ramdisk; int use_generic = USE_GENERIC; + ide = v3_create_ide(); if (use_ramdisk) { PrintDebug("Creating Ramdisk\n"); - ramdisk = v3_create_ramdisk(); - cdrom = v3_create_cdrom(ramdisk, config_ptr->ramdisk, config_ptr->ramdisk_size); + // cdrom = v3_create_cdrom(ramdisk, config_ptr->ramdisk, config_ptr->ramdisk_size); } @@ -329,9 +329,11 @@ static int setup_devices(struct guest_info * info, struct v3_vm_config * config_ v3_attach_device(info, para_net); + v3_attach_device(info, ide); + if (use_ramdisk) { - v3_attach_device(info, ramdisk); - v3_attach_device(info, cdrom); + + // v3_attach_device(info, cdrom); } if (use_generic) {