/*
- * 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 <cuizheng@cs.unm.edu>
- * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
* Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
- * All rights reserved for original changes
- *
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * 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 <palacios/vmm_types.h>
#include <palacios/vm_dev.h>
-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();
#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
--- /dev/null
+/*
+ * 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 <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm.h>
+#include <devices/ide.h>
+#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;
+}