help
This enables Palacios' internal implementation of memcpy
+config BUILT_IN_MEMMOVE
+ bool "memmove()"
+ default n
+ depends on BUILT_IN_STDLIB
+ help
+ This enables Palacios' internal implementation of memmove
+
config BUILT_IN_MEMCMP
bool "memcmp()"
default n
help
This enables Palacios' internal implementation of strcmp
+
+config BUILT_IN_STRCASECMP
+ bool "strcasecmp()"
+ default n
+ depends on BUILT_IN_STDLIB
+ help
+ This enables Palacios' internal implementation of strcasecmp
+
config BUILT_IN_STRNCMP
bool "strncmp()"
default n
help
This enables Palacios' internal implementation of strncmp
+config BUILT_IN_STRNCASECMP
+ bool "strncasecmp()"
+ default n
+ depends on BUILT_IN_STDLIB
+ help
+ This enables Palacios' internal implementation of strncasecmp
+
+
config BUILT_IN_STRCAT
bool "strcat()"
default n
help
This enables Palacios' internal implementation of strdup
+config BUILT_IN_STRSTR
+ bool "strstr()"
+ default n
+ depends on BUILT_IN_STDLIB
+ help
+ This enables Palacios internal implementation of strstr
+
config BUILT_IN_ATOI
bool "atoi()"
+++ /dev/null
-mainmenu "Palacios VMM Configuration"
-
-config x86_64
- bool
- default y
- help
- Support for the x86-64 architecture.
-
-
-menu "Target Configuration"
-
-choice
- prompt "System Architecture"
- default PC
-
-config V3_32BIT
- bool "Compile a 32 bit library"
- help
- Support for 32 bit Operating Systems
-
-config V3_64BIT
- bool "Compile a 64 bit library"
- help
- Support for 64 bit Operating Systems
-endchoice
-
-config CRAY_XT
- bool "Red Storm (Cray XT3/XT4)"
- help
- Support for Cray XT3 and XT4 systems.
-
-
-
-#
-# Define implied options from the CPU selection
-#
-
-config X86_L1_CACHE_BYTES
- int
- default "128" if GENERIC_CPU || MPSC
- default "64" if MK8
-
-config X86_L1_CACHE_SHIFT
- int
- default "7" if GENERIC_CPU || MPSC
- default "6" if MK8
-
-config X86_INTERNODE_CACHE_BYTES
- int
- default X86_L1_CACHE_BYTES
-
-config X86_INTERNODE_CACHE_SHIFT
- int
- default X86_L1_CACHE_SHIFT
-
-config NR_CPUS
- int "Maximum number of CPUs (2-256)"
- range 1 255
- default "16"
- help
- This allows you to specify the maximum number of CPUs which this
- kernel will support. Current maximum is 256 CPUs due to
- APIC addressing limits. Less depending on the hardware.
-
- This is purely to save memory - each supported CPU requires
- memory in the static kernel configuration.
-
-#
-# Physical address where the kernel is loaded
-#
-config PHYSICAL_START
- hex
- default "0x200000"
-
-endmenu
-
-menu "Virtualization"
-
-config PALACIOS
- bool "Include Palacios virtual machine monitor"
- default "n"
- help
- Include the Palacios virtual machine monitor. This enables Kitten
- to run guest operating systems alongside native applications.
-
-config PALACIOS_SOCKET
- bool
- depends on NETWORK && LWIP_TCP && LWIP_UDP && LWIP_SOCKET
- default "y"
-
-config PALACIOS_PATH
- string "Path to pre-built Palacios tree"
- depends on PALACIOS
- default "../palacios"
- help
- Path to a built Palacios source tree. This path is used to
- find Palacios include files and libraries that need to be
- linked with the Kitten kernel image.
-
-config GUEST_OS_ISOIMAGE_PATH
- string "Path to guest OS ISO image"
- depends on PALACIOS
- default "/opt/vmm-tools/isos/puppy.iso"
- help
- Path to an ISO image to link with the example user/hello_world
- init task. The hello_world init task will use this ISO image
- to spawn a guest OS virtual machine via Palacios.
-
-endmenu
-
-#source "net/Kconfig"
-
+++ /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".
- */
-
-#ifndef __DEVICES_BLOCK_DEV_H__
-#define __DEVICES_BLOCK_DEV_H__
-
-#ifdef __V3VEE__
-
-
-
-#define ATAPI_BLOCK_SIZE 2048
-#define HD_SECTOR_SIZE 512
-
-
-struct v3_hd_ops {
- uint64_t (*get_capacity)(void * private_data);
- // Reads always operate on 2048 byte blocks
- int (*read)(uint8_t * buf, int sector_count, uint64_t lba, void * private_data);
- int (*write)(uint8_t * buf, int sector_count, uint64_t lba, void * private_data);
-};
-
-
-
-struct v3_cd_ops {
- uint32_t (*get_capacity)(void * private_data);
- // Reads always operate on 2048 byte blocks
- int (*read)(uint8_t * buf, int block_count, uint64_t lba, void * private_data);
-};
-
-
-typedef enum {BLOCK_NONE, BLOCK_DISK, BLOCK_CDROM} v3_block_type_t;
-
-
-
-static const char * block_dev_type_strs[] = {"NONE", "HARDDISK", "CDROM" };
-
-static inline const char * v3_block_type_to_str(v3_block_type_t type) {
- if (type > BLOCK_CDROM) {
- return NULL;
- }
- return block_dev_type_strs[type];
-}
-
-
-
-#endif
-
-
-#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".
- */
-
-#ifndef __DEVICES_CGA_H__
-#define __DEVICES_CGA_H__
-
-#ifdef __V3VEE__
-
-#include <devices/console.h>
-
-
-int v3_console_register_cga(struct vm_device * cga_dev, struct v3_console_ops * ops, void * private_data);
-
-#endif
-
-#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, Peter Dinda <pdinda@northwestern.edu>
- * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
- * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
- * All rights reserved.
- *
- * Author: Peter Dinda <pdinda@northwestern.edu>
- * 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_GENERIC_H__
-#define __DEVICES_GENERIC_H__
-
-#ifdef __V3VEE__
-
-#include <palacios/vmm_dev_mgr.h>
-
-
-//
-// The generic device simply hooks ranges of ports, addresses, and irqs
-// if they are not already hooked
-//
-// for each hooked port, it simply executes reads and writes and the same physical port,
-// for each hooked memory range, it simply executes reads and writes on the same
-// physical memory addresses
-// for each hooked irq, it simply injects the irq into the VM
-//
-// These operations are also logged to serial (optionaly)
-//
-// If you attach a generic device *last*, you can capture all ops that are not
-// already hooked, and capture a log of VM activity with respect to them.
-//
-// The effects of using the generic device should be identical to
-// doing passthrough I/O, but with logging, and, of course, slower
-//
-
-
-#define GENERIC_PRINT_AND_PASSTHROUGH 0
-#define GENERIC_PRINT_AND_IGNORE 1
-
-
-int v3_generic_add_port_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type);
-
-
-
-
-#endif // ! __V3VEE__
-
-#endif
#ifdef __V3VEE__
-#include <devices/block_dev.h>
-
-struct ide_cfg {
- char pci[32];
- char southbridge[32];
-};
-
-
-int v3_ide_register_cdrom(struct vm_device * ide,
- uint_t bus_num,
- uint_t drive_num,
- char * drive_name,
- struct v3_cd_ops * ops,
- void * private_data);
-
-int v3_ide_register_harddisk(struct vm_device * ide,
- uint_t bus_num,
- uint_t drive_num,
- char * drive_name,
- struct v3_hd_ops * ops,
- void * private_data);
-
-
-
int v3_ide_get_geometry(struct vm_device * ide_dev, int channel_num, int drive_num,
+++ /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".
- */
-
-#ifndef __DEVICES_LNX_VIRTIO_BLK_H__
-#define __DEVICES_LNX_VIRTIO_BLK_H__
-
-#ifdef __V3VEE__
-
-#include <devices/block_dev.h>
-
-int v3_virtio_register_cdrom(struct vm_device * dev,
- struct v3_cd_ops * ops,
- void * private_data);
-
-
-int v3_virtio_register_harddisk(struct vm_device * dev,
- struct v3_hd_ops * ops,
- void * private_data);
-
-
-#endif
-
-
-#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".
- */
-
-#ifndef __DEVICES_NET_CD_H__
-#define __DEVICES_NET_CD_H__
-
-#ifdef __V3VEE__
-
-
-struct net_cd_cfg {
- char ide[32];
- uint_t bus;
- uint_t drive;
- const char * ip_str;
- uint16_t port;
- const char * disk_tag;
-};
-
-
-
-#endif
-
-#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".
- */
-
-#ifndef __DEVICES_NET_HD_H__
-#define __DEVICES_NET_HD_H__
-
-#ifdef __V3VEE__
-
-
-
-struct net_hd_cfg {
- char ide[32];
- uint_t bus;
- uint_t drive;
- const char * ip_str;
- uint16_t port;
- const char * disk_tag;
-};
-
-
-
-#endif
-
-#endif
#include <devices/pci_types.h>
+struct vm_device;
+
typedef enum { PCI_BAR_IO,
PCI_BAR_MEM24,
char name[64];
- struct vm_device * vm_dev; //the corresponding virtual device
-
int (*config_update)(uint_t reg_num, void * src, uint_t length, void * priv_data);
int (*cmd_update)(struct pci_device * pci_dev, uchar_t io_enabled, uchar_t mem_enabled);
int (*config_update)(uint_t reg_num, void * src, uint_t length, void * private_data),
int (*cmd_update)(struct pci_device *pci_dev, uchar_t io_enabled, uchar_t mem_enabled),
int (*ext_rom_update)(struct pci_device *pci_dev),
- struct vm_device * dev, void * priv_data);
+ void * priv_data);
struct pci_device *
const char * name,
int (*config_write)(uint_t reg_num, void * src, uint_t length, void * private_data),
int (*config_read)(uint_t reg_num, void * dst, uint_t length, void * private_data),
- struct vm_device * dev,
void * private_data);
+++ /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".
- */
-
-#ifndef __DEVICES_PCI_PASSTHROUGH_H__
-#define __DEVICES_PCI_PASSTHROUGH_H__
-
-#ifdef __V3VEE__
-
-struct pci_passthrough_cfg {
- char pci_bus_name[32];
-
- char name[32];
- uint16_t vendor_id;
- uint16_t device_id;
-};
-
-
-#endif
-
-#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".
- */
-
-#ifndef __DEVICES_RAM_CD_H__
-#define __DEVICES_RAM_CD_H__
-
-#ifdef __V3VEE__
-
-
-
-struct ram_cd_cfg {
- char ide[32];
- uint_t bus;
- uint_t drive;
- addr_t ramdisk;
- uint32_t size;
-};
-
-
-
-#endif
-
-#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".
- */
-
-#ifndef __DEVICES_RAM_HD_H__
-#define __DEVICES_RAM_HD_H__
-
-#ifdef __V3VEE__
-
-struct ram_hd_cfg {
- char ide[32];
- uint_t bus;
- uint_t drive;
- addr_t ramdisk;
- uint32_t size;
-};
-
-
-
-#endif
-
-#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".
- */
-
-#ifndef __DEVICES_TELNET_CONS_H__
-#define __DEVICES_TELNET_CONS_H__
-
-#ifdef __V3VEE__
-
-
-
-struct telnet_cons_cfg {
- char frontend[32];
- uint16_t port;
-};
-
-
-
-#endif
-
-#endif
#define ETHERNET_DATA_MAX 1500
#define ETHERNET_PACKET_LEN (ETHERNET_HEADER_LEN + ETHERNET_DATA_MAX)
-#define TCP_TYPE 0
-#define UDP_TYPE 1
-
-#define TCP_STR "TCP"
-#define UDP_STR "UDP"
-
-
//the routing entry
struct routing {
char src_mac[6];
void v3_init_svm_cpu(int cpu_id);
-void v3_init_svm_hooks(struct v3_ctrl_ops * vmm_ops);
int v3_is_svm_capable();
+int v3_init_svm_vmcb(struct guest_info * info, v3_vm_class_t vm_class);
+
int v3_svm_enter(struct guest_info * info);
+int v3_start_svm_guest(struct guest_info *info);
#endif
+
+
struct v3_gprs {
v3_reg_t rdi;
v3_reg_t rsi;
#include <palacios/vmm_sym_iface.h>
#endif
+#include <palacios/vmm_config.h>
+
struct shadow_page_state;
struct v3_intr_state;
addr_t mem_size; // In bytes for now
v3_shdw_map_t mem_map;
+ struct v3_config * cfg_data;
+ v3_vm_class_t vm_class;
struct vm_time time_state;
#define __VMM_H__
-#include <palacios/vm_guest.h>
+//#include <palacios/vm_guest.h>
#include <palacios/vmm_mem.h>
#include <palacios/vmm_types.h>
+struct guest_info;
#ifdef __V3VEE__
-#define VMM_INVALID_CPU 0
-#define VMM_VMX_CPU 1
-#define VMM_SVM_CPU 2
+
+typedef enum v3_vm_class {V3_INVALID_VM, V3_PC_VM, V3_CRAY_VM} v3_vm_class_t;
// Maybe make this a define....
void v3_interrupt_cpu(struct guest_info * vm, int logical_cpu);
+unsigned int v3_get_cpu_id();
+
+v3_cpu_arch_t v3_get_cpu_type(int cpu_id);
+
+
int v3_vm_enter(struct guest_info * info);
void (*mutex_lock)(void * mutex, int must_spin);
void (*mutex_unlock)(void * mutex);
+ unsigned int (*get_cpu)(void);
void (*interrupt_cpu)(struct guest_info * vm, int logical_cpu);
void (*call_on_cpu)(int logical_cpu, void (*fn)(void * arg), void * arg);
void (*start_thread_on_cpu)(int logical_cpu, int (*fn)(void * arg), void * arg, char * thread_name);
-typedef enum {NONE, HARDDRIVE, CDROM, VIRTIO} v3_disk_type_t;
-typedef enum {RAM, NETWORK} v3_disk_connection_t;
-
-union v3_disk_info {
- struct {
- void * data_ptr;
- int size;
- } ram;
-
- struct {
- char * ip_str;
- int port;
- char * disk_name;
- } net;
-};
-
-struct v3_vm_config {
-
- unsigned long mem_size; // in bytes, var should be natural size of cpu
- // so we can specify maximum physical address size
- // (We're screwed if we want to do 32 bit host/64 bit guest)
-
- int enable_telemetry;
- int enable_nested_paging;
-
- int enable_pci;
-
- int enable_swap;
-
- int guest_cpu;
-
- unsigned long schedule_freq; // in HZ
-
- v3_disk_type_t pri_disk_type;
- v3_disk_connection_t pri_disk_con;
- union v3_disk_info pri_disk_info;
-
- v3_disk_type_t sec_disk_type;
- v3_disk_connection_t sec_disk_con;
- union v3_disk_info sec_disk_info;
-};
-
-
-
-/* This will contain Function pointers that control the VMs */
-struct v3_ctrl_ops {
- struct guest_info *(*allocate_guest)(void);
-
- int (*init_guest)(struct guest_info * info, struct v3_vm_config * config_ptr);
- int (*start_guest)(struct guest_info * info);
- // int (*stop_vm)(uint_t vm_id);
-
- int (*has_nested_paging)(void);
-
- // v3_cpu_arch_t (*get_cpu_arch)();
-};
-void Init_V3(struct v3_os_hooks * hooks, struct v3_ctrl_ops * vmm_ops, int num_cpus);
+void Init_V3(struct v3_os_hooks * hooks, int num_cpus);
+
+
+int v3_start_vm(struct guest_info * info, unsigned int cpu_mask);
+struct guest_info * v3_create_vm(void * cfg);
int v3_deliver_irq(struct guest_info * vm, struct v3_interrupt * intr);
#ifdef __V3VEE__
-#include <palacios/vm_guest.h>
+//#include <palacios/vm_guest.h>
#include <palacios/vmm.h>
+#include <palacios/vmm_xml.h>
+#include <palacios/vmm_list.h>
+#include <palacios/vmm_hashtable.h>
+//#include <palacios/svm.h>
-int v3_pre_config_guest(struct guest_info * info, struct v3_vm_config * config_ptr);
-int v3_post_config_guest(struct guest_info * info, struct v3_vm_config * config_ptr);
+struct guest_info;
+int v3_config_guest(struct guest_info * info, void * cfg_blob);
+struct v3_cfg_file {
+ void * data;
+ uint64_t size;
-#endif // ! __V3VEE__
+ char tag[256];
+
+ struct list_head file_node;
+};
+
+
+
+typedef struct v3_xml v3_cfg_tree_t;
+
+struct v3_config {
+ v3_cfg_tree_t * cfg;
+ struct list_head file_list;
+ struct hashtable * file_table;
+ void * blob;
+};
+
+
+struct v3_cfg_file * v3_cfg_get_file(struct guest_info * info, char * tag);
+
+char * v3_cfg_val(v3_cfg_tree_t * tree, char * tag);
+v3_cfg_tree_t * v3_cfg_subtree(v3_cfg_tree_t * tree, char * tag);
+v3_cfg_tree_t * v3_cfg_next_branch(v3_cfg_tree_t * tree);
+
+#endif // ! __V3VEE__
#endif
#include <palacios/vmm_list.h>
#include <palacios/vmm_string.h>
#include <palacios/vmm_hashtable.h>
+#include <palacios/vmm_config.h>
struct guest_info;
struct vmm_dev_mgr {
uint_t num_devs;
struct list_head dev_list;
-
struct hashtable * dev_table;
+
+ struct list_head blk_list;
+ struct hashtable * blk_table;
+
+ struct list_head net_list;
+ struct hashtable * net_table;
+
+ struct list_head console_list;
+ struct hashtable * console_table;
+
};
-int v3_create_device(struct guest_info * info, const char * dev_name, void * cfg_data);
+int v3_create_device(struct guest_info * info, const char * dev_name, v3_cfg_tree_t * cfg);
void v3_free_device(struct vm_device * dev);
struct v3_device_info {
char * name;
- int (*init)(struct guest_info * info, void * cfg_data);
+ int (*init)(struct guest_info * info, v3_cfg_tree_t * cfg);
};
-void PrintDebugDevMgr(struct guest_info * info);
-void PrintDebugDev(struct vm_device * dev);
+void v3_print_dev_mgr(struct guest_info * info);
+
+struct v3_dev_blk_ops {
+ uint64_t (*get_capacity)(void * private_data);
+ // Reads always operate on 2048 byte blocks
+ int (*read)(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data);
+ int (*write)(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data);
+};
+
+struct v3_dev_net_ops {
+
+};
+
+struct v3_dev_console_ops {
+};
+int v3_dev_add_blk_frontend(struct guest_info * info,
+ char * name,
+ int (*connect)(struct guest_info * info,
+ void * frontend_data,
+ struct v3_dev_blk_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * private_data),
+ void * priv_data);
+int v3_dev_connect_blk(struct guest_info * info,
+ char * frontend_name,
+ struct v3_dev_blk_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * private_data);
+
+int v3_dev_add_net_frontend(struct guest_info * info,
+ char * name,
+ int (*connect)(struct guest_info * info,
+ void * frontend_data,
+ struct v3_dev_net_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * private_data),
+ void * priv_data);
+int v3_dev_connect_net(struct guest_info * info,
+ char * frontend_name,
+ struct v3_dev_net_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * private_data);
#endif // ! __V3VEE__
-void v3_init_shadow_map(struct guest_info * info);
+int v3_init_shadow_map(struct guest_info * info);
void v3_delete_shadow_map(struct guest_info * info);
struct shadow_page_state {
- // ugly optimization hack
- v3_reg_t prev_guest_cr3;
-
// virtualized control registers
v3_reg_t guest_cr3;
#ifdef __V3VEE__
#include <palacios/vmm_types.h>
-
+#include <stdarg.h>
int sprintf(char *buf, const char *cfmt, ...);
// __attribute__ ((format (printf, 1, 2)));
//int vsprintf(char *buf, const char * cfmt, va_list ap);
int snprintf(char *str, size_t size, const char * fmt, ...);
-//int vsnprintf(char *str, size_t size, const char * fmt, va_list ap);
+int vsnprintf(char *str, size_t size, const char * fmt, va_list ap);
//int vsnrprintf(char *str, size_t size, int radix, const char * fmt, va_list ap);
#define HD_COLUMN_MASK 0xff
#include <palacios/vmm_types.h>
-void* memset(void* s, int c, size_t n);
-void* memcpy(void *dst, const void* src, size_t n);
-//void *memmove(void *dst, const void *src, size_t n);
+void * memset(void* s, int c, size_t n);
+void * memcpy(void *dst, const void* src, size_t n);
+void * memmove(void *dst, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
size_t strlen(const char* s);
size_t strnlen(const char *s, size_t maxlen);
int strcmp(const char* s1, const char* s2);
+int strcasecmp(const char* s1, const char* s2);
int strncmp(const char* s1, const char* s2, size_t limit);
+int strncasecmp(const char* s1, const char* s2, size_t limit);
char *strcat(char *s1, const char *s2);
char *strncat(char *s1, const char *s2, size_t limit);
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t limit);
char *strdup(const char *s1);
-int atoi(const char *buf);
+int atoi(const char * buf);
+uint64_t atox(const char * buf);
+int strtoi(const char * nptr, char ** endptr);
+uint64_t strtox(const char * nptr, char ** endptr);
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
char *strpbrk(const char *s, const char *accept);
+size_t strspn(const char * s, const char * accept);
+size_t strcspn(const char * s, const char * reject);
+char * strstr(const char * haystack, const char * needle);
+void str_tolower(char * s);
+void str_toupper(char * s);
-#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
+#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
#define isascii(c) (((c) & ~0x7f) == 0)
#define isupper(c) ((c) >= 'A' && (c) <= 'Z')
#define islower(c) ((c) >= 'a' && (c) <= 'z')
#ifdef __V3VEE__
-#include <palacios/vm_guest.h>
-
struct v3_sym_interface {
uint64_t magic;
-
union {
uint32_t feature_flags;
struct {
- uint_t pci_map_valid : 1;
+ uint_t pci_map_valid : 1;
uint32_t sym_call_enabled : 1;
} __attribute__((packed));
} __attribute__((packed));
uint8_t pci_pt_map[(4 * 256) / 8]; // we're hardcoding this: (4 busses, 256 max devs)
-
-
-
} __attribute__((packed));
+#include <palacios/vm_guest.h>
+
struct v3_sym_context {
struct v3_gprs vm_regs;
};
-
struct v3_sym_state {
struct v3_sym_interface * sym_page;
uint64_t sym_call_fs;
};
+
+
+
+
+
+
int v3_init_sym_iface(struct guest_info * info);
--- /dev/null
+/* ezxml.h
+ *
+ * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Modified for Palacios by Jack Lange <jarusl@cs.northwestern.edu>
+ */
+
+#ifndef __VMM_XML_H
+#define __VMM_XML_H
+
+#include <palacios/vmm.h>
+#include <palacios/vmm_types.h>
+
+
+struct v3_xml {
+ char *name; // tag name
+ char **attr; // tag attributes { name, value, name, value, ... NULL }
+ char *txt; // tag character content, empty string if none
+ size_t off; // tag offset from start of parent tag character content
+ struct v3_xml * next; // next tag with same name in this section at this depth
+ struct v3_xml * sibling; // next tag with different name in same section and depth
+ struct v3_xml * ordered; // next tag, same section and depth, in original order
+ struct v3_xml * child; // head of sub tag list, NULL if none
+ struct v3_xml * parent; // parent tag, NULL if current tag is root tag
+ short flags; // additional information
+};
+
+// Given a string of xml data and its length, parses it and creates an v3_xml
+// structure. For efficiency, modifies the data by adding null terminators
+// and decoding ampersand sequences. If you don't want this, copy the data and
+// pass in the copy. Returns NULL on failure.
+struct v3_xml * v3_xml_parse(char * buf);
+
+
+// returns the name of the given tag
+#define v3_xml_name(xml) ((xml) ? xml->name : NULL)
+
+// returns the given tag's character content or empty string if none
+#define v3_xml_txt(xml) ((xml) ? xml->txt : "")
+
+
+// returns the first child tag (one level deeper) with the given name or NULL
+// if not found
+struct v3_xml * v3_xml_child(struct v3_xml * xml, const char * name);
+
+// returns the next tag of the same name in the same section and depth or NULL
+// if not found
+#define v3_xml_next(xml) ((xml) ? xml->next : NULL)
+
+// Returns the Nth tag with the same name in the same section at the same depth
+// or NULL if not found. An index of 0 returns the tag given.
+struct v3_xml * v3_xml_idx(struct v3_xml * xml, int idx);
+
+// returns the value of the requested tag attribute, or NULL if not found
+const char *v3_xml_attr(struct v3_xml * xml, const char * attr);
+
+
+// Traverses the v3_xml sturcture to retrieve a specific subtag. Takes a
+// variable length list of tag names and indexes. The argument list must be
+// terminated by either an index of -1 or an empty string tag name. Example:
+// title = v3_xml_get(library, "shelf", 0, "book", 2, "title", -1);
+// This retrieves the title of the 3rd book on the 1st shelf of library.
+// Returns NULL if not found.
+struct v3_xml * v3_xml_get(struct v3_xml * xml, ...);
+
+
+// frees the memory allocated for an v3_xml structure
+void v3_xml_free(struct v3_xml * xml);
+
+#endif // __VMM_XML_H
+
/*
* This file is part of the Palacios Virtual Machine Monitor developed
* by the V3VEE Project with funding from the United States National
};
int v3_is_vmx_capable();
-void v3_init_vmx_hooks(struct v3_ctrl_ops * vm_ops);
void v3_init_vmx_cpu(int cpu_id);
#include <palacios/vmm_time.h>
#include <palacios/vmm_util.h>
#include <palacios/vmm_intr.h>
-
+#include <palacios/vmm_config.h>
#ifndef CONFIG_DEBUG_PIT
};
-static int pit_init(struct guest_info * info, void * cfg_data) {
+static int pit_init(struct guest_info * info, v3_cfg_tree_t * cfg) {
struct pit * pit_state = NULL;
struct vm_device * dev = NULL;
+ char * name = v3_cfg_val(cfg, "name");
uint_t cpu_khz = V3_CPU_KHZ();
ullong_t reload_val = (ullong_t)cpu_khz * 1000;
pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
V3_ASSERT(pit_state != NULL);
- dev = v3_allocate_device("PIT", &dev_ops, pit_state);
+ dev = v3_allocate_device(name, &dev_ops, pit_state);
if (v3_attach_device(info, dev) == -1) {
- PrintError("Could not attach device %s\n", "PIT");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
-static int pic_init(struct guest_info * vm, void * cfg_data) {
+static int pic_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct pic_internal * state = NULL;
state = (struct pic_internal *)V3_Malloc(sizeof(struct pic_internal));
+ char * name = v3_cfg_val(cfg, "name");
+
V3_ASSERT(state != NULL);
- struct vm_device * dev = v3_allocate_device("8259A", &dev_ops, state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "8259A");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
Enable debugging for the NE2K
-config NET_CD
- bool "Networked CD backend"
- default y
- depends on SOCKET && (IDE || LINUX_VIRTIO_BLOCK)
- help
- Includes the Network CD backend
-config NET_HD
- bool "Networked HD backend"
- default y
- depends on SOCKET && (IDE || LINUX_VIRTIO_BLOCK)
- help
- Includes the Network HD backend
config NVRAM
Enable debugging for the PIT
-
-
-config RAM_CD
- bool "RAM based CD backend"
+config NETDISK
+ bool "NETDISK storage backend"
default y
- depends on IDE || LINUX_VIRTIO_BLOCK
+ depends on SOCKET && (IDE || LINUX_VIRTIO_BLOCK)
help
- Includes the RAM based CD backend
+ Includes the Network based disk backend
-config RAM_HD
- bool "RAM based HD backend"
+config RAMDISK
+ bool "RAMDISK storage backend"
default y
depends on IDE || LINUX_VIRTIO_BLOCK
help
- Includes the RAM based HD backend
-
+ Includes the RAM based disk backend
+config TMPDISK
+ bool "TMPDISK storage backend"
+ default y
+ depends on IDE || LINUX_VIRTIO_BLOCK
+ help
+ Includes the temporary RAM disk
config SYM_SWAP
bool "Symbiotic Swap disk"
obj-$(CONFIG_OS_DEBUG) += os_debug.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_PIIX3) += piix3.o
-obj-$(CONFIG_RAM_CD) += ram_cd.o
-obj-$(CONFIG_RAM_HD) += ram_hd.o
-obj-$(CONFIG_SYM_SWAP) += sym_swap.o
+obj-$(CONFIG_SYM_SWAP) += sym_swap.o
obj-$(CONFIG_NE2K) += ne2k.o
-obj-$(CONFIG_NET_CD) += net_cd.o
-obj-$(CONFIG_NET_HD) += net_hd.o
+obj-$(CONFIG_TMPDISK) += tmpdisk.o
+obj-$(CONFIG_RAMDISK) += ramdisk.o
+obj-$(CONFIG_NETDISK) += netdisk.o
obj-$(CONFIG_CGA) += cga.o
obj-$(CONFIG_TELNET_CONSOLE) += telnet_cons.o
#include <devices/apic_regs.h>
#include <palacios/vmm.h>
#include <palacios/vmm_msr.h>
-
+#include <palacios/vm_guest.h>
#ifndef CONFIG_DEBUG_APIC
#undef PrintDebug
-static int apic_init(struct guest_info * vm, void * cfg_data) {
+static int apic_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
PrintDebug("Creating APIC\n");
+ char * name = v3_cfg_val(cfg, "name");
struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state));
- struct vm_device * dev = v3_allocate_device("LAPIC", &dev_ops, apic);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, apic);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "LAPIC");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
drive_id->lba_enable = 1;
// Drive Capacity (28 bit LBA)
- drive_id->lba_capacity = drive->hd_ops->get_capacity(drive->private_data);
+ drive_id->lba_capacity = drive->ops->get_capacity(drive->private_data);
// Drive Capacity (48 bit LBA)
- drive_id->lba_capacity_2 = drive->hd_ops->get_capacity(drive->private_data);
+ drive_id->lba_capacity_2 = drive->ops->get_capacity(drive->private_data);
// lower byte is the maximum multiple sector size...
PrintDebug("Reading Drive LBA=%d (count=%d)\n", (uint32_t)(drive->current_lba), sect_cnt);
- int ret = drive->hd_ops->read(dst, sect_cnt, drive->current_lba, drive->private_data);
+ int ret = drive->ops->read(dst, drive->current_lba * HD_SECTOR_SIZE, sect_cnt * HD_SECTOR_SIZE, drive->private_data);
if (ret == -1) {
PrintError("IDE: Error reading HD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba));
PrintDebug("Writing Drive LBA=%d (count=%d)\n", (uint32_t)(drive->current_lba), sect_cnt);
- int ret = drive->hd_ops->write(src, sect_cnt, drive->current_lba, drive->private_data);
+ int ret = drive->ops->write(src, drive->current_lba * HD_SECTOR_SIZE, sect_cnt * HD_SECTOR_SIZE, drive->private_data);
if (ret == -1) {
PrintError("IDE: Error writing HD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba));
if ((lba_addr.addr + sect_cnt) >
- drive->hd_ops->get_capacity(drive->private_data)) {
+ drive->ops->get_capacity(drive->private_data)) {
PrintError("IDE: request size exceeds disk capacity (lba=%d) (sect_cnt=%d) (ReadEnd=%d) (capacity=%p)\n",
lba_addr.addr, sect_cnt,
lba_addr.addr + (sect_cnt * HD_SECTOR_SIZE),
- (void *)(addr_t)(drive->hd_ops->get_capacity(drive->private_data)));
+ (void *)(addr_t)(drive->ops->get_capacity(drive->private_data)));
return -1;
}
static int atapi_read_chunk(struct vm_device * dev, struct ide_channel * channel) {
struct ide_drive * drive = get_selected_drive(channel);
- int ret = drive->cd_ops->read(drive->data_buf, 1, drive->current_lba, drive->private_data);
+ int ret = drive->ops->read(drive->data_buf, drive->current_lba * ATAPI_BLOCK_SIZE, ATAPI_BLOCK_SIZE,
+drive->private_data);
if (ret == -1) {
PrintError("IDE: Error reading CD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba));
return 0;
}
- if (lba + xfer_len > drive->cd_ops->get_capacity(drive->private_data)) {
+ if (lba + xfer_len > drive->ops->get_capacity(drive->private_data)) {
PrintError("IDE: xfer len exceeded capacity (lba=%d) (xfer_len=%d) (ReadEnd=%d) (capacity=%d)\n",
lba, xfer_len, lba + xfer_len,
- drive->cd_ops->get_capacity(drive->private_data));
+ (uint32_t)drive->ops->get_capacity(drive->private_data));
atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_LOG_BLK_OOR);
ide_raise_irq(dev, channel);
return 0;
static int atapi_get_capacity(struct vm_device * dev, struct ide_channel * channel) {
struct ide_drive * drive = get_selected_drive(channel);
struct atapi_rd_capacity_resp * resp = (struct atapi_rd_capacity_resp *)(drive->data_buf);
- uint32_t capacity = drive->cd_ops->get_capacity(drive->private_data);
+ uint32_t capacity = drive->ops->get_capacity(drive->private_data);
resp->lba = le_to_be_32(capacity);
resp->block_len = le_to_be_32(ATAPI_BLOCK_SIZE);
-static int debug_init(struct guest_info * vm, void * cfg_data) {
- struct debug_state * state = NULL;
+static int debug_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
+ struct debug_state * state = NULL;
+ char * name = v3_cfg_val(cfg, "name");
state = (struct debug_state *)V3_Malloc(sizeof(struct debug_state));
V3_ASSERT(state != NULL);
PrintDebug("Creating Bochs Debug Device\n");
- struct vm_device * dev = v3_allocate_device("BOCHS_DEBUG", &dev_ops, state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "BOCHS_DEBUG");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
.stop = NULL,
};
-static int cga_init(struct guest_info * vm, void * cfg_data) {
+static int cga_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct video_internal * video_state = (struct video_internal *)V3_Malloc(sizeof(struct video_internal));
addr_t frame_buf_pa = 0;
- uint32_t enable_passthrough = (uint32_t)(addr_t)cfg_data;
+ int enable_passthrough = 0;
+ char * name = v3_cfg_val(cfg, "name");
+ enable_passthrough = (strcasecmp(v3_cfg_val(cfg, "passthrough"), "enable") == 0) ? 1 : 0;
PrintDebug("video: init_device\n");
- struct vm_device * dev = v3_allocate_device("CGA_VIDEO", &dev_ops, video_state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, video_state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "CGA_VIDEO");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
.stop = cirrus_gfx_card_stop_device,
};
-static int cirrus_gfx_card_init(struct guest_info * vm, void * cfg_data){
+static int cirrus_gfx_card_init(struct guest_info * vm, v3_cfg_tree_t * cfg){
struct video_internal * video_state = (struct video_internal *)V3_Malloc(sizeof(struct video_internal));
struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
+ char * name = v3_cfg_val(cfg, "name");
+
struct vm_device * dev = v3_allocate_device("TEXT_GFX_CARD", &dev_ops, video_state);
if (v3_attach_device(vm, dev) == -1) {
* redistribute, and modify it as specified in the file "V3VEE_LICENSE".
*/
-#include <devices/generic.h>
#include <palacios/vmm.h>
#include <palacios/vmm_types.h>
#include <palacios/vmm_list.h>
-
-
+#include <palacios/vmm_io.h>
+#include <palacios/vmm_dev_mgr.h>
#ifndef CONFIG_DEBUG_GENERIC
#undef PrintDebug
#endif
+typedef enum {GENERIC_IGNORE,
+ GENERIC_PASSTHROUGH,
+ GENERIC_PRINT_AND_PASSTHROUGH,
+ GENERIC_PRINT_AND_IGNORE} generic_mode_t;
+
struct generic_internal {
struct list_head port_list;
uint_t num_port_ranges;
struct port_range {
uint_t start;
uint_t end;
- uint_t type;
+ generic_mode_t mode;
struct list_head range_link;
};
-int v3_generic_add_port_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
+static int add_port_range(struct vm_device * dev, uint_t start, uint_t end, generic_mode_t mode) {
struct generic_internal * state = (struct generic_internal *)(dev->private_data);
struct port_range * range = (struct port_range *)V3_Malloc(sizeof(struct port_range));
uint_t i = 0;
range->start = start;
range->end = end;
- range->type = type;
+ range->mode = mode;
PrintDebug("generic: Adding Port Range: 0x%x to 0x%x as %s\n",
- range->start, range->end,
- (range->type == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
+ start, end,
+ (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
for (i = start; i <= end; i++) {
- if (type == GENERIC_PRINT_AND_PASSTHROUGH) {
+ if (mode == GENERIC_PRINT_AND_PASSTHROUGH) {
if (v3_dev_hook_io(dev, i, &generic_read_port_passthrough, &generic_write_port_passthrough) == -1) {
PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
return -1;
}
- } else if (type == GENERIC_PRINT_AND_IGNORE) {
+ } else if (mode == GENERIC_PRINT_AND_IGNORE) {
if (v3_dev_hook_io(dev, i, &generic_read_port_ignore, &generic_write_port_ignore) == -1) {
PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
return -1;
-static int generic_init(struct guest_info * vm, void * cfg_data) {
+static int generic_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct generic_internal * state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
-
+ char * name = v3_cfg_val(cfg, "name");
+
+ v3_cfg_tree_t * port_cfg = v3_cfg_subtree(cfg, "ports");
+
+
INIT_LIST_HEAD(&(state->port_list));
state->num_port_ranges = 0;
+
- struct vm_device * dev = v3_allocate_device("GENERIC", &dev_ops, state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "GENERIC");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
PrintDebug("generic: init_device\n");
generic_reset_device(dev);
+ // scan port list....
+ while (port_cfg) {
+ uint16_t start = atox(v3_cfg_val(port_cfg, "start"));
+ uint16_t end = atox(v3_cfg_val(port_cfg, "end"));
+ char * mode_str = v3_cfg_val(port_cfg, "mode");
+ generic_mode_t mode = GENERIC_IGNORE;
+
+ if (strcasecmp(mode_str, "print_and_ignore") == 0) {
+ mode = GENERIC_PRINT_AND_IGNORE;
+ } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
+ mode = GENERIC_PRINT_AND_PASSTHROUGH;
+ } else {
+ PrintError("Invalid Mode %s\n", mode_str);
+ return -1;
+ }
+
+ if (add_port_range(dev, start, end, mode) == -1) {
+ PrintError("Could not add port range %d-%d\n", start, end);
+ return -1;
+ }
+
+ port_cfg = v3_cfg_next_branch(port_cfg);
+ }
+
+
return 0;
}
-static int i440_init(struct guest_info * vm, void * cfg_data) {
+static int i440_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct pci_device * pci_dev = NULL;
struct v3_pci_bar bars[6];
int i;
struct i440_state * state = NULL;
- struct vm_device * pci = v3_find_dev(vm, (char *)cfg_data);
+ struct vm_device * pci = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
+ char * name = v3_cfg_val(cfg, "name");
if (!pci) {
PrintError("could not find PCI Device\n");
state->pci = pci;
- struct vm_device * dev = v3_allocate_device("i440FX", &dev_ops, state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "i440FX");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
pci_dev = v3_pci_register_device(state->pci, PCI_STD_DEVICE,
0, 0, 0, "i440FX", bars,
- NULL, NULL, NULL, dev, NULL);
+ NULL, NULL, NULL, dev);
if (!pci_dev) {
return -1;
*/
#include <palacios/vmm.h>
+#include <palacios/vmm_dev_mgr.h>
#include <palacios/vm_guest_mem.h>
#include <devices/ide.h>
#include <devices/pci.h>
#include <devices/southbridge.h>
-#include <devices/block_dev.h>
#include "ide-types.h"
#include "atapi-types.h"
#define DATA_BUFFER_SIZE 2048
+#define ATAPI_BLOCK_SIZE 2048
+#define HD_SECTOR_SIZE 512
+
+
static const char * ide_pri_port_strs[] = {"PRI_DATA", "PRI_FEATURES", "PRI_SECT_CNT", "PRI_SECT_NUM",
"PRI_CYL_LOW", "PRI_CYL_HIGH", "PRI_DRV_SEL", "PRI_CMD",
"PRI_CTRL", "PRI_ADDR_REG"};
"DMA_PRD0", "DMA_PRD1", "DMA_PRD2", "DMA_PRD3"};
+typedef enum {BLOCK_NONE, BLOCK_DISK, BLOCK_CDROM} v3_block_type_t;
static inline const char * io_port_to_str(uint16_t port) {
if ((port >= PRI_DATA_PORT) && (port <= PRI_CMD_PORT)) {
v3_block_type_t drive_type;
- union {
- struct v3_cd_ops * cd_ops;
- struct v3_hd_ops * hd_ops;
- };
-
+ struct v3_dev_blk_ops * ops;
union {
struct ide_cd_state cd_state;
drive->private_data = NULL;
- drive->cd_ops = NULL;
+ drive->ops = NULL;
}
static void init_channel(struct ide_channel * channel) {
-static int ide_init(struct guest_info * vm, void * cfg_data) {
- struct ide_internal * ide = (struct ide_internal *)V3_Malloc(sizeof(struct ide_internal));
- struct ide_cfg * cfg = (struct ide_cfg *)(cfg_data);
+
+static int connect_fn(struct guest_info * info,
+ void * frontend_data,
+ struct v3_dev_blk_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * private_data) {
+ struct ide_internal * ide = (struct ide_internal *)(frontend_data);
+ struct ide_channel * channel = NULL;
+ struct ide_drive * drive = NULL;
+
+ char * bus_str = v3_cfg_val(cfg, "bus_num");
+ char * drive_str = v3_cfg_val(cfg, "drive_num");
+ char * type_str = v3_cfg_val(cfg, "type");
+ char * model_str = v3_cfg_val(cfg, "model");
+ uint_t bus_num = 0;
+ uint_t drive_num = 0;
+
+
+ if ((!type_str) || (!drive_str) || (!bus_str)) {
+ PrintError("Incomplete IDE Configuration\n");
+ return -1;
+ }
+
+ bus_num = atoi(bus_str);
+ drive_num = atoi(drive_str);
+
+ channel = &(ide->channels[bus_num]);
+ drive = &(channel->drives[drive_num]);
+
+ if (drive->drive_type != BLOCK_NONE) {
+ PrintError("Device slot (bus=%d, drive=%d) already occupied\n", bus_num, drive_num);
+ return -1;
+ }
+
+ strncpy(drive->model, model_str, sizeof(drive->model) - 1);
+ if (strcasecmp(type_str, "cdrom") == 0) {
+ drive->drive_type = BLOCK_CDROM;
+
+ while (strlen((char *)(drive->model)) < 40) {
+ strcat((char*)(drive->model), " ");
+ }
+
+ } else if (strcasecmp(type_str, "hd") == 0) {
+ drive->drive_type = BLOCK_DISK;
+
+ drive->hd_state.accessed = 0;
+ drive->hd_state.mult_sector_num = 1;
+
+ drive->num_sectors = 63;
+ drive->num_heads = 16;
+ drive->num_cylinders = ops->get_capacity(private_data) / (drive->num_sectors * drive->num_heads);
+ } else {
+ PrintError("invalid IDE drive type\n");
+ return -1;
+ }
+
+
+ drive->ops = ops;
+
+ if (ide->ide_pci) {
+ // Hardcode this for now, but its not a good idea....
+ ide->ide_pci->config_space[0x41 + (bus_num * 2)] = 0x80;
+ }
+
+ drive->private_data = private_data;
+
+ return 0;
+}
+
+
+
+
+static int ide_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
+ struct ide_internal * ide = (struct ide_internal *)V3_Malloc(sizeof(struct ide_internal));
+ char * name = v3_cfg_val(cfg, "name");
+
PrintDebug("IDE: Initializing IDE\n");
memset(ide, 0, sizeof(struct ide_internal));
- if (cfg->pci != NULL) {
- if (cfg->southbridge == NULL) {
- PrintError("PCI Enabled BUT southbridge is NULL\n");
- return -1;
- }
-
- ide->pci_bus = v3_find_dev(vm, (char *)cfg->pci);
-
- if (ide->pci_bus == NULL) {
- PrintError("Could not find PCI device\n");
- return -1;
- }
+ ide->pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
- struct vm_device * southbridge = v3_find_dev(vm, cfg->southbridge);
+ if (ide->pci_bus != NULL) {
+ struct vm_device * southbridge = v3_find_dev(vm, v3_cfg_val(cfg, "controller"));
if (!southbridge) {
PrintError("Could not find southbridge\n");
ide->southbridge = (struct v3_southbridge *)(southbridge->private_data);
}
-
PrintDebug("IDE: Creating IDE bus x 2\n");
- struct vm_device * dev = v3_allocate_device("IDE", &dev_ops, ide);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, ide);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "IDE");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
-
if (init_ide_state(dev) == -1) {
PrintError("Failed to initialize IDE state\n");
return -1;
pci_dev = v3_pci_register_device(ide->pci_bus, PCI_STD_DEVICE, 0, sb_pci->dev_num, 1,
"PIIX3_IDE", bars,
- pci_config_update, NULL, NULL, dev, dev);
+ pci_config_update, NULL, NULL, dev);
if (pci_dev == NULL) {
PrintError("Failed to register IDE BUS %d with PCI\n", i);
}
+ if (v3_dev_add_blk_frontend(vm, name, connect_fn, (void *)ide) == -1) {
+ PrintError("Could not register %s as frontend\n", name);
+ return -1;
+ }
+
+
PrintDebug("IDE Initialized\n");
return 0;
-
-
-
-
-
int v3_ide_get_geometry(struct vm_device * ide_dev, int channel_num, int drive_num,
uint32_t * cylinders, uint32_t * heads, uint32_t * sectors) {
-
-int v3_ide_register_cdrom(struct vm_device * ide_dev,
- uint_t bus_num,
- uint_t drive_num,
- char * dev_name,
- struct v3_cd_ops * ops,
- void * private_data) {
-
- struct ide_internal * ide = (struct ide_internal *)(ide_dev->private_data);
- struct ide_channel * channel = NULL;
- struct ide_drive * drive = NULL;
-
- V3_ASSERT((bus_num >= 0) && (bus_num < 2));
- V3_ASSERT((drive_num >= 0) && (drive_num < 2));
-
- channel = &(ide->channels[bus_num]);
- drive = &(channel->drives[drive_num]);
-
- if (drive->drive_type != BLOCK_NONE) {
- PrintError("Device slot (bus=%d, drive=%d) already occupied\n", bus_num, drive_num);
- return -1;
- }
-
- strncpy(drive->model, dev_name, sizeof(drive->model) - 1);
-
- while (strlen((char *)(drive->model)) < 40) {
- strcat((char*)(drive->model), " ");
- }
-
-
- drive->drive_type = BLOCK_CDROM;
-
- drive->cd_ops = ops;
-
- if (ide->ide_pci) {
- // Hardcode this for now, but its not a good idea....
- ide->ide_pci->config_space[0x41 + (bus_num * 2)] = 0x80;
- }
-
- drive->private_data = private_data;
-
- return 0;
-}
-
-
-int v3_ide_register_harddisk(struct vm_device * ide_dev,
- uint_t bus_num,
- uint_t drive_num,
- char * dev_name,
- struct v3_hd_ops * ops,
- void * private_data) {
-
- struct ide_internal * ide = (struct ide_internal *)(ide_dev->private_data);
- struct ide_channel * channel = NULL;
- struct ide_drive * drive = NULL;
-
- V3_ASSERT((bus_num >= 0) && (bus_num < 2));
- V3_ASSERT((drive_num >= 0) && (drive_num < 2));
-
- channel = &(ide->channels[bus_num]);
- drive = &(channel->drives[drive_num]);
-
- if (drive->drive_type != BLOCK_NONE) {
- PrintError("Device slot (bus=%d, drive=%d) already occupied\n", bus_num, drive_num);
- return -1;
- }
-
- strncpy(drive->model, dev_name, sizeof(drive->model) - 1);
-
- drive->drive_type = BLOCK_DISK;
-
- drive->hd_state.accessed = 0;
- drive->hd_state.mult_sector_num = 1;
-
- drive->hd_ops = ops;
-
- /* this is something of a hack... */
- drive->num_sectors = 63;
- drive->num_heads = 16;
- drive->num_cylinders = ops->get_capacity(private_data) / (drive->num_sectors * drive->num_heads);
-
- if (ide->ide_pci) {
- // Hardcode this for now, but its not a good idea....
- ide->ide_pci->config_space[0x41 + (bus_num * 2)] = 0x80;
- }
-
-
-
- drive->private_data = private_data;
-
- return 0;
-}
-
-
-
#include <palacios/vmm.h>
#include <palacios/vmm_dev_mgr.h>
#include <devices/apic.h>
-
+#include <palacios/vm_guest.h>
#ifndef CONFIG_DEBUG_IO_APIC
#undef PrintDebug
-static int ioapic_init(struct guest_info * vm, void * cfg_data) {
- struct vm_device * apic = v3_find_dev(vm, (char *)cfg_data);
+static int ioapic_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
+ struct vm_device * apic = v3_find_dev(vm, v3_cfg_val(cfg, "irq_bus"));
+ char * name = v3_cfg_val(cfg, "name");
if (!apic) {
- PrintError("Could not locate APIC device (%s)\n", (char *)cfg_data);
+ PrintError("Could not locate APIC device (%s)\n", v3_cfg_val(cfg, "irq_bus"));
return -1;
}
ioapic->apic = apic;
- struct vm_device * dev = v3_allocate_device("IOAPIC", &dev_ops, ioapic);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, ioapic);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "IOAPIC");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
#include <palacios/vmm_ringbuffer.h>
#include <palacios/vmm_lock.h>
+#include <palacios/vmm_intr.h>
+#include <palacios/vmm_host_events.h>
+#include <palacios/vm_guest.h>
#ifndef CONFIG_DEBUG_KEYBOARD
-static int keyboard_init(struct guest_info * vm, void * cfg_data) {
+static int keyboard_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct keyboard_internal * keyboard_state = NULL;
-
+ char * name = v3_cfg_val(cfg, "name");
PrintDebug("keyboard: init_device\n");
keyboard_state->mouse_enabled = 0;
- struct vm_device * dev = v3_allocate_device("KEYBOARD", &dev_ops, keyboard_state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, keyboard_state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "KEYBOARD");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
-static int virtio_init(struct guest_info * vm, void * cfg_data) {
- struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
+static int virtio_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
+ struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
struct virtio_balloon_state * virtio_state = NULL;
struct pci_device * pci_dev = NULL;
+ char * name = v3_cfg_val(cfg, "name");
PrintDebug("Initializing VIRTIO Balloon device\n");
memset(virtio_state, 0, sizeof(struct virtio_balloon_state));
- struct vm_device * dev = v3_allocate_device("LNX_VIRTIO_BALLOON", &dev_ops, virtio_state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "LNX_VIRTIO_BALLOON");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE,
0, PCI_AUTO_DEV_NUM, 0,
"LNX_VIRTIO_BALLOON", bars,
- NULL, NULL, NULL, dev, NULL);
+ NULL, NULL, NULL, dev);
if (!pci_dev) {
PrintError("Could not register PCI Device\n");
#include <palacios/vmm.h>
#include <palacios/vmm_dev_mgr.h>
#include <devices/lnx_virtio_pci.h>
-#include <devices/lnx_virtio_blk.h>
-#include <devices/block_dev.h>
#include <palacios/vm_guest_mem.h>
#include <devices/pci.h>
#define VIRTIO_LEGACY_GEOM 0x10 /* Indicates support of legacy geometry */
-
+struct virtio_dev_state {
+ struct vm_device * pci_bus;
+ struct list_head dev_list;
+ struct guest_info * vm;
+};
struct virtio_blk_state {
+
+ struct pci_device * pci_dev;
struct blk_config block_cfg;
struct virtio_config virtio_cfg;
- struct vm_device * pci_bus;
- struct pci_device * pci_dev;
struct virtio_queue queue;
- union {
- struct v3_cd_ops * cd_ops;
- struct v3_hd_ops * hd_ops;
- };
+ struct v3_dev_blk_ops * ops;
- v3_block_type_t block_type;
void * backend_data;
int io_range_size;
+
+ struct virtio_dev_state * virtio_dev;
+
+ struct list_head dev_link;
};
return -1;
}
-static int virtio_reset(struct vm_device * dev) {
- struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
+static int blk_reset(struct virtio_blk_state * virtio) {
virtio->queue.ring_desc_addr = 0;
virtio->queue.ring_avail_addr = 0;
virtio->virtio_cfg.status = 0;
virtio->virtio_cfg.pci_isr = 0;
-
return 0;
}
-static int handle_read_op(struct vm_device * dev, uint8_t * buf, uint64_t * sector, uint32_t len) {
- struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
- int ret = -1;
-
- if (virtio->block_type == BLOCK_DISK) {
- if (len % HD_SECTOR_SIZE) {
- PrintError("Write of something that is not a sector len %d, mod=%d\n", len, len % HD_SECTOR_SIZE);
- return -1;
- }
-
- PrintDebug("Reading Disk\n");
-
- ret = virtio->hd_ops->read(buf, len / HD_SECTOR_SIZE, *sector, virtio->backend_data);
+static int virtio_reset(struct vm_device * dev) {
+ struct virtio_dev_state * dev_state = (struct virtio_dev_state *)(dev->private_data);
+ struct virtio_blk_state * blk_state = NULL;
- *sector += len / HD_SECTOR_SIZE;
+ list_for_each_entry(blk_state, &(dev_state->dev_list), dev_link) {
+ blk_reset(blk_state);
+ }
- } else if (virtio->block_type == BLOCK_CDROM) {
- if (len % ATAPI_BLOCK_SIZE) {
- PrintError("Write of something that is not an ATAPI block len %d, mod=%d\n", len, len % ATAPI_BLOCK_SIZE);
- return -1;
- }
+ return 0;
+}
- ret = virtio->cd_ops->read(buf, len / ATAPI_BLOCK_SIZE, *sector , virtio->backend_data);
+static int handle_read_op(struct virtio_blk_state * blk_state, uint8_t * buf, uint64_t * sector, uint64_t len) {
+ int ret = -1;
- *sector += len / ATAPI_BLOCK_SIZE;
- }
+ PrintDebug("Reading Disk\n");
+ ret = blk_state->ops->read(buf, *sector, len, (void *)(blk_state->backend_data));
+ *sector += len;
return ret;
}
-static int handle_write_op(struct vm_device * dev, uint8_t * buf, uint64_t * sector, uint32_t len) {
- struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
+static int handle_write_op(struct virtio_blk_state * blk_state, uint8_t * buf, uint64_t * sector, uint64_t len) {
int ret = -1;
- if (virtio->block_type == BLOCK_DISK) {
- if (len % HD_SECTOR_SIZE) {
- PrintError("Write of something that is not a sector len %d, mod=%d\n", len, len % HD_SECTOR_SIZE);
- return -1;
- }
-
- PrintDebug("Writing Disk\n");
-
- ret = virtio->hd_ops->write(buf, len / HD_SECTOR_SIZE, *sector, virtio->backend_data);
-
- *sector += len / HD_SECTOR_SIZE;
- }
+ PrintDebug("Writing Disk\n");
+ ret = blk_state->ops->write(buf, *sector, len, (void *)(blk_state->backend_data));
+ *sector += len;
return ret;
}
// multiple block operations need to increment the sector
-static int handle_block_op(struct vm_device * dev, struct blk_op_hdr * hdr,
+static int handle_block_op(struct virtio_blk_state * blk_state, struct blk_op_hdr * hdr,
struct vring_desc * buf_desc, uint8_t * status) {
- struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
uint8_t * buf = NULL;
PrintDebug("Handling Block op\n");
-
-
-
- if (guest_pa_to_host_va(dev->vm, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
+ if (guest_pa_to_host_va(blk_state->virtio_dev->vm, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
PrintError("Could not translate buffer address\n");
return -1;
}
-
PrintDebug("Sector=%p Length=%d\n", (void *)(addr_t)(hdr->sector), buf_desc->length);
if (hdr->type == BLK_IN_REQ) {
- if (virtio->block_type != BLOCK_NONE) {
- if (handle_read_op(dev, buf, &(hdr->sector), buf_desc->length) == -1) {
- *status = BLK_STATUS_ERR;
- return -1;
- } else {
- *status = BLK_STATUS_OK;
- }
+ if (handle_read_op(blk_state, buf, &(hdr->sector), buf_desc->length) == -1) {
+ *status = BLK_STATUS_ERR;
+ return -1;
} else {
- *status = BLK_STATUS_NOT_SUPPORTED;
+ *status = BLK_STATUS_OK;
}
-
} else if (hdr->type == BLK_OUT_REQ) {
- if (virtio->block_type == BLOCK_DISK) {
- if (handle_write_op(dev, buf, &(hdr->sector), buf_desc->length) == -1) {
- *status = BLK_STATUS_ERR;
- return -1;
- } else {
- *status = BLK_STATUS_OK;
- }
-
+ if (handle_write_op(blk_state, buf, &(hdr->sector), buf_desc->length) == -1) {
+ *status = BLK_STATUS_ERR;
+ return -1;
} else {
- *status = BLK_STATUS_NOT_SUPPORTED;
+ *status = BLK_STATUS_OK;
}
-
} else if (hdr->type == BLK_SCSI_CMD) {
PrintError("VIRTIO: SCSI Command Not supported!!!\n");
*status = BLK_STATUS_NOT_SUPPORTED;
return -1;
}
-
-
PrintDebug("Returning Status: %d\n", *status);
return 0;
-static int handle_kick(struct vm_device * dev) {
- struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
- struct virtio_queue * q = &(virtio->queue);
+static int handle_kick(struct virtio_blk_state * blk_state) {
+ struct virtio_queue * q = &(blk_state->queue);
PrintDebug("VIRTIO KICK: cur_index=%d (mod=%d), avail_index=%d\n",
q->cur_avail_idx, q->cur_avail_idx % QUEUE_SIZE, q->avail->index);
PrintDebug("Header Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", hdr_desc,
(void *)(hdr_desc->addr_gpa), hdr_desc->length, hdr_desc->flags, hdr_desc->next);
- if (guest_pa_to_host_va(dev->vm, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
+ if (guest_pa_to_host_va(blk_state->virtio_dev->vm, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
PrintError("Could not translate block header address\n");
return -1;
}
PrintDebug("Buffer Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", buf_desc,
(void *)(buf_desc->addr_gpa), buf_desc->length, buf_desc->flags, buf_desc->next);
- if (handle_block_op(dev, &hdr, buf_desc, &tmp_status) == -1) {
+ if (handle_block_op(blk_state, &hdr, buf_desc, &tmp_status) == -1) {
PrintError("Error handling block operation\n");
return -1;
}
PrintDebug("Status Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", status_desc,
(void *)(status_desc->addr_gpa), status_desc->length, status_desc->flags, status_desc->next);
- if (guest_pa_to_host_va(dev->vm, status_desc->addr_gpa, (addr_t *)&(status_ptr)) == -1) {
+ if (guest_pa_to_host_va(blk_state->virtio_dev->vm, status_desc->addr_gpa, (addr_t *)&(status_ptr)) == -1) {
PrintError("Could not translate status address\n");
return -1;
}
}
if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
- PrintDebug("Raising IRQ %d\n", virtio->pci_dev->config_header.intr_line);
- v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
- virtio->virtio_cfg.pci_isr = 1;
+ PrintDebug("Raising IRQ %d\n", blk_state->pci_dev->config_header.intr_line);
+ v3_pci_raise_irq(blk_state->virtio_dev->pci_bus, 0, blk_state->pci_dev);
+ blk_state->virtio_cfg.pci_isr = 1;
}
return 0;
}
static int virtio_io_write(uint16_t port, void * src, uint_t length, void * private_data) {
- struct vm_device * dev = (struct vm_device *)private_data;
- struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
- int port_idx = port % virtio->io_range_size;
+ struct virtio_blk_state * blk_state = (struct virtio_blk_state *)private_data;
+ int port_idx = port % blk_state->io_range_size;
PrintDebug("VIRTIO BLOCK Write for port %d (index=%d) len=%d, value=%x\n",
return -1;
}
- virtio->virtio_cfg.guest_features = *(uint32_t *)src;
- PrintDebug("Setting Guest Features to %x\n", virtio->virtio_cfg.guest_features);
+ blk_state->virtio_cfg.guest_features = *(uint32_t *)src;
+ PrintDebug("Setting Guest Features to %x\n", blk_state->virtio_cfg.guest_features);
break;
case VRING_PG_NUM_PORT:
addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
- virtio->queue.pfn = pfn;
+ blk_state->queue.pfn = pfn;
- virtio->queue.ring_desc_addr = page_addr ;
- virtio->queue.ring_avail_addr = page_addr + (QUEUE_SIZE * sizeof(struct vring_desc));
- virtio->queue.ring_used_addr = ( virtio->queue.ring_avail_addr + \
+ blk_state->queue.ring_desc_addr = page_addr ;
+ blk_state->queue.ring_avail_addr = page_addr + (QUEUE_SIZE * sizeof(struct vring_desc));
+ blk_state->queue.ring_used_addr = ( blk_state->queue.ring_avail_addr + \
sizeof(struct vring_avail) + \
(QUEUE_SIZE * sizeof(uint16_t)));
// round up to next page boundary.
- virtio->queue.ring_used_addr = (virtio->queue.ring_used_addr + 0xfff) & ~0xfff;
+ blk_state->queue.ring_used_addr = (blk_state->queue.ring_used_addr + 0xfff) & ~0xfff;
- if (guest_pa_to_host_va(dev->vm, virtio->queue.ring_desc_addr, (addr_t *)&(virtio->queue.desc)) == -1) {
+ if (guest_pa_to_host_va(blk_state->virtio_dev->vm, blk_state->queue.ring_desc_addr, (addr_t *)&(blk_state->queue.desc)) == -1) {
PrintError("Could not translate ring descriptor address\n");
return -1;
}
- if (guest_pa_to_host_va(dev->vm, virtio->queue.ring_avail_addr, (addr_t *)&(virtio->queue.avail)) == -1) {
+ if (guest_pa_to_host_va(blk_state->virtio_dev->vm, blk_state->queue.ring_avail_addr, (addr_t *)&(blk_state->queue.avail)) == -1) {
PrintError("Could not translate ring available address\n");
return -1;
}
- if (guest_pa_to_host_va(dev->vm, virtio->queue.ring_used_addr, (addr_t *)&(virtio->queue.used)) == -1) {
+ if (guest_pa_to_host_va(blk_state->virtio_dev->vm, blk_state->queue.ring_used_addr, (addr_t *)&(blk_state->queue.used)) == -1) {
PrintError("Could not translate ring used address\n");
return -1;
}
PrintDebug("RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
- (void *)(virtio->queue.ring_desc_addr),
- (void *)(virtio->queue.ring_avail_addr),
- (void *)(virtio->queue.ring_used_addr));
+ (void *)(blk_state->queue.ring_desc_addr),
+ (void *)(blk_state->queue.ring_avail_addr),
+ (void *)(blk_state->queue.ring_used_addr));
PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n",
- virtio->queue.desc, virtio->queue.avail, virtio->queue.used);
+ blk_state->queue.desc, blk_state->queue.avail, blk_state->queue.used);
} else {
PrintError("Illegal write length for page frame number\n");
}
break;
case VRING_Q_SEL_PORT:
- virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
+ blk_state->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
- if (virtio->virtio_cfg.vring_queue_selector != 0) {
+ if (blk_state->virtio_cfg.vring_queue_selector != 0) {
PrintError("Virtio Block device only uses 1 queue, selected %d\n",
- virtio->virtio_cfg.vring_queue_selector);
+ blk_state->virtio_cfg.vring_queue_selector);
return -1;
}
break;
case VRING_Q_NOTIFY_PORT:
PrintDebug("Handling Kick\n");
- if (handle_kick(dev) == -1) {
+ if (handle_kick(blk_state) == -1) {
PrintError("Could not handle Block Notification\n");
return -1;
}
break;
case VIRTIO_STATUS_PORT:
- virtio->virtio_cfg.status = *(uint8_t *)src;
+ blk_state->virtio_cfg.status = *(uint8_t *)src;
- if (virtio->virtio_cfg.status == 0) {
+ if (blk_state->virtio_cfg.status == 0) {
PrintDebug("Resetting device\n");
- virtio_reset(dev);
+ blk_reset(blk_state);
}
break;
case VIRTIO_ISR_PORT:
- virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
+ blk_state->virtio_cfg.pci_isr = *(uint8_t *)src;
break;
default:
return -1;
static int virtio_io_read(uint16_t port, void * dst, uint_t length, void * private_data) {
- struct vm_device * dev = (struct vm_device *)private_data;
- struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
- int port_idx = port % virtio->io_range_size;
+ struct virtio_blk_state * blk_state = (struct virtio_blk_state *)private_data;
+ int port_idx = port % blk_state->io_range_size;
PrintDebug("VIRTIO BLOCK Read for port %d (index =%d), length=%d\n",
return -1;
}
- *(uint32_t *)dst = virtio->virtio_cfg.host_features;
+ *(uint32_t *)dst = blk_state->virtio_cfg.host_features;
break;
case VRING_PG_NUM_PORT:
return -1;
}
- *(uint32_t *)dst = virtio->queue.pfn;
+ *(uint32_t *)dst = blk_state->queue.pfn;
break;
case VRING_SIZE_PORT:
return -1;
}
- *(uint16_t *)dst = virtio->queue.queue_size;
+ *(uint16_t *)dst = blk_state->queue.queue_size;
break;
return -1;
}
- *(uint8_t *)dst = virtio->virtio_cfg.status;
+ *(uint8_t *)dst = blk_state->virtio_cfg.status;
break;
case VIRTIO_ISR_PORT:
- *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
- virtio->virtio_cfg.pci_isr = 0;
- v3_pci_lower_irq(virtio->pci_bus, 0, virtio->pci_dev);
+ *(uint8_t *)dst = blk_state->virtio_cfg.pci_isr;
+ blk_state->virtio_cfg.pci_isr = 0;
+ v3_pci_lower_irq(blk_state->virtio_dev->pci_bus, 0, blk_state->pci_dev);
break;
default:
if ( (port_idx >= sizeof(struct virtio_config)) &&
(port_idx < (sizeof(struct virtio_config) + sizeof(struct blk_config))) ) {
int cfg_offset = port_idx - sizeof(struct virtio_config);
- uint8_t * cfg_ptr = (uint8_t *)&(virtio->block_cfg);
+ uint8_t * cfg_ptr = (uint8_t *)&(blk_state->block_cfg);
memcpy(dst, cfg_ptr + cfg_offset, length);
static struct v3_device_ops dev_ops = {
.free = virtio_free,
- .reset = NULL,
+ .reset = virtio_reset,
.start = NULL,
.stop = NULL,
};
-int v3_virtio_register_cdrom(struct vm_device * dev, struct v3_cd_ops * ops, void * private_data) {
- struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
-
- virtio->block_type = BLOCK_CDROM;
- virtio->cd_ops = ops;
- virtio->backend_data = private_data;
-
- virtio->block_cfg.capacity = ops->get_capacity(private_data);
-
- return 0;
-}
-
-
-int v3_virtio_register_harddisk(struct vm_device * dev, struct v3_hd_ops * ops, void * private_data) {
- struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
-
- virtio->block_type = BLOCK_DISK;
- virtio->hd_ops = ops;
- virtio->backend_data = private_data;
-
- virtio->block_cfg.capacity = ops->get_capacity(private_data);
-
- PrintDebug("Virtio Capacity = %d -- 0x%p\n", (int)(virtio->block_cfg.capacity),
- (void *)(addr_t)(virtio->block_cfg.capacity));
-
- return 0;
-}
-
-
-static int virtio_init(struct guest_info * vm, void * cfg_data) {
- struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
- struct virtio_blk_state * virtio_state = NULL;
+static int register_dev(struct virtio_dev_state * virtio, struct virtio_blk_state * blk_state) {
+ // initialize PCI
struct pci_device * pci_dev = NULL;
+ struct v3_pci_bar bars[6];
+ int num_ports = sizeof(struct virtio_config) + sizeof(struct blk_config);
+ int tmp_ports = num_ports;
+ int i;
- PrintDebug("Initializing VIRTIO Block device\n");
- if (pci_bus == NULL) {
- PrintError("VirtIO devices require a PCI Bus");
- return -1;
- }
+ // This gets the number of ports, rounded up to a power of 2
+ blk_state->io_range_size = 1; // must be a power of 2
- virtio_state = (struct virtio_blk_state *)V3_Malloc(sizeof(struct virtio_blk_state));
- memset(virtio_state, 0, sizeof(struct virtio_blk_state));
-
-
- struct vm_device * dev = v3_allocate_device("LNX_VIRTIO_BLK", &dev_ops, virtio_state);
- if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "LNX_VIRTIO_BLK");
+ while (tmp_ports > 0) {
+ tmp_ports >>= 1;
+ blk_state->io_range_size <<= 1;
+ }
+
+ // this is to account for any low order bits being set in num_ports
+ // if there are none, then num_ports was already a power of 2 so we shift right to reset it
+ if ((num_ports & ((blk_state->io_range_size >> 1) - 1)) == 0) {
+ blk_state->io_range_size >>= 1;
+ }
+
+
+ for (i = 0; i < 6; i++) {
+ bars[i].type = PCI_BAR_NONE;
+ }
+
+ PrintDebug("Virtio-BLK io_range_size = %d\n", blk_state->io_range_size);
+
+ bars[0].type = PCI_BAR_IO;
+ bars[0].default_base_port = -1;
+ bars[0].num_ports = blk_state->io_range_size;
+
+ bars[0].io_read = virtio_io_read;
+ bars[0].io_write = virtio_io_write;
+ bars[0].private_data = blk_state;
+
+ pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE,
+ 0, PCI_AUTO_DEV_NUM, 0,
+ "LNX_VIRTIO_BLK", bars,
+ NULL, NULL, NULL, blk_state);
+
+ if (!pci_dev) {
+ PrintError("Could not register PCI Device\n");
return -1;
}
+
+ pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
+ pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
+
+
+ pci_dev->config_header.device_id = VIRTIO_BLOCK_DEV_ID;
+ pci_dev->config_header.class = PCI_CLASS_STORAGE;
+ pci_dev->config_header.subclass = PCI_STORAGE_SUBCLASS_OTHER;
+
+ pci_dev->config_header.subsystem_id = VIRTIO_BLOCK_SUBDEVICE_ID;
+
+
+ pci_dev->config_header.intr_pin = 1;
+
+ pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
+
+
+ blk_state->pci_dev = pci_dev;
+
+ /* Block configuration */
+ blk_state->virtio_cfg.host_features = VIRTIO_SEG_MAX;
+ blk_state->block_cfg.max_seg = QUEUE_SIZE - 2;
+ // Virtio Block only uses one queue
+ blk_state->queue.queue_size = QUEUE_SIZE;
- // PCI initialization
- {
- struct v3_pci_bar bars[6];
- int num_ports = sizeof(struct virtio_config) + sizeof(struct blk_config);
- int tmp_ports = num_ports;
- int i;
-
+ blk_state->virtio_dev = virtio;
+ blk_reset(blk_state);
- // This gets the number of ports, rounded up to a power of 2
- virtio_state->io_range_size = 1; // must be a power of 2
- while (tmp_ports > 0) {
- tmp_ports >>= 1;
- virtio_state->io_range_size <<= 1;
- }
-
- // this is to account for any low order bits being set in num_ports
- // if there are none, then num_ports was already a power of 2 so we shift right to reset it
- if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
- virtio_state->io_range_size >>= 1;
- }
+ return 0;
+}
- for (i = 0; i < 6; i++) {
- bars[i].type = PCI_BAR_NONE;
- }
+static int connect_fn(struct guest_info * info,
+ void * frontend_data,
+ struct v3_dev_blk_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * private_data) {
- PrintDebug("Virtio-BLK io_range_size = %d\n", virtio_state->io_range_size);
+ struct virtio_dev_state * virtio = (struct virtio_dev_state *)frontend_data;
- bars[0].type = PCI_BAR_IO;
- bars[0].default_base_port = -1;
- bars[0].num_ports = virtio_state->io_range_size;
+ struct virtio_blk_state * blk_state = (struct virtio_blk_state *)V3_Malloc(sizeof(struct virtio_blk_state));
+ memset(blk_state, 0, sizeof(struct virtio_blk_state));
- bars[0].io_read = virtio_io_read;
- bars[0].io_write = virtio_io_write;
- bars[0].private_data = dev;
+ register_dev(virtio, blk_state);
- pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE,
- 0, PCI_AUTO_DEV_NUM, 0,
- "LNX_VIRTIO_BLK", bars,
- NULL, NULL, NULL, dev, NULL);
+ blk_state->ops = ops;
+ blk_state->backend_data = private_data;
- if (!pci_dev) {
- PrintError("Could not register PCI Device\n");
- return -1;
- }
-
- pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
- pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
-
+ blk_state->block_cfg.capacity = ops->get_capacity(private_data);
- pci_dev->config_header.device_id = VIRTIO_BLOCK_DEV_ID;
- pci_dev->config_header.class = PCI_CLASS_STORAGE;
- pci_dev->config_header.subclass = PCI_STORAGE_SUBCLASS_OTHER;
-
- pci_dev->config_header.subsystem_id = VIRTIO_BLOCK_SUBDEVICE_ID;
+ PrintDebug("Virtio Capacity = %d -- 0x%p\n", (int)(virtio->block_cfg.capacity),
+ (void *)(addr_t)(virtio->block_cfg.capacity));
+ return 0;
+}
- pci_dev->config_header.intr_pin = 1;
- pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
+static int virtio_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
+ struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
+ struct virtio_dev_state * virtio_state = NULL;
+ char * name = v3_cfg_val(cfg, "name");
+ PrintDebug("Initializing VIRTIO Block device\n");
- virtio_state->pci_dev = pci_dev;
- virtio_state->pci_bus = pci_bus;
+ if (pci_bus == NULL) {
+ PrintError("VirtIO devices require a PCI Bus");
+ return -1;
}
- /* Block configuration */
- virtio_state->virtio_cfg.host_features = VIRTIO_SEG_MAX;
- virtio_state->block_cfg.max_seg = QUEUE_SIZE - 2;
- // Virtio Block only uses one queue
- virtio_state->queue.queue_size = QUEUE_SIZE;
-
- virtio_reset(dev);
+ virtio_state = (struct virtio_dev_state *)V3_Malloc(sizeof(struct virtio_dev_state));
+ memset(virtio_state, 0, sizeof(struct virtio_dev_state));
+ INIT_LIST_HEAD(&(virtio_state->dev_list));
+ virtio_state->pci_bus = pci_bus;
+ virtio_state->vm = vm;
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state);
+ if (v3_attach_device(vm, dev) == -1) {
+ PrintError("Could not attach device %s\n", name);
+ return -1;
+ }
- virtio_state->backend_data = NULL;
- virtio_state->block_type = BLOCK_NONE;
- virtio_state->hd_ops = NULL;
+ if (v3_dev_add_blk_frontend(vm, name, connect_fn, (void *)virtio_state) == -1) {
+ PrintError("Could not register %s as block frontend\n", name);
+ return -1;
+ }
return 0;
}
-static int virtio_init(struct guest_info * vm, void * cfg_data) {
- struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
+static int virtio_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
+ struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
struct virtio_sym_state * virtio_state = NULL;
struct pci_device * pci_dev = NULL;
+ char * name = v3_cfg_val(cfg, "name");
PrintDebug("Initializing VIRTIO Symbiotic device\n");
memset(virtio_state, 0, sizeof(struct virtio_sym_state));
- struct vm_device * dev = v3_allocate_device("LNX_VIRTIO_SYM", &dev_ops, virtio_state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "LNX_VIRTIO_SYM");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE,
0, PCI_AUTO_DEV_NUM, 0,
"LNX_VIRTIO_SYM", bars,
- NULL, NULL, NULL, dev, NULL);
+ NULL, NULL, NULL, dev);
if (!pci_dev) {
PrintError("Could not register PCI Device\n");
+++ /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/net_cd.h>
-#include <devices/ide.h>
-#include <palacios/vmm_socket.h>
-
-#ifndef CONFIG_DEBUG_IDE
-#undef PrintDebug
-#define PrintDebug(fmt, args...)
-#endif
-
-
-#define NBD_READ_CMD 0x1
-#define NBD_WRITE_CMD 0x2
-#define NBD_CAPACITY_CMD 0x3
-
-#define NBD_STATUS_OK 0x00
-#define NBD_STATUS_ERR 0xff
-
-struct cd_state {
- uint64_t capacity; // in bytes
-
- int socket;
-
- uint32_t ip_addr;
- uint16_t port;
-
- char disk_name[32];
-
- struct vm_device * ide;
-
- uint_t bus;
- uint_t drive;
-};
-
-
-static int send_all(int socket, char * buf, int length) {
- int bytes_sent = 0;
-
- PrintDebug("Sending %d bytes\n", length - bytes_sent);
- while (bytes_sent < length) {
- int tmp_bytes = V3_Send(socket, buf + bytes_sent, length - bytes_sent);
- PrintDebug("Sent %d bytes\n", tmp_bytes);
-
- if (tmp_bytes == 0) {
- PrintError("Connection Closed unexpectedly\n");
- return -1;
- }
-
- bytes_sent += tmp_bytes;
- }
-
- return 0;
-}
-
-
-static int recv_all(int socket, char * buf, int length) {
- int bytes_read = 0;
-
- PrintDebug("Reading %d bytes\n", length - bytes_read);
- while (bytes_read < length) {
- int tmp_bytes = V3_Recv(socket, buf + bytes_read, length - bytes_read);
- PrintDebug("Received %d bytes\n", tmp_bytes);
-
- if (tmp_bytes == 0) {
- PrintError("Connection Closed unexpectedly\n");
- return -1;
- }
-
- bytes_read += tmp_bytes;
- }
-
- return 0;
-}
-
-// CDs always read 2048 byte blocks... ?
-static int cd_read(uint8_t * buf, int block_count, uint64_t lba, void * private_data) {
- struct vm_device * cd_dev = (struct vm_device *)private_data;
- struct cd_state * cd = (struct cd_state *)(cd_dev->private_data);
- uint64_t offset = lba * ATAPI_BLOCK_SIZE;
- int length = block_count * ATAPI_BLOCK_SIZE;
- uint8_t status;
- uint32_t ret_len = 0;
- char nbd_cmd[4] = {0,0,0,0};
-
- nbd_cmd[0] = NBD_READ_CMD;
-
- if (send_all(cd->socket, nbd_cmd, 4) == -1) {
- PrintError("Error sending capacity command\n");
- return -1;
- }
-
- if (send_all(cd->socket, (char *)&offset, 8) == -1) {
- PrintError("Error sending read offset\n");
- return -1;
- }
-
- if (send_all(cd->socket, (char *)&length, 4) == -1) {
- PrintError("Error sending read length\n");
- return -1;
- }
-
- if (recv_all(cd->socket, (char *)&status, 1) == -1) {
- PrintError("Error receiving status\n");
- return -1;
- }
-
- if (status != NBD_STATUS_OK) {
- PrintError("NBD Error....\n");
- return -1;
- }
-
- PrintDebug("Reading Data Ret Length\n");
-
- if (recv_all(cd->socket, (char *)&ret_len, 4) == -1) {
- PrintError("Error receiving Return read length\n");
- return -1;
- }
-
- if (ret_len != length) {
- PrintError("Read length mismatch (req=%d) (result=%d)\n", length, ret_len);
- return -1;
- }
-
- PrintDebug("Reading Data (%d bytes)\n", ret_len);
-
- if (recv_all(cd->socket, (char *)buf, ret_len) == -1) {
- PrintError("Read Data Error\n");
- return -1;
- }
-
- return 0;
-}
-
-
-static uint32_t cd_get_capacity(void * private_data) {
- struct vm_device * cd_dev = (struct vm_device *)private_data;
- struct cd_state * cd = (struct cd_state *)(cd_dev->private_data);
-
- return cd->capacity / ATAPI_BLOCK_SIZE;
-}
-
-static struct v3_cd_ops cd_ops = {
- .read = cd_read,
- .get_capacity = cd_get_capacity,
-};
-
-
-
-
-static int cd_free(struct vm_device * dev) {
- return 0;
-}
-
-static struct v3_device_ops dev_ops = {
- .free = cd_free,
- .reset = NULL,
- .start = NULL,
- .stop = NULL,
-};
-
-
-
-static int socket_init(struct cd_state * cd) {
- char header[64];
-
- PrintDebug("Intializing Net CD\n");
-
- cd->socket = V3_Create_TCP_Socket();
-
- PrintDebug("CD socket: %d\n", cd->socket);
- PrintDebug("Connecting to: %s:%d\n", v3_inet_ntoa(cd->ip_addr), cd->port);
-
- V3_Connect_To_IP(cd->socket, v3_ntohl(cd->ip_addr), cd->port);
-
-
- PrintDebug("Connected to NBD server\n");
-
- //snprintf(header, 64, "V3_NBD_1 %s\n", cd->disk_name);
- strcpy(header, "V3_NBD_1 ");
- strncat(header, cd->disk_name, 32);
- strncat(header, "\n", 1);
-
-
- if (send_all(cd->socket, header, strlen(header)) == -1) {
- PrintError("Error connecting to Network Block Device: %s\n", cd->disk_name);
- return -1;
- }
-
- // Cache Capacity
- {
- char nbd_cmd[4] = {0,0,0,0};
-
- nbd_cmd[0] = NBD_CAPACITY_CMD;
-
- if (send_all(cd->socket, nbd_cmd, 4) == -1) {
- PrintError("Error sending capacity command\n");
- return -1;
- }
-
- if (recv_all(cd->socket, (char *)&(cd->capacity), 8) == -1) {
- PrintError("Error Receiving Capacity\n");
- return -1;
- }
-
- PrintDebug("Capacity: %p\n", (void *)(cd->capacity));
- }
-
- return 0;
-}
-
-static int cd_init(struct guest_info * vm, void * cfg_data) {
- struct net_cd_cfg * cfg = (struct net_cd_cfg *)cfg_data;
- struct cd_state * cd = (struct cd_state *)V3_Malloc(sizeof(struct cd_state));
-
- PrintDebug("Registering Net CD at %s:%d disk=%s\n", cfg->ip_str, cfg->port, cfg->disk_tag);
-
- strncpy(cd->disk_name, cfg->disk_tag, sizeof(cd->disk_name));
- cd->ip_addr = v3_inet_addr(cfg->ip_str);
- cd->port = cfg->port;
-
- cd->ide = (struct vm_device * )v3_find_dev(vm, cfg->ide);
-
- if (cd->ide == 0) {
- PrintError("Could not find backend %s\n", cfg->ide);
- return -1;
- }
-
- cd->bus = cfg->bus;
- cd->drive = cfg->drive;
-
- struct vm_device * dev = v3_allocate_device("NET-CD", &dev_ops, cd);
-
-
- if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "NET-CD");
- return -1;
- }
-
- if (socket_init(cd) == -1) {
- PrintError("Could not initialize socket connection\n");
- return -1;
- }
-
- PrintDebug("Registering CD\n");
-
- if (v3_ide_register_cdrom(cd->ide, cd->bus, cd->drive, "NET-CD", &cd_ops, dev) == -1) {
- return -1;
- }
-
- PrintDebug("intialization done\n");
-
- return 0;
-}
-
-
-
-
-device_register("NET-CD", cd_init)
*/
#include <palacios/vmm.h>
-#include <devices/net_hd.h>
-#include <devices/ide.h>
+#include <palacios/vmm_dev_mgr.h>
#include <palacios/vmm_socket.h>
#ifndef CONFIG_DEBUG_IDE
#define NBD_STATUS_ERR 0xff
-struct hd_state {
+struct disk_state {
uint64_t capacity; // in bytes
int socket;
char disk_name[32];
- struct vm_device * ide;
-
- uint_t bus;
- uint_t drive;
};
// HDs always read 512 byte blocks... ?
-static int hd_read(uint8_t * buf, int sector_count, uint64_t lba, void * private_data) {
- struct vm_device * hd_dev = (struct vm_device *)private_data;
- struct hd_state * hd = (struct hd_state *)(hd_dev->private_data);
- int offset = lba * HD_SECTOR_SIZE;
- int length = sector_count * HD_SECTOR_SIZE;
+static int read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
+ struct disk_state * disk = (struct disk_state *)private_data ;
uint8_t status;
uint32_t ret_len = 0;
char nbd_cmd[4] = {0,0,0,0};
+ uint64_t offset = lba;
+ uint64_t length = num_bytes;
nbd_cmd[0] = NBD_READ_CMD;
- if (send_all(hd->socket, nbd_cmd, 4) == -1) {
+ if (send_all(disk->socket, nbd_cmd, 4) == -1) {
PrintError("Error sending read command\n");
return -1;
}
- if (send_all(hd->socket, (char *)&offset, 8) == -1) {
+ if (send_all(disk->socket, (char *)&offset, 8) == -1) {
PrintError("Error sending read offset\n");
return -1;
}
- if (send_all(hd->socket, (char *)&length, 4) == -1) {
+ if (send_all(disk->socket, (char *)&length, 4) == -1) {
PrintError("Error sending read length\n");
return -1;
}
- if (recv_all(hd->socket, (char *)&status, 1) == -1) {
+ if (recv_all(disk->socket, (char *)&status, 1) == -1) {
PrintError("Error receiving status\n");
return -1;
}
PrintDebug("Reading Data Ret Length\n");
- if (recv_all(hd->socket, (char *)&ret_len, 4) == -1) {
+ if (recv_all(disk->socket, (char *)&ret_len, 4) == -1) {
PrintError("Error receiving Return read length\n");
return -1;
}
PrintDebug("Reading Data (%d bytes)\n", ret_len);
- if (recv_all(hd->socket, (char *)buf, ret_len) == -1) {
+ if (recv_all(disk->socket, (char *)buf, ret_len) == -1) {
PrintError("Read Data Error\n");
return -1;
}
}
-static int hd_write(uint8_t * buf, int sector_count, uint64_t lba, void * private_data) {
- struct vm_device * hd_dev = (struct vm_device *)private_data;
- struct hd_state * hd = (struct hd_state *)(hd_dev->private_data);
- int offset = lba * HD_SECTOR_SIZE;
- int length = sector_count * HD_SECTOR_SIZE;
+static int write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
+ struct disk_state * disk = (struct disk_state *)private_data ;
+ uint64_t offset = lba;
+ int length = num_bytes;
uint8_t status;
char nbd_cmd[4] = {0,0,0,0};
nbd_cmd[0] = NBD_WRITE_CMD;
- if (send_all(hd->socket, nbd_cmd, 4) == -1) {
+ if (send_all(disk->socket, nbd_cmd, 4) == -1) {
PrintError("Error sending write command\n");
return -1;
}
- if (send_all(hd->socket, (char *)&offset, 8) == -1) {
+ if (send_all(disk->socket, (char *)&offset, 8) == -1) {
PrintError("Error sending write offset\n");
return -1;
}
- if (send_all(hd->socket, (char *)&length, 4) == -1) {
+ if (send_all(disk->socket, (char *)&length, 4) == -1) {
PrintError("Error sending write length\n");
return -1;
}
PrintDebug("Writing Data (%d bytes)\n", length);
- if (send_all(hd->socket, (char *)buf, length) == -1) {
+ if (send_all(disk->socket, (char *)buf, length) == -1) {
PrintError("Write Data Error\n");
return -1;
}
- if (recv_all(hd->socket, (char *)&status, 1) == -1) {
+ if (recv_all(disk->socket, (char *)&status, 1) == -1) {
PrintError("Error receiving status\n");
return -1;
}
}
-static uint64_t hd_get_capacity(void * private_data) {
- struct vm_device * hd_dev = (struct vm_device *)private_data;
- struct hd_state * hd = (struct hd_state *)(hd_dev->private_data);
+static uint64_t get_capacity(void * private_data) {
+ struct disk_state * disk = (struct disk_state *)private_data;
- return hd->capacity / HD_SECTOR_SIZE;
+ return disk->capacity;
}
-static struct v3_hd_ops hd_ops = {
- .read = hd_read,
- .write = hd_write,
- .get_capacity = hd_get_capacity,
+static struct v3_dev_blk_ops blk_ops = {
+ .read = read,
+ .write = write,
+ .get_capacity = get_capacity,
};
-static int hd_free(struct vm_device * dev) {
+static int disk_free(struct vm_device * dev) {
return 0;
}
static struct v3_device_ops dev_ops = {
- .free = hd_free,
+ .free = disk_free,
.reset = NULL,
.start = NULL,
.stop = NULL,
};
-static int socket_init(struct hd_state * hd) {
+static int socket_init(struct disk_state * disk) {
char header[64];
- PrintDebug("Intializing Net HD\n");
+ PrintDebug("Intializing Net Disk\n");
- hd->socket = V3_Create_TCP_Socket();
+ disk->socket = V3_Create_TCP_Socket();
- PrintDebug("HD socket: %d\n", hd->socket);
- PrintDebug("Connecting to: %s:%d\n", v3_inet_ntoa(hd->ip_addr), hd->port);
+ PrintDebug("DISK socket: %d\n", disk->socket);
+ PrintDebug("Connecting to: %s:%d\n", v3_inet_ntoa(disk->ip_addr), disk->port);
- V3_Connect_To_IP(hd->socket, v3_ntohl(hd->ip_addr), hd->port);
+ V3_Connect_To_IP(disk->socket, v3_ntohl(disk->ip_addr), disk->port);
PrintDebug("Connected to NBD server\n");
//snprintf(header, 64, "V3_NBD_1 %s\n", cd->disk_name);
strcpy(header, "V3_NBD_1 ");
- strncat(header, hd->disk_name, 32);
+ strncat(header, disk->disk_name, 32);
strncat(header, "\n", 1);
- if (send_all(hd->socket, header, strlen(header)) == -1) {
- PrintError("Error connecting to Network Block Device: %s\n", hd->disk_name);
+ if (send_all(disk->socket, header, strlen(header)) == -1) {
+ PrintError("Error connecting to Network Block Device: %s\n", disk->disk_name);
return -1;
}
- // Cache Capacity
+ // store local copy of capacity
{
char nbd_cmd[4] = {0,0,0,0};
nbd_cmd[0] = NBD_CAPACITY_CMD;
- if (send_all(hd->socket, nbd_cmd, 4) == -1) {
+ if (send_all(disk->socket, nbd_cmd, 4) == -1) {
PrintError("Error sending capacity command\n");
return -1;
}
- if (recv_all(hd->socket, (char *)&(hd->capacity), 8) == -1) {
+ if (recv_all(disk->socket, (char *)&(disk->capacity), 8) == -1) {
PrintError("Error Receiving Capacity\n");
return -1;
}
- PrintDebug("Capacity: %p\n", (void *)(hd->capacity));
+ PrintDebug("Capacity: %p\n", (void *)(disk->capacity));
}
}
-static int hd_init(struct guest_info * vm, void * cfg_data) {
- struct hd_state * hd = (struct hd_state *)V3_Malloc(sizeof(struct hd_state));
- struct net_hd_cfg * cfg = (struct net_hd_cfg *)cfg_data;
-
- PrintDebug("Registering Net HD at %s:%d disk=%s\n", cfg->ip_str, cfg->port, cfg->disk_tag);
+static int disk_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
+ struct disk_state * disk = (struct disk_state *)V3_Malloc(sizeof(struct disk_state));
- strncpy(hd->disk_name, cfg->disk_tag, sizeof(hd->disk_name));
- hd->ip_addr = v3_inet_addr(cfg->ip_str);
- hd->port = cfg->port;
+ char * ip_str = v3_cfg_val(cfg, "IP");
+ char * port_str = v3_cfg_val(cfg, "port");
+ char * disk_tag = v3_cfg_val(cfg, "tag");
+ char * name = v3_cfg_val(cfg, "name");
- hd->ide = v3_find_dev(vm, cfg->ide);
+ v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
- if (hd->ide == 0) {
- PrintError("Could not find backend %s\n", cfg->ide);
- return -1;
- }
+ PrintDebug("Registering Net disk at %s:%s disk=%s\n", ip_str, port_str, disk_tag);
- hd->bus = cfg->bus;
- hd->drive = cfg->drive;
+ strncpy(disk->disk_name, disk_tag, sizeof(disk->disk_name));
+ disk->ip_addr = v3_inet_addr(ip_str);
+ disk->port = atoi(port_str);
- struct vm_device * dev = v3_allocate_device("NET-HD", &dev_ops, hd);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, disk);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "NET-HD");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
- if (socket_init(hd) == -1) {
+ if (socket_init(disk) == -1) {
PrintError("could not initialize network connection\n");
return -1;
}
+ PrintDebug("Registering Disk\n");
- PrintDebug("Registering HD\n");
-
- if (v3_ide_register_harddisk(hd->ide, hd->bus, hd->drive, "V3-NET-HD", &hd_ops, dev) == -1) {
+ if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"),
+ &blk_ops, frontend_cfg, disk) == -1) {
+ PrintError("Could not connect %s to frontend\n", name);
return -1;
}
-
+
PrintDebug("intialization done\n");
return 0;
}
-device_register("NET-HD", hd_init)
+device_register("NETDISK", disk_init)
#include <palacios/vmm_lock.h>
#include <devices/ide.h>
+#include <palacios/vmm_intr.h>
+#include <palacios/vmm_host_events.h>
+#include <palacios/vm_guest.h>
#ifndef CONFIG_DEBUG_NVRAM
#undef PrintDebug
-static int nvram_init(struct guest_info * vm, void * cfg_data) {
+static int nvram_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct nvram_internal * nvram_state = NULL;
- struct vm_device * ide = v3_find_dev(vm, (char *)cfg_data);
+ struct vm_device * ide = v3_find_dev(vm, v3_cfg_val(cfg, "storage"));
+ char * name = v3_cfg_val(cfg, "name");
if (!ide) {
PrintError("Could not find IDE device\n");
nvram_state->ide = ide;
- struct vm_device * dev = v3_allocate_device("NVRAM", &dev_ops, nvram_state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, nvram_state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "NVRAM");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
-static int debug_init(struct guest_info * vm, void * cfg_data) {
+static int debug_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct debug_state * state = NULL;
+ char * name = v3_cfg_val(cfg, "name");
state = (struct debug_state *)V3_Malloc(sizeof(struct debug_state));
PrintDebug("Creating OS Debug Device\n");
- struct vm_device * dev = v3_allocate_device("OS_DEBUG", &dev_ops, state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "OS_DEBUG");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
-static int net_init(struct guest_info * vm, void * cfg_data) {
+static int net_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct nic_state * state = NULL;
+ char * name = v3_cfg_val(cfg, "name");
state = (struct nic_state *)V3_Malloc(sizeof(struct nic_state));
PrintDebug("Creating VMNet Device\n");
- struct vm_device * dev = v3_allocate_device("VMNET", &dev_ops, state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "VMNET");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
* and the University of New Mexico. You can find out more at
* http://www.v3vee.org
*
+ * Copyright (c) 2009, Jack Lange <jarusl@cs.northwestern.edu>
* Copyright (c) 2009, Lei Xia <lxia@northwestern.edu>
* Copyright (c) 2009, Chang Seok Bae <jhuell@gmail.com>
- * Copyright (c) 2009, Jack Lange <jarusl@cs.northwestern.edu>
* Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org>
* All rights reserved.
*
- * Author: Lei Xia <lxia@northwestern.edu>
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ * Lei Xia <lxia@northwestern.edu>
* Chang Seok Bae <jhuell@gmail.com>
- * 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_io.h>
#include <palacios/vmm_intr.h>
#include <palacios/vmm_rbtree.h>
+#include <palacios/vmm_dev_mgr.h>
#include <devices/pci.h>
#include <devices/pci_types.h>
+
+
#ifndef CONFIG_DEBUG_PCI
#undef PrintDebug
#define PrintDebug(fmt, args...)
}
-static int bar_update(struct pci_device * pci, int bar_num, uint32_t new_val) {
+static int bar_update(struct guest_info * info, struct pci_device * pci, int bar_num, uint32_t new_val) {
struct v3_pci_bar * bar = &(pci->bar[bar_num]);
PrintDebug("Updating BAR Register (Dev=%s) (bar=%d) (old_val=0x%x) (new_val=0x%x)\n",
PrintDebug("Rehooking PCI IO port (old port=%u) (new port=%u)\n",
PCI_IO_BASE(bar->val) + i, PCI_IO_BASE(new_val) + i);
- v3_unhook_io_port(pci->vm_dev->vm, PCI_IO_BASE(bar->val) + i);
+ v3_unhook_io_port(info, PCI_IO_BASE(bar->val) + i);
- if (v3_hook_io_port(pci->vm_dev->vm, PCI_IO_BASE(new_val) + i,
+ if (v3_hook_io_port(info, PCI_IO_BASE(new_val) + i,
bar->io_read, bar->io_write,
bar->private_data) == -1) {
PrintError("Could not hook PCI IO port (old port=%u) (new port=%u)\n",
PCI_IO_BASE(bar->val) + i, PCI_IO_BASE(new_val) + i);
- v3_print_io_map(pci->vm_dev->vm);
+ v3_print_io_map(info);
return -1;
}
}
break;
}
case PCI_BAR_MEM32: {
- v3_unhook_mem(pci->vm_dev->vm, (addr_t)(bar->val));
+ v3_unhook_mem(info, (addr_t)(bar->val));
if (bar->mem_read) {
- v3_hook_full_mem(pci->vm_dev->vm, PCI_MEM32_BASE(new_val),
+ v3_hook_full_mem(info, PCI_MEM32_BASE(new_val),
PCI_MEM32_BASE(new_val) + (bar->num_pages * PAGE_SIZE_4KB),
- bar->mem_read, bar->mem_write, pci->vm_dev);
+ bar->mem_read, bar->mem_write, pci->priv_data);
} else {
PrintError("Write hooks not supported for PCI\n");
return -1;
// check special flags....
// bar_update
- if (bar_update(pci_dev, i, *(uint32_t *)(pci_dev->config_space + bar_offset)) == -1) {
+ if (bar_update(vmdev->vm, pci_dev, i, *(uint32_t *)(pci_dev->config_space + bar_offset)) == -1) {
PrintError("PCI Device %s: Bar update Error Bar=%d\n", pci_dev->name, i);
return -1;
}
-static int pci_init(struct guest_info * vm, void * cfg_data) {
+static int pci_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct pci_internal * pci_state = V3_Malloc(sizeof(struct pci_internal));
int i = 0;
+ char * name = v3_cfg_val(cfg, "name");
PrintDebug("PCI internal at %p\n",(void *)pci_state);
- struct vm_device * dev = v3_allocate_device("PCI", &dev_ops, pci_state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, pci_state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "PCI");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
device_register("PCI", pci_init)
-static inline int init_bars(struct pci_device * pci_dev) {
+static inline int init_bars(struct guest_info * info, struct pci_device * pci_dev) {
int i = 0;
for (i = 0; i < 6; i++) {
for (j = 0; j < pci_dev->bar[i].num_ports; j++) {
// hook IO
if (pci_dev->bar[i].default_base_port != 0xffff) {
- if (v3_hook_io_port(pci_dev->vm_dev->vm, pci_dev->bar[i].default_base_port + j,
+ if (v3_hook_io_port(info, pci_dev->bar[i].default_base_port + j,
pci_dev->bar[i].io_read, pci_dev->bar[i].io_write,
pci_dev->bar[i].private_data) == -1) {
PrintError("Could not hook default io port %x\n", pci_dev->bar[i].default_base_port + j);
// hook memory
if (pci_dev->bar[i].mem_read) {
// full hook
- v3_hook_full_mem(pci_dev->vm_dev->vm, pci_dev->bar[i].default_base_addr,
+ v3_hook_full_mem(info, pci_dev->bar[i].default_base_addr,
pci_dev->bar[i].default_base_addr + (pci_dev->bar[i].num_pages * PAGE_SIZE_4KB),
- pci_dev->bar[i].mem_read, pci_dev->bar[i].mem_write, pci_dev->vm_dev);
+ pci_dev->bar[i].mem_read, pci_dev->bar[i].mem_write, pci_dev->priv_data);
} else if (pci_dev->bar[i].mem_write) {
// write hook
PrintError("Write hooks not supported for PCI devices\n");
int (*config_update)(uint_t reg_num, void * src, uint_t length, void * priv_data),
int (*cmd_update)(struct pci_device *pci_dev, uchar_t io_enabled, uchar_t mem_enabled),
int (*ext_rom_update)(struct pci_device * pci_dev),
- struct vm_device * dev, void * priv_data) {
+ void * priv_data) {
struct pci_internal * pci_state = (struct pci_internal *)pci->private_data;
struct pci_bus * bus = &(pci_state->bus_list[bus_num]);
pci_dev->fn_num = fn_num;
strncpy(pci_dev->name, name, sizeof(pci_dev->name));
- pci_dev->vm_dev = dev;
pci_dev->priv_data = priv_data;
// register update callbacks
}
}
- if (init_bars(pci_dev) == -1) {
+ if (init_bars(pci->vm, pci_dev) == -1) {
PrintError("could not initialize bar registers\n");
return NULL;
}
const char * name,
int (*config_write)(uint_t reg_num, void * src, uint_t length, void * private_data),
int (*config_read)(uint_t reg_num, void * dst, uint_t length, void * private_data),
- struct vm_device * dev,
void * private_data) {
struct pci_internal * pci_state = (struct pci_internal *)pci->private_data;
pci_dev->fn_num = fn_num;
strncpy(pci_dev->name, name, sizeof(pci_dev->name));
- pci_dev->vm_dev = dev;
pci_dev->priv_data = private_data;
// register update callbacks
#include <palacios/vmm_dev_mgr.h>
#include <palacios/vmm_sprintf.h>
#include <palacios/vmm_lowlevel.h>
+#include <palacios/vm_guest.h> // must include this to avoid dependency issue
#include <palacios/vmm_sym_iface.h>
#include <devices/pci.h>
#include <devices/pci_types.h>
-#include <devices/pci_passthrough.h>
// Hardcoded... Are these standard??
bus_num, -1, 0,
state->name, bars,
pt_config_update, NULL, NULL,
- dev, dev);
+ dev);
// This will overwrite the bar registers.. but that should be ok.
memcpy(pci_dev->config_space, (uint8_t *)&(state->real_hdr), sizeof(struct pci_config_header));
-static int passthrough_init(struct guest_info * info, void * cfg_data) {
- struct pci_passthrough_cfg * cfg = (struct pci_passthrough_cfg *)cfg_data;
+static int passthrough_init(struct guest_info * info, v3_cfg_tree_t * cfg) {
struct pt_dev_state * state = V3_Malloc(sizeof(struct pt_dev_state));
struct vm_device * dev = NULL;
- struct vm_device * pci = v3_find_dev(info, cfg->pci_bus_name);
-
+ struct vm_device * pci = v3_find_dev(info, v3_cfg_val(cfg, "bus"));
+ char * name = v3_cfg_val(cfg, "name");
memset(state, 0, sizeof(struct pt_dev_state));
}
state->pci_bus = pci;
- strncpy(state->name, cfg->name, 32);
-
-
+ strncpy(state->name, name, 32);
- dev = v3_allocate_device("PCI_PASSTHROUGH", &dev_ops, state);
+ dev = v3_allocate_device(name, &dev_ops, state);
if (v3_attach_device(info, dev) == -1) {
- PrintError("Could not attach device %s\n", "PCI_PASSTHROUGH");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
- if (find_real_pci_dev(cfg->vendor_id, cfg->device_id, state) == -1) {
- PrintError("Could not find PCI Device %x:%x\n", cfg->vendor_id, cfg->device_id);
+ if (find_real_pci_dev(atox(v3_cfg_val(cfg, "vendor_id")),
+ atox(v3_cfg_val(cfg, "device_id")),
+ state) == -1) {
+ PrintError("Could not find PCI Device %s:%s\n",
+ v3_cfg_val(cfg, "vendor_id"),
+ v3_cfg_val(cfg, "device_id"));
return 0;
}
setup_virt_pci_dev(info, dev);
- v3_hook_irq(info, 59, irq_handler, dev);
- v3_hook_irq(info, 64, irq_handler, dev);
+ v3_hook_irq(info, atoi(v3_cfg_val(cfg, "irq")), irq_handler, dev);
+ // v3_hook_irq(info, 64, irq_handler, dev);
return 0;
}
#include <palacios/vmm.h>
+#include <palacios/vmm_dev_mgr.h>
+#include <palacios/vmm_intr.h>
+
#include <devices/pci.h>
#include <devices/southbridge.h>
+
struct iort_reg {
union {
uint8_t value;
pci_dev = v3_pci_register_device(piix3->pci_bus, PCI_MULTIFUNCTION,
bus_num, -1, 0,
"PIIX3", bars,
- NULL, NULL, NULL, dev, NULL);
+ NULL, NULL, NULL, dev);
if (pci_dev == NULL) {
PrintError("Could not register PCI Device for PIIX3\n");
return -1;
return 0;
}
-static int piix3_init(struct guest_info * vm, void * cfg_data) {
+static int piix3_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct v3_southbridge * piix3 = (struct v3_southbridge *)V3_Malloc(sizeof(struct v3_southbridge));
struct vm_device * dev = NULL;
- struct vm_device * pci = v3_find_dev(vm, (char *)cfg_data);
+ struct vm_device * pci = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
+ char * name = v3_cfg_val(cfg, "name");
if (!pci) {
PrintError("Could not find PCI device\n");
piix3->pci_bus = pci;
piix3->type = V3_SB_PIIX3;
- dev = v3_allocate_device("PIIX3", &dev_ops, piix3);
+ dev = v3_allocate_device(name, &dev_ops, piix3);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "PIIX3");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
+++ /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/ram_cd.h>
-#include <palacios/vmm_dev_mgr.h>
-#include <devices/ide.h>
-
-#ifndef CONFIG_DEBUG_IDE
-#undef PrintDebug
-#define PrintDebug(fmt, args...)
-#endif
-
-
-struct cd_state {
- addr_t disk_image;
- uint32_t capacity; // in bytes
-
- struct vm_device * ide;
-
- uint_t bus;
- uint_t drive;
-};
-
-
-// CDs always read 2048 byte blocks... ?
-static int cd_read(uint8_t * buf, int block_count, uint64_t lba, void * private_data) {
- struct vm_device * cd_dev = (struct vm_device *)private_data;
- struct cd_state * cd = (struct cd_state *)(cd_dev->private_data);
- int offset = lba * ATAPI_BLOCK_SIZE;
- int length = block_count * ATAPI_BLOCK_SIZE;
-
- PrintDebug("Reading RAM CD at (LBA=%d) offset %d (length=%d)\n", (uint32_t)lba, offset, length);
-
- memcpy(buf, (uint8_t *)(cd->disk_image + offset), length);
-
- return 0;
-}
-
-
-static uint32_t cd_get_capacity(void * private_data) {
- struct vm_device * cd_dev = (struct vm_device *)private_data;
- struct cd_state * cd = (struct cd_state *)(cd_dev->private_data);
- PrintDebug("Querying RAM CD capacity (bytes=%d) (ret = %d)\n",
- cd->capacity, cd->capacity / ATAPI_BLOCK_SIZE);
- return cd->capacity / ATAPI_BLOCK_SIZE;
-}
-
-static struct v3_cd_ops cd_ops = {
- .read = cd_read,
- .get_capacity = cd_get_capacity,
-};
-
-
-
-
-static int cd_free(struct vm_device * dev) {
- return 0;
-}
-
-static struct v3_device_ops dev_ops = {
- .free = cd_free,
- .reset = NULL,
- .start = NULL,
- .stop = NULL,
-};
-
-
-static int cd_init(struct guest_info * vm, void * cfg_data) {
- struct cd_state * cd = NULL;
- struct ram_cd_cfg * cfg = (struct ram_cd_cfg *)cfg_data;
-
- if (cfg->size % ATAPI_BLOCK_SIZE) {
- PrintError("CD image must be an integral of block size (ATAPI_BLOCK_SIZE=%d)\n", ATAPI_BLOCK_SIZE);
- return -1;
- }
-
- cd = (struct cd_state *)V3_Malloc(sizeof(struct cd_state));
-
- PrintDebug("Registering Ram CD at %p (size=%d)\n", (void *)cfg->ramdisk, cfg->size);
-
-
- cd->disk_image = cfg->ramdisk;
- cd->capacity = cfg->size;
-
- cd->ide = v3_find_dev(vm, cfg->ide);
-
- if (cd->ide == 0) {
- PrintError("Could not find backend %s\n", cfg->ide);
- return -1;
- }
-
- cd->bus = cfg->bus;
- cd->drive = cfg->drive;
-
- struct vm_device * dev = v3_allocate_device("RAM-CD", &dev_ops, cd);
-
- if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "RAM-CD");
- return -1;
- }
-
-
- if (v3_ide_register_cdrom(cd->ide, cd->bus, cd->drive, "RAM-CD", &cd_ops, dev) == -1) {
- return -1;
- }
-
- return 0;
-}
-
-
-device_register("RAM-CD", cd_init)
+++ /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/ram_hd.h>
-#include <devices/ide.h>
-
-
-
-#ifndef CONFIG_DEBUG_IDE
-#undef PrintDebug
-#define PrintDebug(fmt, args...)
-#endif
-
-struct hd_state {
- addr_t disk_image;
- uint32_t capacity; // in bytes
-
- struct vm_device * ide;
-
- uint_t bus;
- uint_t drive;
-};
-
-
-// HDs always read 512 byte blocks... ?
-static int hd_read(uint8_t * buf, int sector_count, uint64_t lba, void * private_data) {
- struct vm_device * hd_dev = (struct vm_device *)private_data;
- struct hd_state * hd = (struct hd_state *)(hd_dev->private_data);
- int offset = lba * HD_SECTOR_SIZE;
- int length = sector_count * HD_SECTOR_SIZE;
-
- // PrintDebug("Reading RAM HD at (LBA=%d) offset %d (length=%d)\n", (uint32_t)lba, offset, length);
-
- memcpy(buf, (uint8_t *)(hd->disk_image + offset), length);
-
- return 0;
-}
-
-
-static int hd_write(uint8_t * buf, int sector_count, uint64_t lba, void * private_data) {
- struct vm_device * hd_dev = (struct vm_device *)private_data;
- struct hd_state * hd = (struct hd_state *)(hd_dev->private_data);
- int offset = lba * HD_SECTOR_SIZE;
- int length = sector_count * HD_SECTOR_SIZE;
-
- memcpy((uint8_t *)(hd->disk_image + offset), buf, length);
-
- return 0;
-}
-
-
-static uint64_t hd_get_capacity(void * private_data) {
- struct vm_device * hd_dev = (struct vm_device *)private_data;
- struct hd_state * hd = (struct hd_state *)(hd_dev->private_data);
- PrintDebug("Querying RAM HD capacity (bytes=%d) (ret = %d)\n",
- hd->capacity, hd->capacity / HD_SECTOR_SIZE);
- return hd->capacity / HD_SECTOR_SIZE;
-}
-
-static struct v3_hd_ops hd_ops = {
- .read = hd_read,
- .write = hd_write,
- .get_capacity = hd_get_capacity,
-};
-
-
-
-
-static int hd_free(struct vm_device * dev) {
- return 0;
-}
-
-static struct v3_device_ops dev_ops = {
- .free = hd_free,
- .reset = NULL,
- .start = NULL,
- .stop = NULL,
-};
-
-
-
-
-static int hd_init(struct guest_info * vm, void * cfg_data) {
- struct hd_state * hd = NULL;
- struct ram_hd_cfg * cfg = (struct ram_hd_cfg *)cfg_data;
-
- if (cfg->size % HD_SECTOR_SIZE) {
- PrintError("HD image must be an integral of sector size (HD_SECTOR_SIZE=%d)\n", HD_SECTOR_SIZE);
- return -1;
- }
-
- hd = (struct hd_state *)V3_Malloc(sizeof(struct hd_state));
-
- PrintDebug("Registering Ram HDD at %p (size=%d)\n", (void *)cfg->ramdisk, cfg->size);
-
- hd->disk_image = cfg->ramdisk;
- hd->capacity = cfg->size;
-
- hd->ide = v3_find_dev(vm, cfg->ide);
-
- if (hd->ide == 0) {
- PrintError("Could not find backend %s\n", cfg->ide);
- return -1;
- }
-
- hd->bus = cfg->bus;
- hd->drive = cfg->drive;
-
- struct vm_device * dev = v3_allocate_device("RAM-HD", &dev_ops, hd);
-
- if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "RAM-HD");
- return -1;
- }
-
-
- if (v3_ide_register_harddisk(hd->ide, hd->bus, hd->drive, "RAM-HD", &hd_ops, dev) == -1) {
- return -1;
- }
-
- return 0;
-}
-
-
-device_register("RAM-HD", hd_init)
--- /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 <palacios/vmm_dev_mgr.h>
+
+
+#ifndef CONFIG_DEBUG_RAMDISK
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
+
+struct disk_state {
+ uint8_t * disk_image;
+ uint32_t capacity; // in bytes
+};
+
+
+static int read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
+ struct disk_state * disk = (struct disk_state *)private_data;
+
+ PrintDebug("Reading %d bytes from %p to %p\n", (uint32_t)num_bytes, (uint8_t *)(disk->disk_image + lba), buf);
+
+ memcpy(buf, (uint8_t *)(disk->disk_image + lba), num_bytes);
+
+ return 0;
+}
+
+
+static int write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
+ struct disk_state * disk = (struct disk_state *)private_data;
+
+ PrintDebug("Writing %d bytes from %p to %p\n", (uint32_t)num_bytes, buf, (uint8_t *)(disk->disk_image + lba));
+
+ memcpy((uint8_t *)(disk->disk_image + lba), buf, num_bytes);
+
+ return 0;
+}
+
+
+static uint64_t get_capacity(void * private_data) {
+ struct disk_state * disk = (struct disk_state *)private_data;
+
+ PrintDebug("Querying RAMDISK capacity %d\n",
+ (uint32_t)(disk->capacity));
+
+ return disk->capacity;
+}
+
+static struct v3_dev_blk_ops blk_ops = {
+ .read = read,
+ .write = write,
+ .get_capacity = get_capacity,
+};
+
+
+
+
+static int disk_free(struct vm_device * dev) {
+ return 0;
+}
+
+static struct v3_device_ops dev_ops = {
+ .free = disk_free,
+ .reset = NULL,
+ .start = NULL,
+ .stop = NULL,
+};
+
+
+
+
+static int disk_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
+ struct disk_state * disk = NULL;
+ struct v3_cfg_file * file = NULL;
+ char * name = v3_cfg_val(cfg, "name");
+ char * filename = v3_cfg_val(cfg, "file");
+
+ v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
+
+ disk = (struct disk_state *)V3_Malloc(sizeof(struct disk_state));
+ memset(disk, 0, sizeof(struct disk_state));
+
+
+ if (!filename) {
+ PrintError("Missing filename (%s) for %s\n", filename, name);
+ return -1;
+ }
+
+ file = v3_cfg_get_file(vm, filename);
+
+ if (!file) {
+ PrintError("Invalid ramdisk file: %s\n", filename);
+ return -1;
+ }
+
+ disk->disk_image = file->data;
+ disk->capacity = file->size;
+ PrintDebug("Registering RAMDISK at %p (size=%d)\n",
+ (void *)file->data, (uint32_t)file->size);
+
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, disk);
+
+ if (v3_attach_device(vm, dev) == -1) {
+ PrintError("Could not attach device %s\n", name);
+ return -1;
+ }
+
+ if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"),
+ &blk_ops, frontend_cfg, disk) == -1) {
+ PrintError("Could not connect %s to frontend %s\n",
+ name, v3_cfg_val(frontend_cfg, "tag"));
+ return -1;
+ }
+
+
+ return 0;
+}
+
+
+device_register("RAMDISK", disk_init)
#include <palacios/vmm.h>
#include <palacios/vmm_dev_mgr.h>
-#include <devices/lnx_virtio_blk.h>
#include <palacios/vmm_sym_swap.h>
-#define SWAP_CAPACITY (150 * 1024 * 1024)
#ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
#include <palacios/vmm_telemetry.h>
struct swap_state {
int active;
- struct vm_device * blk_dev;
-
uint_t swapped_pages;
uint_t unswapped_pages;
PrintDebug("SymSwap: Getting Capacity %d\n", (uint32_t)(swap->capacity));
- return swap->capacity / HD_SECTOR_SIZE;
+ return swap->capacity;
}
-static int swap_read(uint8_t * buf, int sector_count, uint64_t lba, void * private_data) {
+static int swap_read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
struct vm_device * dev = (struct vm_device *)private_data;
struct swap_state * swap = (struct swap_state *)(dev->private_data);
- uint32_t offset = lba * HD_SECTOR_SIZE;
- uint32_t length = sector_count * HD_SECTOR_SIZE;
+ uint32_t offset = lba;
+ uint32_t length = num_bytes;
/*
-static int swap_write(uint8_t * buf, int sector_count, uint64_t lba, void * private_data) {
+static int swap_write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
struct vm_device * dev = (struct vm_device *)private_data;
struct swap_state * swap = (struct swap_state *)(dev->private_data);
- uint32_t offset = lba * HD_SECTOR_SIZE;
- uint32_t length = sector_count * HD_SECTOR_SIZE;
+ uint32_t offset = lba;
+ uint32_t length = num_bytes;
/*
PrintDebug("SymSwap: Writing %d bytes to %p from %p\n", length,
}
-static struct v3_hd_ops hd_ops = {
+static struct v3_dev_blk_ops blk_ops = {
.read = swap_read,
.write = swap_write,
.get_capacity = swap_get_capacity,
-static int swap_init(struct guest_info * vm, void * cfg_data) {
+static int swap_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct swap_state * swap = NULL;
- struct vm_device * virtio_blk = v3_find_dev(vm, (char *)cfg_data);
+ v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
+ uint32_t capacity = atoi(v3_cfg_val(cfg, "size")) * 1024 * 1024;
+ char * name = v3_cfg_val(cfg, "name");
- if (!virtio_blk) {
- PrintError("could not find Virtio backend\n");
+ if (!frontend_cfg) {
+ PrintError("Initializing sym swap without a frontend device\n");
return -1;
}
PrintDebug("Creating Swap Device\n");
- if (virtio_blk == NULL) {
- PrintError("Swap device requires a virtio block device\n");
- return -1;
- }
-
- swap = (struct swap_state *)V3_Malloc(sizeof(struct swap_state) + ((SWAP_CAPACITY / 4096) / 8));
+ swap = (struct swap_state *)V3_Malloc(sizeof(struct swap_state) + ((capacity / 4096) / 8));
- swap->blk_dev = virtio_blk;
- swap->capacity = SWAP_CAPACITY;
+ swap->capacity = capacity;
swap->swapped_pages = 0;
swap->unswapped_pages = 0;
swap->active = 0;
swap->hdr = (union swap_header *)swap;
-
swap->swap_base_addr = (addr_t)V3_AllocPages(swap->capacity / 4096);
swap->swap_space = (uint8_t *)V3_VAddr((void *)(swap->swap_base_addr));
- memset(swap->swap_space, 0, SWAP_CAPACITY);
+ memset(swap->swap_space, 0, swap->capacity);
- memset(swap->usage_map, 0, ((SWAP_CAPACITY / 4096) / 8));
+ memset(swap->usage_map, 0, ((swap->capacity / 4096) / 8));
- struct vm_device * dev = v3_allocate_device("SYM_SWAP", &dev_ops, swap);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, swap);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "SYM_SWAP");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
-
- v3_virtio_register_harddisk(virtio_blk, &hd_ops, dev);
+ if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"),
+ &blk_ops, frontend_cfg, swap) == -1) {
+ PrintError("Could not connect %s to frontend %s\n",
+ name, v3_cfg_val(frontend_cfg, "tag"));
+ return -1;
+ }
#ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
if (vm->enable_telemetry) {
}
-static int cons_init(struct guest_info * vm, void * cfg_data) {
- struct telnet_cons_cfg * cfg = (struct telnet_cons_cfg *)cfg_data;
+static int cons_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
struct cons_state * state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
- struct vm_device * frontend = v3_find_dev(vm, cfg->frontend);
+ v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
+ struct vm_device * frontend = v3_find_dev(vm, v3_cfg_val(frontend_cfg, "id"));
+ char * name = v3_cfg_val(cfg, "name");
state->server_fd = 0;
state->client_fd = 0;
state->frontend_dev = frontend;
- state->port = cfg->port;
+ state->port = atoi(v3_cfg_val(cfg, "port"));
v3_lock_init(&(state->cons_lock));
- struct vm_device * dev = v3_allocate_device("TELNET_CONS", &dev_ops, state);
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, state);
if (v3_attach_device(vm, dev) == -1) {
- PrintError("Could not attach device %s\n", "TELNET_CONS");
+ PrintError("Could not attach device %s\n", name);
return -1;
}
--- /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 <palacios/vmm_dev_mgr.h>
+
+
+struct blk_state {
+ uint64_t capacity;
+ uint8_t * blk_space;
+ addr_t blk_base_addr;
+};
+
+
+
+static uint64_t blk_get_capacity(void * private_data) {
+ struct blk_state * blk = (struct blk_state *)private_data;
+
+ PrintDebug("SymBlk: Getting Capacity %d\n", (uint32_t)(blk->capacity));
+
+ return blk->capacity;
+}
+
+
+
+static int blk_read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
+ struct blk_state * blk = (struct blk_state *)private_data;
+
+ memcpy(buf, blk->blk_space + lba, num_bytes);
+
+ return 0;
+}
+
+
+
+
+static int blk_write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
+ struct blk_state * blk = (struct blk_state *)private_data;
+
+ memcpy(blk->blk_space + lba, buf, num_bytes);
+
+ return 0;
+}
+
+
+static int blk_free(struct vm_device * dev) {
+ return -1;
+}
+
+
+static struct v3_dev_blk_ops blk_ops = {
+ .read = blk_read,
+ .write = blk_write,
+ .get_capacity = blk_get_capacity,
+};
+
+
+
+static struct v3_device_ops dev_ops = {
+ .free = blk_free,
+ .reset = NULL,
+ .start = NULL,
+ .stop = NULL,
+};
+
+
+
+
+static int blk_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
+ struct blk_state * blk = NULL;
+ v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
+ char * name = v3_cfg_val(cfg, "name");
+ uint64_t capacity = atoi(v3_cfg_val(cfg, "size"));
+
+ if (!frontend_cfg) {
+ PrintError("Frontend Configuration not present\n");
+ return -1;
+ }
+
+ PrintDebug("Creating Blk Device\n");
+
+
+ blk = (struct blk_state *)V3_Malloc(sizeof(struct blk_state) + ((capacity / 4096) / 8));
+
+ blk->capacity = capacity;
+
+ blk->blk_base_addr = (addr_t)V3_AllocPages(capacity / 4096);
+ blk->blk_space = (uint8_t *)V3_VAddr((void *)(blk->blk_base_addr));
+ memset(blk->blk_space, 0, capacity);
+
+
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, blk);
+
+ if (v3_attach_device(vm, dev) == -1) {
+ PrintError("Could not attach device %s\n", name);
+ return -1;
+ }
+
+ if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"),
+ &blk_ops, frontend_cfg, blk) == -1) {
+ PrintError("Could not connect %s to frontend %s\n",
+ name, v3_cfg_val(frontend_cfg, "tag"));
+ return -1;
+ }
+
+
+ return 0;
+}
+
+device_register("TMPDISK", blk_init)
vmm_xed.o \
vmm_binaries.o \
vmm_cpuid.o \
-
+ vmm_xml.o
obj-$(CONFIG_SVM) += svm.o \
svm_io.o \
#include <palacios/vmm_direct_paging.h>
#include <palacios/vmm_ctrl_regs.h>
-#include <palacios/vmm_config.h>
#include <palacios/svm_io.h>
#include <palacios/vmm_sprintf.h>
}
-static int init_svm_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
-
-
- v3_pre_config_guest(info, config_ptr);
+int v3_init_svm_vmcb(struct guest_info * info, v3_vm_class_t vm_class) {
PrintDebug("Allocating VMCB\n");
info->vmm_data = (void*)Allocate_VMCB();
-
- PrintDebug("Initializing VMCB (addr=%p)\n", (void *)info->vmm_data);
- Init_VMCB_BIOS((vmcb_t*)(info->vmm_data), info);
-
- v3_post_config_guest(info, config_ptr);
+
+ if (vm_class == V3_PC_VM) {
+ PrintDebug("Initializing VMCB (addr=%p)\n", (void *)info->vmm_data);
+ Init_VMCB_BIOS((vmcb_t*)(info->vmm_data), info);
+ } else {
+ PrintError("Invalid VM class\n");
+ return -1;
+ }
return 0;
}
}
-static int start_svm_guest(struct guest_info *info) {
+int v3_start_svm_guest(struct guest_info *info) {
// vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
// vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
}
-void v3_init_svm_hooks(struct v3_ctrl_ops * vmm_ops) {
-
- // Setup the SVM specific vmm operations
- vmm_ops->init_guest = &init_svm_guest;
- vmm_ops->start_guest = &start_svm_guest;
- vmm_ops->has_nested_paging = &has_svm_nested_paging;
-
- return;
-}
#include <palacios/vmm_msr.h>
#include <palacios/vmm_sprintf.h>
#include <palacios/vmm_list.h>
-
+#include <palacios/vm_guest.h>
#define PENTIUM_MSRS_START 0x00000000
#define PENTIUM_MSRS_END 0x00001fff
+
+
+
static struct guest_info * allocate_guest() {
void * info = V3_Malloc(sizeof(struct guest_info));
memset(info, 0, sizeof(struct guest_info));
}
-struct vmm_init_arg {
- int cpu_id;
- struct v3_ctrl_ops * vmm_ops;
-};
-
static void init_cpu(void * arg) {
- struct vmm_init_arg * vmm_arg = (struct vmm_init_arg *)arg;
- int cpu_id = vmm_arg->cpu_id;
- struct v3_ctrl_ops * vmm_ops = vmm_arg->vmm_ops;
+ uint32_t cpu_id = (uint32_t)(addr_t)arg;
#ifdef CONFIG_SVM
if (v3_is_svm_capable()) {
PrintDebug("Machine is SVM Capable\n");
v3_init_svm_cpu(cpu_id);
- if (cpu_id == 0) {
- v3_init_svm_hooks(vmm_ops);
- }
} else
#endif
#ifdef CONFIG_VMX
PrintDebug("Machine is VMX Capable\n");
v3_init_vmx_cpu(cpu_id);
- if (cpu_id == 0) {
- v3_init_vmx_hooks(vmm_ops);
- }
} else
#endif
{
-void Init_V3(struct v3_os_hooks * hooks, struct v3_ctrl_ops * vmm_ops, int num_cpus) {
+
+
+void Init_V3(struct v3_os_hooks * hooks, int num_cpus) {
int i;
- struct vmm_init_arg arg;
- arg.vmm_ops = vmm_ops;
// Set global variables.
os_hooks = hooks;
// Register all the possible device types
v3_init_devices();
-
#ifdef INSTRUMENT_VMM
v3_init_instrumentation();
#endif
- vmm_ops->allocate_guest = &allocate_guest;
-
-
if ((hooks) && (hooks->call_on_cpu)) {
for (i = 0; i < num_cpus; i++) {
- arg.cpu_id = i;
V3_Print("Initializing VMM extensions on cpu %d\n", i);
- hooks->call_on_cpu(i, &init_cpu, &arg);
+ hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
}
}
+}
+
+v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
+ return v3_cpu_types[cpu_id];
+}
+struct guest_info * v3_create_vm(void * cfg) {
+ struct guest_info * info = allocate_guest();
+
+ if (!info) {
+ PrintError("Could not allocate Guest\n");
+ return NULL;
+ }
+
+ if (v3_config_guest(info, cfg) == -1) {
+ PrintError("Could not configure guest\n");
+ return NULL;
+ }
+
+ return info;
}
+int v3_start_vm(struct guest_info * info, unsigned int cpu_mask) {
+
+ info->cpu_id = v3_get_cpu_id();
+
+ V3_Print("V3 -- Starting VM\n");
+
+ switch (v3_cpu_types[info->cpu_id]) {
+#ifdef CONFIG_SVM
+ case V3_SVM_CPU:
+ case V3_SVM_REV3_CPU:
+ return v3_start_svm_guest(info);
+ break;
+#endif
+#if CONFIG_VMX && 0
+ case V3_VMX_CPU:
+ case V3_VMX_EPT_CPU:
+ return v3_start_vmx_guest(info);
+ break;
+#endif
+ default:
+ PrintError("Attemping to enter a guest on an invalid CPU\n");
+ return -1;
+ }
+
+
+ return 0;
+}
#ifdef __V3_32BIT__
+unsigned int v3_get_cpu_id() {
+ extern struct v3_os_hooks * os_hooks;
+ unsigned int ret = (unsigned int)-1;
+
+ if ((os_hooks) && (os_hooks)->get_cpu) {
+ ret = os_hooks->get_cpu();
+ }
+
+ return ret;
+}
+
+
+
+
+
int v3_vm_enter(struct guest_info * info) {
switch (v3_cpu_types[info->cpu_id]) {
#ifdef CONFIG_SVM
return -1;
}
}
+
+
+
#include <palacios/vmm_hypercall.h>
#include <palacios/vmm_dev_mgr.h>
#include <palacios/vmm_cpuid.h>
+#include <palacios/vmm_xml.h>
+
+#include <palacios/svm.h>
+#include <palacios/vmx.h>
#ifdef CONFIG_SYMBIOTIC
#include <palacios/vmm_sym_iface.h>
#endif
-#include <devices/generic.h>
-#include <devices/ide.h>
-#include <devices/ram_cd.h>
-#include <devices/net_cd.h>
-#include <devices/ram_hd.h>
-#include <devices/net_hd.h>
-#include <devices/telnet_cons.h>
-#include <devices/pci_passthrough.h>
+#include <palacios/vmm_host_events.h>
+#include <palacios/vmm_socket.h>
+#include "vmm_config_class.h"
+// This is used to access the configuration file index table
+struct file_hdr {
+ uint32_t index;
+ uint32_t size;
+ uint64_t offset;
+};
+struct file_idx_table {
+ uint64_t num_files;
+ struct file_hdr hdrs[0];
+};
-#include <palacios/vmm_host_events.h>
-#include <palacios/vmm_socket.h>
+static int setup_memory_map(struct guest_info * info, struct v3_config * config_ptr);
+static int setup_devices(struct guest_info * info, struct v3_config * config_ptr);
+
+
+char * v3_cfg_val(v3_cfg_tree_t * tree, char * tag) {
+ char * attrib = (char *)v3_xml_attr(tree, tag);
+ v3_cfg_tree_t * child_entry = v3_xml_child(tree, tag);
+ char * val = NULL;
+
+ if ((child_entry != NULL) && (attrib != NULL)) {
+ PrintError("Duplicate Configuration parameters present for %s\n", tag);
+ return NULL;
+ }
+
+ val = (attrib == NULL) ? v3_xml_txt(child_entry): attrib;
+ return val;
+}
+
+v3_cfg_tree_t * v3_cfg_subtree(v3_cfg_tree_t * tree, char * tag) {
+ return v3_xml_child(tree, tag);
+}
+
+v3_cfg_tree_t * v3_cfg_next_branch(v3_cfg_tree_t * tree) {
+ return v3_xml_next(tree);
+}
-static int setup_memory_map(struct guest_info * info, struct v3_vm_config * config_ptr);
-static int setup_devices(struct guest_info * info, struct v3_vm_config * config_ptr);
-static int configure_generic(struct guest_info * info, struct v3_vm_config * config_ptr);
+struct v3_cfg_file * v3_cfg_get_file(struct guest_info * info, char * tag) {
+ struct v3_cfg_file * file = NULL;
-#ifdef CONFIG_PASSTHROUGH_VIDEO
-static int passthrough_mem_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
+ file = (struct v3_cfg_file *)v3_htable_search(info->cfg_data->file_table, (addr_t)tag);
+
+ return file;
+}
+
+
+static uint_t file_hash_fn(addr_t key) {
+ char * name = (char *)key;
+ return v3_hash_buffer((uchar_t *)name, strlen(name));
+}
- return length;
- // memcpy((void*)guest_addr, src, length);
- PrintDebug("Write of %d bytes to %p\n", length, (void *)guest_addr);
- PrintDebug("Write Value = %p\n", (void *)*(addr_t *)src);
+static int file_eq_fn(addr_t key1, addr_t key2) {
+ char * name1 = (char *)key1;
+ char * name2 = (char *)key2;
+
+ return (strcmp(name1, name2) == 0);
+}
+
+static struct v3_config * parse_config(void * cfg_blob) {
+ struct v3_config * cfg = NULL;
+ int offset = 0;
+ uint_t xml_len = 0;
+ struct file_idx_table * files = NULL;
+ v3_cfg_tree_t * file_tree = NULL;
+
+ V3_Print("cfg data at %p\n", cfg_blob);
+
+ if (memcmp(cfg_blob, "v3vee\0\0\0", 8) != 0) {
+ PrintError("Invalid Configuration Header\n");
+ return NULL;
+ }
+
+ offset += 8;
+
+ cfg = (struct v3_config *)V3_Malloc(sizeof(struct v3_config));
+ memset(cfg, 0, sizeof(struct v3_config));
+
+ cfg->blob = cfg_blob;
+ INIT_LIST_HEAD(&(cfg->file_list));
+ cfg->file_table = v3_create_htable(0, file_hash_fn, file_eq_fn);
- return length;
+ xml_len = *(uint32_t *)(cfg_blob + offset);
+ offset += 4;
+
+ cfg->cfg = (v3_cfg_tree_t *)v3_xml_parse((uint8_t *)(cfg_blob + offset));
+ offset += xml_len;
+
+ offset += 8;
+
+ files = (struct file_idx_table *)(cfg_blob + offset);
+
+ V3_Print("Number of files in cfg: %d\n", (uint32_t)(files->num_files));
+
+ file_tree = v3_cfg_subtree(v3_cfg_subtree(cfg->cfg, "files"), "file");
+
+ while (file_tree) {
+ char * id = v3_cfg_val(file_tree, "id");
+ char * index = v3_cfg_val(file_tree, "index");
+ int idx = atoi(index);
+ struct file_hdr * hdr = &(files->hdrs[idx]);
+ struct v3_cfg_file * file = NULL;
+
+ file = (struct v3_cfg_file *)V3_Malloc(sizeof(struct v3_cfg_file));
+
+ if (!file) {
+ PrintError("Could not allocate file structure\n");
+ return NULL;
+ }
+
+
+ V3_Print("File index=%d id=%s\n", idx, id);
+
+ strncpy(file->tag, id, 256);
+ file->size = hdr->size;
+ file->data = cfg_blob + hdr->offset;
+
+ V3_Print("Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
+ V3_Print("file data at %p\n", file->data);
+ list_add( &(file->file_node), &(cfg->file_list));
+
+ V3_Print("Keying file to name\n");
+ v3_htable_insert(cfg->file_table, (addr_t)(file->tag), (addr_t)(file));
+
+ V3_Print("Iterating to next file\n");
+
+ file_tree = v3_cfg_next_branch(file_tree);
+ }
+
+ V3_Print("Configuration parsed successfully\n");
+
+ return cfg;
}
-#endif
-int v3_pre_config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
- extern v3_cpu_arch_t v3_cpu_types[];
- // Amount of ram the Guest will have, rounded to a 4K page boundary
- info->mem_size = config_ptr->mem_size & ~(addr_t)0xfff;
+static int pre_config_guest(struct guest_info * info, struct v3_config * config_ptr) {
+ extern v3_cpu_arch_t v3_cpu_types[];
+ char * memory_str = v3_cfg_val(config_ptr->cfg, "memory");
+ char * paging = v3_cfg_val(config_ptr->cfg, "paging");
+ char * schedule_hz_str = v3_cfg_val(config_ptr->cfg, "schedule_hz");
+ char * vm_class = v3_cfg_val(config_ptr->cfg, "class");
+ uint32_t sched_hz = 100; // set the schedule frequency to 100 HZ
+
+ if (!memory_str) {
+ PrintError("Memory is a required configuration parameter\n");
+ return -1;
+ }
+
+ PrintDebug("Memory=%s\n", memory_str);
+
+ // Amount of ram the Guest will have, always in MB
+ info->mem_size = atoi(memory_str) * 1024 * 1024;
+
+ if (strcasecmp(vm_class, "PC") == 0) {
+ info->vm_class = V3_PC_VM;
+ } else {
+ PrintError("Invalid VM class\n");
+ return -1;
+ }
- info->cpu_id = config_ptr->guest_cpu;
/*
* Initialize the subsystem data strutures
*/
#ifdef CONFIG_TELEMETRY
- // This should go first, because other subsystems will depend on the guest_info flag
- if (config_ptr->enable_telemetry) {
- info->enable_telemetry = 1;
- v3_init_telemetry(info);
- } else {
- info->enable_telemetry = 0;
+ {
+ char * telemetry = v3_cfg_val(config_ptr->cfg, "telemetry");
+
+ // This should go first, because other subsystems will depend on the guest_info flag
+ if ((telemetry) && (strcasecmp(telemetry, "enable") == 0)) {
+ info->enable_telemetry = 1;
+ v3_init_telemetry(info);
+ } else {
+ info->enable_telemetry = 0;
+ }
}
#endif
v3_init_host_events(info);
// Initialize the memory map
- v3_init_shadow_map(info);
+ if (v3_init_shadow_map(info) == -1) {
+ PrintError("Could not initialize shadow map\n");
+ return -1;
+ }
if ((v3_cpu_types[info->cpu_id] == V3_SVM_REV3_CPU) &&
- (config_ptr->enable_nested_paging == 1)) {
+ (paging) && (strcasecmp(paging, "nested") == 0)) {
PrintDebug("Guest Page Mode: NESTED_PAGING\n");
info->shdw_pg_mode = NESTED_PAGING;
} else {
v3_init_sym_swap(info);
#endif
-
- if (config_ptr->schedule_freq == 0) {
- // set the schedule frequency to 100 HZ
- config_ptr->schedule_freq = 100;
+ if (schedule_hz_str) {
+ sched_hz = atoi(schedule_hz_str);
}
- PrintDebug("CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), (void *)config_ptr->schedule_freq);
+ PrintDebug("CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(),
+ (void *)(addr_t)sched_hz);
- info->yield_cycle_period = (V3_CPU_KHZ() * 1000) / config_ptr->schedule_freq;
+ info->yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
- // Initial CPU operating mode
- info->cpu_mode = REAL;
- info->mem_mode = PHYSICAL_MEM;
+
return 0;
}
-int v3_post_config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
+static int post_config_guest(struct guest_info * info, struct v3_config * config_ptr) {
// Configure the memory map for the guest
if (setup_memory_map(info, config_ptr) == -1) {
info->run_state = VM_STOPPED;
- info->vm_regs.rdi = 0;
- info->vm_regs.rsi = 0;
- info->vm_regs.rbp = 0;
- info->vm_regs.rsp = 0;
- info->vm_regs.rbx = 0;
- info->vm_regs.rdx = 0;
- info->vm_regs.rcx = 0;
- info->vm_regs.rax = 0;
-
- return 0;
-}
-
-
-
-
-
-/* TODO:
- * The amount of guest memory is stored in info->mem_size
- * We need to make sure the memory map extends to cover it
- */
-static int setup_memory_map(struct guest_info * info, struct v3_vm_config * config_ptr) {
-
-#ifdef CONFIG_PASSTHROUGH_VIDEO
- PrintDebug("Setting up memory map (memory size=%dMB)\n", (uint_t)(info->mem_size / (1024 * 1024)));
-
- // VGA frame buffer
- if (1) {
- if (v3_add_shadow_mem(info, 0xa0000, 0xc0000, 0xa0000) == -1) {
- PrintError("Could not map VGA framebuffer\n");
+ if (info->vm_class == V3_PC_VM) {
+ if (post_config_pc(info, config_ptr) == -1) {
+ PrintError("PC Post configuration failure\n");
return -1;
}
} else {
- v3_hook_write_mem(info, 0xa0000, 0xc0000, 0xa0000, passthrough_mem_write, NULL);
- }
-#endif
-
-#define VGABIOS_START 0x000c0000
-#define ROMBIOS_START 0x000f0000
-
- /* layout vgabios */
- {
- extern uint8_t v3_vgabios_start[];
- extern uint8_t v3_vgabios_end[];
-
- addr_t vgabios_dst = v3_get_shadow_addr(&(info->mem_map.base_region), VGABIOS_START);
- memcpy(V3_VAddr((void *)vgabios_dst), v3_vgabios_start, v3_vgabios_end - v3_vgabios_start);
- }
-
- /* layout rombios */
- {
- extern uint8_t v3_rombios_start[];
- extern uint8_t v3_rombios_end[];
-
- addr_t rombios_dst = v3_get_shadow_addr(&(info->mem_map.base_region), ROMBIOS_START);
- memcpy(V3_VAddr((void *)rombios_dst), v3_rombios_start, v3_rombios_end - v3_rombios_start);
- }
-
-#ifdef CONFIG_CRAY_XT
- {
-#define SEASTAR_START 0xffe00000
-#define SEASTAR_END 0xffffffff
- // Map the Seastar straight through
- if (v3_add_shadow_mem(info, SEASTAR_START, SEASTAR_END, SEASTAR_START) == -1) {
- PrintError("Could not map through the seastar\n");
- return -1;
- }
+ PrintError("Invalid VM Class\n");
+ return -1;
}
-#endif
- v3_print_mem_map(info);
return 0;
}
-static int setup_devices(struct guest_info * info, struct v3_vm_config * config_ptr) {
-
- v3_create_device(info, "8259A", NULL);
- v3_create_device(info, "KEYBOARD", NULL);
- v3_create_device(info, "8254_PIT", NULL);
- v3_create_device(info, "BOCHS_DEBUG", NULL);
- v3_create_device(info, "OS_DEBUG", NULL);
- v3_create_device(info, "LAPIC", NULL);
- v3_create_device(info, "IOAPIC", "LAPIC");
- v3_create_device(info, "VMNET", NULL);
-
+int v3_config_guest(struct guest_info * info, void * cfg_blob) {
+ v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
- v3_create_device(info, "CGA_VIDEO", (void *)1);
- {
- struct telnet_cons_cfg cons_cfg = {"CGA_VIDEO", 19997};
- v3_create_device(info, "TELNET_CONSOLE", &cons_cfg);
+ if (cpu_type == V3_INVALID_CPU) {
+ PrintError("Configuring guest on invalid CPU\n");
+ return -1;
}
- if (config_ptr->enable_pci == 1) {
- struct ide_cfg ide_config = {"PCI", "PIIX3"};
- struct pci_passthrough_cfg pci_qemu_pt_cfg = {"PCI", "E1000", 0x8086, 0x100e};
- struct pci_passthrough_cfg pci_hw_pt_cfg = {"PCI", "E1000", 0x8086, 0x107c};
-
- v3_create_device(info, "PCI", NULL);
- v3_create_device(info, "i440FX", "PCI");
- v3_create_device(info, "PIIX3", "PCI");
-
+ info->cfg_data = parse_config(cfg_blob);
- v3_create_device(info, "LNX_VIRTIO_SYM", "PCI");
- v3_create_device(info, "LNX_VIRTIO_BLK", "PCI");
- v3_create_device(info, "LNX_VIRTIO_BALLOON", "PCI");
- v3_create_device(info, "SYM_SWAP", "LNX_VIRTIO_BLK");
-
- v3_create_device(info, "IDE", &ide_config);
-
- v3_create_device(info, "PCI_PASSTHROUGH", &pci_qemu_pt_cfg);
- v3_create_device(info, "PCI_PASSTHROUGH", &pci_hw_pt_cfg);
+ if (!info->cfg_data) {
+ PrintError("Could not parse configuration\n");
+ return -1;
+ }
+ V3_Print("Preconfiguration\n");
- } else {
- v3_create_device(info, "IDE", NULL);
+ if (pre_config_guest(info, info->cfg_data) == -1) {
+ PrintError("Error in preconfiguration\n");
+ return -1;
}
+ V3_Print("Arch dependent configuration\n");
- if (config_ptr->pri_disk_type != NONE) {
- if (config_ptr->pri_disk_type == CDROM) {
- if (config_ptr->pri_disk_con == RAM) {
- struct ram_cd_cfg cfg = {"IDE", 0, 0,
- (addr_t)(config_ptr->pri_disk_info.ram.data_ptr),
- config_ptr->pri_disk_info.ram.size};
-
- PrintDebug("Creating RAM CD\n");
-
- v3_create_device(info, "RAM-CD", &cfg);
- } else if (config_ptr->pri_disk_con == NETWORK) {
- struct net_cd_cfg cfg = {"IDE", 0, 0,
- config_ptr->pri_disk_info.net.ip_str,
- config_ptr->pri_disk_info.net.port,
- config_ptr->pri_disk_info.net.disk_name};
- PrintDebug("Creating NET CD\n");
-
- v3_create_device(info, "NET-CD", &cfg);
- }
- } else if (config_ptr->pri_disk_type == HARDDRIVE) {
- if (config_ptr->pri_disk_con == RAM) {
- struct ram_hd_cfg cfg = {"IDE", 0, 0,
- (addr_t)(config_ptr->pri_disk_info.ram.data_ptr),
- config_ptr->pri_disk_info.ram.size};
-
- PrintDebug("Creating RAM HD\n");
-
- v3_create_device(info, "RAM-HD", &cfg);
- } else if (config_ptr->pri_disk_con == NETWORK) {
- struct net_hd_cfg cfg = {"IDE", 0, 0,
- config_ptr->pri_disk_info.net.ip_str,
- config_ptr->pri_disk_info.net.port,
- config_ptr->pri_disk_info.net.disk_name};
- PrintDebug("Creating NET HD\n");
- v3_create_device(info, "NET-HD", &cfg);
- }
+ // init SVM/VMX
+#ifdef CONFIG_SVM
+ if ((cpu_type == V3_SVM_CPU) || (cpu_type == V3_SVM_REV3_CPU)) {
+ if (v3_init_svm_vmcb(info, info->vm_class) == -1) {
+ PrintError("Error in SVM initialization\n");
+ return -1;
+ }
+ }
+#endif
+#ifdef CONFIG_VMX
+ else if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
+ if (v3_init_vmx_vmcs(info, info->vm_class) == -1) {
+ PrintError("Error in VMX initialization\n");
+ return -1;
}
}
+#endif
+ else {
+ PrintError("Invalid CPU Type\n");
+ return -1;
+ }
+ V3_Print("Post Configuration\n");
-
- if (config_ptr->sec_disk_type != NONE) {
- if (config_ptr->sec_disk_type == CDROM) {
- if (config_ptr->sec_disk_con == RAM) {
- struct ram_cd_cfg cfg = {"IDE", 0, 1,
- (addr_t)(config_ptr->sec_disk_info.ram.data_ptr),
- config_ptr->sec_disk_info.ram.size};
-
- PrintDebug("Creating RAM CD\n");
- v3_create_device(info, "RAM-CD", &cfg);
- } else if (config_ptr->sec_disk_con == NETWORK) {
- struct net_cd_cfg cfg = {"IDE", 0, 1,
- config_ptr->sec_disk_info.net.ip_str,
- config_ptr->sec_disk_info.net.port,
- config_ptr->sec_disk_info.net.disk_name};
-
- PrintDebug("Creating NET CD\n");
- v3_create_device(info, "NET-CD", &cfg);
- }
- } else if (config_ptr->sec_disk_type == HARDDRIVE) {
- if (config_ptr->sec_disk_con == RAM) {
- struct ram_hd_cfg cfg = {"IDE", 0, 1,
- (addr_t)(config_ptr->sec_disk_info.ram.data_ptr),
- config_ptr->sec_disk_info.ram.size};
- PrintDebug("Creating RAM HD\n");
- v3_create_device(info, "RAM-HD", &cfg);
- } else if (config_ptr->sec_disk_con == NETWORK) {
- struct net_hd_cfg cfg = {"IDE", 0, 1,
- config_ptr->sec_disk_info.net.ip_str,
- config_ptr->sec_disk_info.net.port,
- config_ptr->sec_disk_info.net.disk_name};
- PrintDebug("Creating NET HD\n");
- v3_create_device(info, "NET-HD", &cfg);
- }
- }
+ if (post_config_guest(info, info->cfg_data) == -1) {
+ PrintError("Error in postconfiguration\n");
+ return -1;
}
+ V3_Print("Configuration successfull\n");
+ return 0;
+}
-#ifdef CONFIG_GENERIC
- configure_generic(info, config_ptr);
-#endif
- // This should go last because it requires information about the Harddrives
- v3_create_device(info, "NVRAM", "IDE");
-
- PrintDebugDevMgr(info);
- return 0;
-}
+static int setup_memory_map(struct guest_info * info, struct v3_config * config_ptr) {
+ v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(config_ptr->cfg, "memmap"), "region");
-#ifdef CONFIG_GENERIC
-static int configure_generic(struct guest_info * info, struct v3_vm_config * config_ptr) {
- PrintDebug("Creating Generic Device\n");
- v3_create_device(info, "GENERIC", NULL);
-
+ while (mem_region) {
+ addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
+ addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
+ addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
- struct vm_device * generic = v3_find_dev(info, "GENERIC");
+
+ if (v3_add_shadow_mem(info, start_addr, end_addr, host_addr) == -1) {
+ PrintError("Could not map memory region: %p-%p => %p\n",
+ (void *)start_addr, (void *)end_addr, (void *)host_addr);
+ return -1;
+ }
- if (!generic) {
- PrintError("Could not find generic device\n");
- return -1;
+ mem_region = v3_cfg_next_branch(mem_region);
}
- // port 0x92: A20 enable/disable (bit 2) (This causes an MMU flush)
-
-
- // Make the DMA controller invisible
- v3_generic_add_port_range(generic, 0x00, 0x07, GENERIC_PRINT_AND_IGNORE); // DMA 1 channels 0,1,2,3 (address, counter)
- v3_generic_add_port_range(generic, 0xc0, 0xc7, GENERIC_PRINT_AND_IGNORE); // DMA 2 channels 4,5,6,7 (address, counter)
- v3_generic_add_port_range(generic, 0x87, 0x87, GENERIC_PRINT_AND_IGNORE); // DMA 1 channel 0 page register
- v3_generic_add_port_range(generic, 0x83, 0x83, GENERIC_PRINT_AND_IGNORE); // DMA 1 channel 1 page register
- v3_generic_add_port_range(generic, 0x81, 0x81, GENERIC_PRINT_AND_IGNORE); // DMA 1 channel 2 page register
- v3_generic_add_port_range(generic, 0x82, 0x82, GENERIC_PRINT_AND_IGNORE); // DMA 1 channel 3 page register
- v3_generic_add_port_range(generic, 0x8f, 0x8f, GENERIC_PRINT_AND_IGNORE); // DMA 2 channel 4 page register
- v3_generic_add_port_range(generic, 0x8b, 0x8b, GENERIC_PRINT_AND_IGNORE); // DMA 2 channel 5 page register
- v3_generic_add_port_range(generic, 0x89, 0x89, GENERIC_PRINT_AND_IGNORE); // DMA 2 channel 6 page register
- v3_generic_add_port_range(generic, 0x8a, 0x8a, GENERIC_PRINT_AND_IGNORE); // DMA 2 channel 7 page register
- v3_generic_add_port_range(generic, 0x08, 0x0f, GENERIC_PRINT_AND_IGNORE); // DMA 1 misc registers (csr, req, smask,mode,clearff,reset,enable,mmask)
- v3_generic_add_port_range(generic, 0xd0, 0xde, GENERIC_PRINT_AND_IGNORE); // DMA 2 misc registers
-
-
-
-
- // Make the Serial ports invisible
-
- v3_generic_add_port_range(generic, 0x3f8, 0x3f8+7, GENERIC_PRINT_AND_IGNORE); // COM 1
- v3_generic_add_port_range(generic, 0x2f8, 0x2f8+7, GENERIC_PRINT_AND_IGNORE); // COM 2
-
+ return 0;
+}
-
- v3_generic_add_port_range(generic, 0x3e8, 0x3e8+7, GENERIC_PRINT_AND_IGNORE); // COM 3
- v3_generic_add_port_range(generic, 0x2e8, 0x2e8+7, GENERIC_PRINT_AND_IGNORE); // COM 4
-
-
- // Make the PCI bus invisible (at least it's configuration)
-
- //v3_generic_add_port_range(generic, 0xcf8, 0xcf8, GENERIC_PRINT_AND_IGNORE); // PCI Config Address
- //v3_generic_add_port_range(generic, 0xcfc, 0xcfc, GENERIC_PRINT_AND_IGNORE); // PCI Config Data
-
-
-
-#if 0
- if (!use_ramdisk) {
- // Monitor the IDE controllers (very slow)
- v3_generic_add_port_range(generic, 0x170, 0x178, GENERIC_PRINT_AND_PASSTHROUGH); // IDE 1
- v3_generic_add_port_range(generic, 0x376, 0x377, GENERIC_PRINT_AND_PASSTHROUGH); // IDE 1
- }
-
- v3_generic_add_port_range(generic, 0x1f0, 0x1f8, GENERIC_PRINT_AND_PASSTHROUGH); // IDE 0
- v3_generic_add_port_range(generic, 0x3f6, 0x3f7, GENERIC_PRINT_AND_PASSTHROUGH); // IDE 0
-#endif
-
-
-#if 0
-
- // Make the floppy controllers invisible
-
- v3_generic_add_port_range(generic, 0x3f0, 0x3f2, GENERIC_PRINT_AND_IGNORE); // Primary floppy controller (base,statusa/statusb,DOR)
- v3_generic_add_port_range(generic, 0x3f4, 0x3f5, GENERIC_PRINT_AND_IGNORE); // Primary floppy controller (mainstat/datarate,data)
- v3_generic_add_port_range(generic, 0x3f7, 0x3f7, GENERIC_PRINT_AND_IGNORE); // Primary floppy controller (DIR)
- v3_generic_add_port_range(generic, 0x370, 0x372, GENERIC_PRINT_AND_IGNORE); // Secondary floppy controller (base,statusa/statusb,DOR)
- v3_generic_add_port_range(generic, 0x374, 0x375, GENERIC_PRINT_AND_IGNORE); // Secondary floppy controller (mainstat/datarate,data)
- v3_generic_add_port_range(generic, 0x377, 0x377, GENERIC_PRINT_AND_IGNORE); // Secondary floppy controller (DIR)
-
-#endif
-#if 1
- // Make the parallel port invisible
-
- v3_generic_add_port_range(generic, 0x378, 0x37f, GENERIC_PRINT_AND_IGNORE);
-#endif
-#ifdef CONFIG_PASTHROUGH_VIDEO
+static int setup_devices(struct guest_info * info, struct v3_config * config_ptr) {
+ v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(config_ptr->cfg, "devices"), "device");
- // Monitor graphics card operations
- v3_generic_add_port_range(generic, 0x3b0, 0x3bb, GENERIC_PRINT_AND_PASSTHROUGH);
- v3_generic_add_port_range(generic, 0x3c0, 0x3df, GENERIC_PRINT_AND_PASSTHROUGH);
-
-#endif
+ while (device) {
+ char * id = v3_cfg_val(device, "id");
+ V3_Print("configuring device %s\n", id);
-#if 1
- // Make the ISA PNP features invisible
-
- v3_generic_add_port_range(generic, 0x274, 0x277, GENERIC_PRINT_AND_IGNORE);
- v3_generic_add_port_range(generic, 0x279, 0x279, GENERIC_PRINT_AND_IGNORE);
- v3_generic_add_port_range(generic, 0xa79, 0xa79, GENERIC_PRINT_AND_IGNORE);
-#endif
+ if (v3_create_device(info, id, device) == -1) {
+ PrintError("Error creating device %s\n", id);
+ return -1;
+ }
+
+ device = v3_cfg_next_branch(device);
+ }
-#if 1
- // Monitor any network card (realtek ne2000) operations
- v3_generic_add_port_range(generic, 0xc100, 0xc1ff, GENERIC_PRINT_AND_PASSTHROUGH);
-#endif
+ v3_print_dev_mgr(info);
- // v3_generic_add_port_range(generic, 0x378, 0x400, GENERIC_PRINT_AND_IGNORE);
-
return 0;
}
-#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".
+ */
+
+
+static int post_config_pc(struct guest_info * info, struct v3_config * config_ptr) {
+
+
+ info->cpu_mode = REAL;
+ info->mem_mode = PHYSICAL_MEM;
+
+
+ info->vm_regs.rdi = 0;
+ info->vm_regs.rsi = 0;
+ info->vm_regs.rbp = 0;
+ info->vm_regs.rsp = 0;
+ info->vm_regs.rbx = 0;
+ info->vm_regs.rdx = 0;
+ info->vm_regs.rcx = 0;
+ info->vm_regs.rax = 0;
+
+
+#define VGABIOS_START 0x000c0000
+#define ROMBIOS_START 0x000f0000
+
+ /* layout vgabios */
+ {
+ extern uint8_t v3_vgabios_start[];
+ extern uint8_t v3_vgabios_end[];
+
+ addr_t vgabios_dst = v3_get_shadow_addr(&(info->mem_map.base_region), VGABIOS_START);
+ memcpy(V3_VAddr((void *)vgabios_dst), v3_vgabios_start, v3_vgabios_end - v3_vgabios_start);
+ }
+
+ /* layout rombios */
+ {
+ extern uint8_t v3_rombios_start[];
+ extern uint8_t v3_rombios_end[];
+
+ addr_t rombios_dst = v3_get_shadow_addr(&(info->mem_map.base_region), ROMBIOS_START);
+ memcpy(V3_VAddr((void *)rombios_dst), v3_rombios_start, v3_rombios_end - v3_rombios_start);
+ }
+
+ v3_print_mem_map(info);
+
+ return 0;
+}
+
#include <palacios/vmm.h>
#include <palacios/vmm_cpuid.h>
#include <palacios/vmm_lowlevel.h>
-
+#include <palacios/vm_guest.h>
void v3_init_cpuid_map(struct guest_info * info) {
}
-#ifdef CONFIG_CRAY_XT
-
- // If Paging is enabled in the guest then we need to change the shadow page tables
- if (info->mem_mode == VIRTUAL_MEM) {
- if (info->shdw_pg_state.prev_guest_cr3 != info->shdw_pg_state.guest_cr3) {
- if (v3_activate_shadow_pt(info) == -1) {
- PrintError("Failed to activate 32 bit shadow page table\n");
- return -1;
- }
- }
- }
-
- info->shdw_pg_state.prev_guest_cr3 = info->shdw_pg_state.guest_cr3;
-#else
-
// If Paging is enabled in the guest then we need to change the shadow page tables
if (info->mem_mode == VIRTUAL_MEM) {
if (v3_activate_shadow_pt(info) == -1) {
return -1;
}
}
-
-#endif
-
PrintDebug("New Shadow CR3=%p; New Guest CR3=%p\n",
(void *)(addr_t)(info->ctrl_regs.cr3),
mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
+ INIT_LIST_HEAD(&(mgr->blk_list));
+ INIT_LIST_HEAD(&(mgr->net_list));
+ INIT_LIST_HEAD(&(mgr->console_list));
+
+ mgr->blk_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
+ mgr->net_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
+ mgr->console_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
+
return 0;
}
-int v3_create_device(struct guest_info * info, const char * dev_name, void * cfg_data) {
+int v3_create_device(struct guest_info * info, const char * dev_name, v3_cfg_tree_t * cfg) {
int (*dev_init)(struct guest_info * info, void * cfg_data);
dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
}
- if (dev_init(info, cfg_data) == -1) {
+ if (dev_init(info, cfg) == -1) {
PrintError("Could not initialize Device %s\n", dev_name);
return -1;
}
struct vm_device * v3_find_dev(struct guest_info * info, const char * dev_name) {
struct vmm_dev_mgr * mgr = &(info->dev_mgr);
+ if (!dev_name) {
+ return NULL;
+ }
+
return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
}
}
-#ifdef CONFIG_DEBUG_DEV_MGR
-void PrintDebugDevMgr(struct guest_info * info) {
+void v3_print_dev_mgr(struct guest_info * info) {
struct vmm_dev_mgr * mgr = &(info->dev_mgr);
struct vm_device * dev;
- PrintDebug("%d devices registered with manager\n", mgr->num_devs);
+ V3_Print("%d devices registered with manager\n", mgr->num_devs);
list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
- PrintDebugDev(dev);
- PrintDebug("next..\n");
+ V3_Print("Device: %s\n", dev->name);
}
return;
}
-void PrintDebugDev(struct vm_device * dev) {
- PrintDebug("Device: %s\n", dev->name);
+
+
+struct blk_frontend {
+ int (*connect)(struct guest_info * info,
+ void * frontend_data,
+ struct v3_dev_blk_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * priv_data);
+
+
+ struct list_head blk_node;
+
+ void * priv_data;
+};
+
+
+
+int v3_dev_add_blk_frontend(struct guest_info * info,
+ char * name,
+ int (*connect)(struct guest_info * info,
+ void * frontend_data,
+ struct v3_dev_blk_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * priv_data),
+ void * priv_data) {
+
+ struct blk_frontend * frontend = NULL;
+
+ frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
+ memset(frontend, 0, sizeof(struct blk_frontend));
+
+ frontend->connect = connect;
+ frontend->priv_data = priv_data;
+
+ list_add(&(frontend->blk_node), &(info->dev_mgr.blk_list));
+ v3_htable_insert(info->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
+
+ return 0;
}
+int v3_dev_connect_blk(struct guest_info * info,
+ char * frontend_name,
+ struct v3_dev_blk_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * private_data) {
+
+ struct blk_frontend * frontend = NULL;
+ frontend = (struct blk_frontend *)v3_htable_search(info->dev_mgr.blk_table,
+ (addr_t)frontend_name);
+
+ if (frontend == NULL) {
+ PrintError("Could not find frontend blk device %s\n", frontend_name);
+ return 0;
+ }
+ if (frontend->connect(info, frontend->priv_data, ops, cfg, private_data) == -1) {
+ PrintError("Error connecting to block frontend %s\n", frontend_name);
+ return -1;
+ }
-#else
-void PrintDebugDevMgr(struct guest_info * info) {}
-void PrintDebugDev(struct vm_device * dev) {}
-#endif
+ return 0;
+}
#include <palacios/vmm_excp.h>
#include <palacios/vmm.h>
#include <palacios/vmm_types.h>
+#include <palacios/vm_guest.h>
void v3_init_exception_state(struct guest_info * info) {
info->excp_state.excp_pending = 0;
#include <palacios/vmm.h>
#include <palacios/vmm_host_events.h>
-
+#include <palacios/vm_guest.h>
int v3_init_host_events(struct guest_info * info) {
struct v3_host_events * host_evts = &(info->host_event_hooks);
#include <palacios/vmm_hypercall.h>
#include <palacios/vmm.h>
-
+#include <palacios/vm_guest.h>
void v3_init_hypercall_map(struct guest_info * info) {
info->hcall_map.rb_node = NULL;
#include <palacios/vmm_io.h>
#include <palacios/vmm_string.h>
#include <palacios/vmm.h>
-
+#include <palacios/vm_guest.h>
#include <palacios/vmm.h>
#include <palacios/vmm_util.h>
#include <palacios/vmm_emulator.h>
+#include <palacios/vm_guest.h>
#include <palacios/vmm_shadow_paging.h>
#include <palacios/vmm_direct_paging.h>
-
#define MEM_OFFSET_HCALL 0x1000
}
-void v3_init_shadow_map(struct guest_info * info) {
+int v3_init_shadow_map(struct guest_info * info) {
v3_shdw_map_t * map = &(info->mem_map);
addr_t mem_pages = info->mem_size >> 12;
map->base_region.host_type = SHDW_REGION_ALLOCATED;
map->base_region.host_addr = (addr_t)V3_AllocPages(mem_pages);
+
+ if ((void *)map->base_region.host_addr == NULL) {
+ PrintError("Could not allocate Guest memory\n");
+ return -1;
+ }
+
//memset(V3_VAddr((void *)map->base_region.host_addr), 0xffffffff, map->base_region.guest_end);
v3_register_hypercall(info, MEM_OFFSET_HCALL, mem_offset_hypercall, NULL);
+
+ return 0;
}
void v3_delete_shadow_map(struct guest_info * info) {
int v3_init_shadow_page_state(struct guest_info * info) {
struct shadow_page_state * state = &(info->shdw_pg_state);
- state->prev_guest_cr3 = 0;
-
state->guest_cr3 = 0;
state->guest_cr0 = 0;
state->guest_efer.value = 0x0LL;
}
#endif
+#ifdef CONFIG_BUILT_IN_MEMMOVE
+void * memmove(void * dst, const void * src, size_t n) {
+ uint8_t * tmp = (uint8_t *)V3_Malloc(n);
+
+ memcpy(tmp, src, n);
+ memcpy(dst, tmp, n);
+
+ V3_Free(tmp);
+ return dst;
+}
+#endif
+
#ifdef CONFIG_BUILT_IN_MEMCMP
int memcmp(const void * s1_, const void * s2_, size_t n) {
}
#endif
+#ifdef CONFIG_BUILT_IN_STRCASECMP
+int strcasecmp(const char * s1, const char * s2) {
+ while (1) {
+ int cmp = (tolower(*s1) - tolower(*s2));
+
+ if ((cmp != 0) || (*s1 == '\0') || (*s2 == '\0')) {
+ return cmp;
+ }
+
+ ++s1;
+ ++s2;
+ }
+}
+
+#endif
+
#ifdef CONFIG_BUILT_IN_STRNCMP
int strncmp(const char * s1, const char * s2, size_t limit) {
}
#endif
+#ifdef CONFIG_BUILT_IN_STRNCASECMP
+int strncasecmp(const char * s1, const char * s2, size_t limit) {
+ size_t i = 0;
+
+ while (i < limit) {
+ int cmp = (tolower(*s1) - tolower(*s2));
+
+ if ((cmp != 0) || (*s1 == '\0') || (*s2 == '\0')) {
+ return cmp;
+ }
+
+ ++s1;
+ ++s2;
+ ++i;
+ }
+
+ return 0;
+}
+#endif
+
#ifdef CONFIG_BUILT_IN_STRCAT
char * strcat(char * s1, const char * s2) {
#endif
+int strtoi(const char * nptr, char ** endptr) {
+ int ret = 0;
+ char * buf = (char *)nptr;
+
+ while ((*buf >= '0') && (*buf <= '9')) {
+ ret *= 10;
+ ret += (*buf - '0');
+
+ buf++;
+
+ if (endptr) {
+ *endptr = buf;
+ }
+ }
+
+ return ret;
+}
+
+uint64_t atox(const char * buf) {
+ uint64_t ret = 0;
+
+ if (*(buf + 1) == 'x') {
+ buf += 2;
+ }
+
+ while (isxdigit(*buf)) {
+ ret <<= 4;
+
+ if (isdigit(*buf)) {
+ ret += (*buf - '0');
+ } else {
+ ret += tolower(*buf) - 'a' + 10;
+ }
+
+ buf++;
+ }
+
+ return ret;
+}
+
+uint64_t strtox(const char * nptr, char ** endptr) {
+ uint64_t ret = 0;
+ char * buf = (char *)nptr;
+
+ if (*(buf + 1) == 'x') {
+ buf += 2;
+ }
+
+ while (isxdigit(*buf)) {
+ ret <<= 4;
+
+ if (isdigit(*buf)) {
+ ret += (*buf - '0');
+ } else {
+ ret += tolower(*buf) - 'a' + 10;
+ }
+
+ buf++;
+
+ if (endptr) {
+ *endptr = buf;
+ }
+ }
+
+ return ret;
+
+}
+
+
+
#ifdef CONFIG_BUILT_IN_STRCHR
char * strchr(const char * s, int c) {
while (*s != '\0') {
}
#endif
+#ifdef CONFIG_BUILT_IN_STRSPN
+size_t strspn(const char * s, const char * accept) {
+ int match = 1;
+ int cnt = 0;
+ int i = 0;
+ int accept_len = strlen(accept);
+
+ while (match) {
+ match = 0;
+
+ for (i = 0; i < accept_len; i++) {
+ if (s[cnt] == accept[i]) {
+ match = 1;
+ cnt++;
+ break;
+ }
+ }
+ }
+
+ return cnt;
+}
+#endif
+
+
+#ifdef CONFIG_BUILT_IN_STRCSPN
+size_t strcspn(const char * s, const char * reject) {
+ int match = 0;
+ int cnt = 0;
+ int i = 0;
+ int reject_len = strlen(reject);
+
+ while (!match) {
+ for (i = 0; i < reject_len; i++) {
+ if (s[cnt] == reject[i]) {
+ match = 1;
+ cnt++;
+ break;
+ }
+ }
+ }
+
+ return cnt;
+}
+#endif
+
+
+#ifdef CONFIG_BUILT_IN_STRSTR
+char *strstr(const char *haystack, const char *needle)
+{
+ int l1, l2;
+
+ l2 = strlen(s2);
+ if (!l2)
+ return (char *)s1;
+ l1 = strlen(s1);
+ while (l1 >= l2) {
+ l1--;
+ if (!memcmp(s1, s2, l2))
+ return (char *)s1;
+ s1++;
+ }
+ return NULL;
+}
+#endif
+
+
+void str_tolower(char * s) {
+ while (isalpha(*s)) {
+ if (!islower(*s)) {
+ *s = tolower(*s);
+ }
+ s++;
+ }
+}
+
+
+void str_toupper(char * s) {
+ while (isalpha(*s)) {
+ if (!isupper(*s)) {
+ *s = toupper(*s);
+ }
+ s++;
+ }
+}
#include <palacios/vmm_msr.h>
#include <palacios/vmm_mem.h>
#include <palacios/vmm_hypercall.h>
+#include <palacios/vm_guest.h>
#define SYM_PAGE_MSR 0x535
#include <palacios/vmm_sym_swap.h>
#include <palacios/vmm_list.h>
-
+#include <palacios/vm_guest.h>
#ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
#include <palacios/vmm_telemetry.h>
* redistribute, and modify it as specified in the file "V3VEE_LICENSE".
*/
-#include "palacios/vmm_time.h"
-#include "palacios/vmm.h"
-
+#include <palacios/vmm_time.h>
+#include <palacios/vmm.h>
+#include <palacios/vm_guest.h>
void v3_init_time(struct guest_info * info) {
struct vm_time * time_state = &(info->time_state);
--- /dev/null
+/* ezxml.c
+ *
+ * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Modified for Palacios by Jack Lange <jarusl@cs.northwestern.edu>
+ */
+
+
+
+#include <palacios/vmm_xml.h>
+#include <palacios/vmm_sprintf.h>
+#include <stdarg.h>
+#include <palacios/vmm.h>
+
+#define V3_XML_BUFSIZE 1024 // size of internal memory buffers
+
+// Flags for struct v3_xml
+#define V3_XML_NAMEM 0x80 // name is malloced
+#define V3_XML_TXTM 0x40 // txt is malloced
+#define V3_XML_DUP 0x20 // attribute name and value are strduped
+//
+
+
+#define V3_XML_WS "\t\r\n " // whitespace
+#define V3_XML_ERRL 128 // maximum error string length
+
+struct v3_xml_root { // additional data for the root tag
+ struct v3_xml xml; // is a super-struct built on top of v3_xml struct
+ struct v3_xml * cur; // current xml tree insertion point
+ char *str_ptr; // original xml string
+ char *tmp_start; // start of work area
+ char *tmp_end; // end of work area
+ char **ent; // general entities (ampersand sequences)
+ char ***attr; // default attributes
+ short standalone; // non-zero if <?xml standalone="yes"?>
+ char err[V3_XML_ERRL]; // error string
+};
+
+static char * empty_attrib_list[] = { NULL }; // empty, null terminated array of strings
+
+
+static void * tmp_realloc(void * old_ptr, uint_t old_size, uint_t new_size) {
+ void * new_buf = V3_Malloc(new_size);
+
+ if (new_buf == NULL) {
+ return NULL;
+ }
+
+ memcpy(new_buf, old_ptr, old_size);
+ V3_Free(old_ptr);
+
+ return new_buf;
+}
+
+
+
+
+
+// set an error string and return root
+static void v3_xml_err(struct v3_xml_root * root, char * xml_str, const char * err, ...) {
+ va_list ap;
+ int line = 1;
+ char * tmp;
+ char fmt[V3_XML_ERRL];
+
+ for (tmp = root->tmp_start; tmp < xml_str; tmp++) {
+ if (*tmp == '\n') {
+ line++;
+ }
+ }
+
+ snprintf(fmt, V3_XML_ERRL, "[error near line %d]: %s", line, err);
+
+ va_start(ap, err);
+ vsnprintf(root->err, V3_XML_ERRL, fmt, ap);
+ va_end(ap);
+
+ PrintError("XML Error: %s\n", root->err);
+
+ // free memory
+ v3_xml_free(&(root->xml));
+
+ return;
+}
+
+
+
+// returns the first child tag with the given name or NULL if not found
+struct v3_xml * v3_xml_child(struct v3_xml * xml, const char * name) {
+ struct v3_xml * child = NULL;
+
+ if (xml != NULL) {
+ child = xml->child;
+ }
+
+ while ((child) && (strcasecmp(name, child->name) != 0)) {
+ child = child->sibling;
+ }
+
+ return child;
+}
+
+// returns the Nth tag with the same name in the same subsection or NULL if not
+// found
+struct v3_xml * v3_xml_idx(struct v3_xml * xml, int idx) {
+ for (; xml && idx; idx--) {
+ xml = xml->next;
+ }
+
+ return xml;
+}
+
+// returns the value of the requested tag attribute or NULL if not found
+const char * v3_xml_attr(struct v3_xml * xml, const char * attr) {
+ int i = 0;
+ int j = 1;
+ struct v3_xml_root * root = (struct v3_xml_root *)xml;
+
+ if ((!xml) || (!xml->attr)) {
+ return NULL;
+ }
+
+ while ((xml->attr[i]) && (strcasecmp(attr, xml->attr[i]) != 0)) {
+ i += 2;
+ }
+
+ if (xml->attr[i] != NULL) {
+ return xml->attr[i + 1]; // found attribute
+ }
+
+ while (root->xml.parent != NULL) {
+ root = (struct v3_xml_root *)root->xml.parent; // root tag
+ }
+
+ for (i = 0;
+ ( (root->attr[i] != NULL) &&
+ (strcasecmp(xml->name, root->attr[i][0]) != 0) );
+ i++);
+
+ if (! root->attr[i]) {
+ return NULL; // no matching default attributes
+ }
+
+ while ((root->attr[i][j] != NULL) && (strcasecmp(attr, root->attr[i][j]) != 0)) {
+ j += 3;
+ }
+
+ return (root->attr[i][j] != NULL) ? root->attr[i][j + 1] : NULL; // found default
+}
+
+// same as v3_xml_get but takes an already initialized va_list
+static struct v3_xml * v3_xml_vget(struct v3_xml * xml, va_list ap) {
+ char * name = va_arg(ap, char *);
+ int idx = -1;
+
+ if ((name != NULL) && (*name != 0)) {
+ idx = va_arg(ap, int);
+ xml = v3_xml_child(xml, name);
+ }
+ return (idx < 0) ? xml : v3_xml_vget(v3_xml_idx(xml, idx), ap);
+}
+
+// Traverses the xml tree to retrieve a specific subtag. Takes a variable
+// length list of tag names and indexes. The argument list must be terminated
+// by either an index of -1 or an empty string tag name. Example:
+// title = v3_xml_get(library, "shelf", 0, "book", 2, "title", -1);
+// This retrieves the title of the 3rd book on the 1st shelf of library.
+// Returns NULL if not found.
+struct v3_xml * v3_xml_get(struct v3_xml * xml, ...) {
+ va_list ap;
+ struct v3_xml * r;
+
+ va_start(ap, xml);
+ r = v3_xml_vget(xml, ap);
+ va_end(ap);
+ return r;
+}
+
+
+// sets a flag for the given tag and returns the tag
+static struct v3_xml * v3_xml_set_flag(struct v3_xml * xml, short flag)
+{
+ if (xml) xml->flags |= flag;
+ return xml;
+}
+
+
+
+
+
+// Recursively decodes entity and character references and normalizes new lines
+// ent is a null terminated array of alternating entity names and values. set t
+// to '&' for general entity decoding, '%' for parameter entity decoding, 'c'
+// for cdata sections, ' ' for attribute normalization, or '*' for non-cdata
+// attribute normalization. Returns s, or if the decoded string is longer than
+// s, returns a malloced string that must be freed.
+static char * v3_xml_decode(char * s, char ** ent, char t) {
+ char * e;
+ char * r = s;
+ char * m = s;
+ long b, c, d, l;
+
+ // normalize line endings
+ for (; *s; s++) {
+ while (*s == '\r') {
+ *(s++) = '\n';
+
+ if (*s == '\n') {
+ memmove(s, (s + 1), strlen(s));
+ }
+ }
+ }
+
+ for (s = r; ; ) {
+
+ while ( (*s) &&
+ (*s != '&') &&
+ ( (*s != '%') ||
+ (t != '%')) &&
+ (!isspace(*s))) {
+ s++;
+ }
+
+ if (*s == '\0') {
+ break;
+ }
+
+ if ((t != 'c') && (strncmp(s, "&#", 2) == 0)) { // character reference
+ if (s[2] == 'x') {
+ c = strtox(s + 3, &e); // base 16
+ } else {
+ c = strtoi(s + 2, &e); // base 10
+ }
+
+ if ((!c) || (*e != ';')) {
+ // not a character ref
+ s++;
+ continue;
+ }
+
+ *(s++) = c;
+
+ memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';')));
+ } else if ( ( (*s == '&') &&
+ ((t == '&') || (t == ' ') || (t == '*'))) ||
+ ( (*s == '%') && (t == '%'))) {
+ // entity reference`
+
+ for ( (b = 0);
+ (ent[b]) && (strncmp(s + 1, ent[b], strlen(ent[b])) != 0);
+ (b += 2)); // find entity in entity list
+
+ if (ent[b++]) { // found a match
+ if (((c = strlen(ent[b])) - 1) > ((e = strchr(s, ';')) - s)) {
+ l = (d = (s - r)) + c + strlen(e); // new length
+ r = ((r == m) ? strcpy(V3_Malloc(l), r) : tmp_realloc(r, strlen(r), l));
+ e = strchr((s = r + d), ';'); // fix up pointers
+ }
+
+ memmove(s + c, e + 1, strlen(e)); // shift rest of string
+ strncpy(s, ent[b], c); // copy in replacement text
+ } else {
+ // not a known entity
+ s++;
+ }
+ } else if ( ( (t == ' ') || (t == '*')) &&
+ (isspace(*s))) {
+ *(s++) = ' ';
+ } else {
+ // no decoding needed
+ s++;
+ }
+ }
+
+ if (t == '*') {
+ // normalize spaces for non-cdata attributes
+ for (s = r; *s; s++) {
+ if ((l = strspn(s, " "))) {
+ memmove(s, s + l, strlen(s + l) + 1);
+ }
+
+ while ((*s) && (*s != ' ')) {
+ s++;
+ }
+ }
+
+ if ((--s >= r) && (*s == ' ')) {
+ // trim any trailing space
+ *s = '\0';
+ }
+ }
+ return r;
+}
+
+
+
+// called when parser finds character content between open and closing tag
+static void v3_xml_char_content(struct v3_xml_root * root, char * s, size_t len, char t) {
+ struct v3_xml * xml = root->cur;
+ char * m = s;
+ size_t l = 0;
+
+ if ((xml == NULL) || (xml->name == NULL) || (len == 0)) {
+ // sanity check
+ return;
+ }
+
+ s[len] = '\0'; // null terminate text (calling functions anticipate this)
+ len = strlen(s = v3_xml_decode(s, root->ent, t)) + 1;
+
+ if (! *(xml->txt)) {
+ // initial character content
+ xml->txt = s;
+ } else {
+ // allocate our own memory and make a copy
+ xml->txt = (xml->flags & V3_XML_TXTM) ?
+ (tmp_realloc(xml->txt, strlen(xml->txt), (l = strlen(xml->txt)) + len)) :
+ (strcpy(V3_Malloc((l = strlen(xml->txt)) + len), xml->txt));
+
+ strcpy(xml->txt + l, s); // add new char content
+
+ if (s != m) {
+ V3_Free(s); // free s if it was malloced by v3_xml_decode()
+ }
+ }
+
+ if (xml->txt != m) {
+ v3_xml_set_flag(xml, V3_XML_TXTM);
+ }
+}
+
+// called when parser finds closing tag
+static int v3_xml_close_tag(struct v3_xml_root * root, char * name, char * s) {
+ if ( (root->cur == NULL) ||
+ (root->cur->name == NULL) ||
+ (strcasecmp(name, root->cur->name))) {
+ v3_xml_err(root, s, "unexpected closing tag </%s>", name);
+ return -1;
+ }
+
+ root->cur = root->cur->parent;
+ return 0;
+}
+
+// checks for circular entity references, returns non-zero if no circular
+// references are found, zero otherwise
+static int v3_xml_ent_ok(char * name, char * s, char ** ent) {
+ int i;
+
+ for (; ; s++) {
+ while ((*s != '\0') && (*s != '&')) {
+ // find next entity reference
+ s++;
+ }
+
+ if (*s == '\0') {
+ return 1;
+ }
+
+ if (strncmp(s + 1, name, strlen(name)) == 0) {
+ // circular ref.
+ return 0;
+ }
+
+ for (i = 0; (ent[i]) && (strncmp(ent[i], s + 1, strlen(ent[i]))); i += 2);
+
+ if ((ent[i] != NULL) && (v3_xml_ent_ok(name, ent[i + 1], ent) == 0)) {
+ return 0;
+ }
+ }
+}
+
+
+
+// frees a tag attribute list
+static void v3_xml_free_attr(char **attr) {
+ int i = 0;
+ char * m;
+
+ if ((attr == NULL) || (attr == empty_attrib_list)) {
+ // nothing to free
+ return;
+ }
+
+ while (attr[i]) {
+ // find end of attribute list
+ i += 2;
+ }
+
+ m = attr[i + 1]; // list of which names and values are malloced
+
+ for (i = 0; m[i]; i++) {
+ if (m[i] & V3_XML_NAMEM) {
+ V3_Free(attr[i * 2]);
+ }
+
+ if (m[i] & V3_XML_TXTM) {
+ V3_Free(attr[(i * 2) + 1]);
+ }
+ }
+
+ V3_Free(m);
+ V3_Free(attr);
+}
+
+
+
+
+
+
+// returns a new empty v3_xml structure with the given root tag name
+static struct v3_xml * v3_xml_new(const char * name) {
+ static char * ent[] = { "lt;", "<", "gt;", ">", "quot;", """,
+ "apos;", "'", "amp;", "&", NULL };
+
+ struct v3_xml_root * root = (struct v3_xml_root *)V3_Malloc(sizeof(struct v3_xml_root));
+ memset(root, 0, sizeof(struct v3_xml_root));
+
+ root->xml.name = (char *)name;
+ root->cur = &root->xml;
+ root->xml.txt = "";
+ memset(root->err, 0, V3_XML_ERRL);
+
+ root->ent = V3_Malloc(sizeof(ent));
+ memcpy(root->ent, ent, sizeof(ent));
+
+ root->xml.attr = empty_attrib_list;
+ root->attr = (char ***)(empty_attrib_list);
+
+ return &root->xml;
+}
+
+// inserts an existing tag into an v3_xml structure
+static struct v3_xml * v3_xml_insert(struct v3_xml * xml, struct v3_xml * dest, size_t off) {
+ struct v3_xml * cur, * prev, * head;
+
+ xml->next = NULL;
+ xml->sibling = NULL;
+ xml->ordered = NULL;
+
+ xml->off = off;
+ xml->parent = dest;
+
+ if ((head = dest->child)) {
+ // already have sub tags
+
+ if (head->off <= off) {
+ // not first subtag
+
+ for (cur = head;
+ ((cur->ordered) && (cur->ordered->off <= off));
+ cur = cur->ordered);
+
+ xml->ordered = cur->ordered;
+ cur->ordered = xml;
+ } else {
+ // first subtag
+ xml->ordered = head;
+ dest->child = xml;
+ }
+
+ // find tag type
+ for (cur = head, prev = NULL;
+ ((cur) && (strcasecmp(cur->name, xml->name) != 0));
+ prev = cur, cur = cur->sibling);
+
+
+ if (cur && cur->off <= off) {
+ // not first of type
+
+ while (cur->next && cur->next->off <= off) {
+ cur = cur->next;
+ }
+
+ xml->next = cur->next;
+ cur->next = xml;
+ } else {
+ // first tag of this type
+
+ if (prev && cur) {
+ // remove old first
+ prev->sibling = cur->sibling;
+ }
+
+ xml->next = cur; // old first tag is now next
+
+ // new sibling insert point
+ for (cur = head, prev = NULL;
+ ((cur) && (cur->off <= off));
+ prev = cur, cur = cur->sibling);
+
+ xml->sibling = cur;
+
+ if (prev) {
+ prev->sibling = xml;
+ }
+ }
+ } else {
+ // only sub tag
+ dest->child = xml;
+ }
+
+ return xml;
+}
+
+
+// Adds a child tag. off is the offset of the child tag relative to the start
+// of the parent tag's character content. Returns the child tag.
+static struct v3_xml * v3_xml_add_child(struct v3_xml * xml, const char * name, size_t off) {
+ struct v3_xml * child;
+
+ if (xml == NULL) {
+ return NULL;
+ }
+
+ child = (struct v3_xml *)V3_Malloc(sizeof(struct v3_xml));
+ memset(child, 0, sizeof(struct v3_xml));
+
+ child->name = (char *)name;
+ child->attr = empty_attrib_list;
+ child->txt = "";
+
+ return v3_xml_insert(child, xml, off);
+}
+
+
+// called when parser finds start of new tag
+static void v3_xml_open_tag(struct v3_xml_root * root, char * name, char ** attr) {
+ struct v3_xml * xml = root->cur;
+
+ if (xml->name) {
+ xml = v3_xml_add_child(xml, name, strlen(xml->txt));
+ } else {
+ // first open tag
+ xml->name = name;
+ }
+
+ xml->attr = attr;
+ root->cur = xml; // update tag insertion point
+}
+
+
+
+
+
+
+
+// parse the given xml string and return an v3_xml structure
+static struct v3_xml * parse_str(char * buf, size_t len) {
+ struct v3_xml_root * root = (struct v3_xml_root *)v3_xml_new(NULL);
+ char quote_char;
+ char last_char;
+ char * tag_ptr;
+ char ** attr;
+ char ** tmp_attr = NULL; // initialize a to avoid compile warning
+ int attr_idx;
+ int i, j;
+
+ root->str_ptr = buf;
+
+ if (len == 0) {
+ v3_xml_err(root, NULL, "Empty XML String\n");
+ return NULL;
+ }
+
+ root->tmp_start = buf;
+ root->tmp_end = buf + len; // record start and end of work area
+
+ last_char = buf[len - 1]; // save end char
+ buf[len - 1] = '\0'; // turn end char into null terminator
+
+ while ((*buf) && (*buf != '<')) {
+ // find first tag
+ buf++;
+ }
+
+ if (*buf == '\0') {
+ v3_xml_err(root, buf, "root tag missing");
+ return NULL;
+ }
+
+ for (; ; ) {
+ attr = (char **)empty_attrib_list;
+ tag_ptr = ++buf; // skip first '<'
+
+ if (isalpha(*buf) || (*buf == '_') || (*buf == ':') || (*buf < '\0')) {
+ // new tag
+
+ if (root->cur == NULL) {
+ v3_xml_err(root, tag_ptr, "markup outside of root element");
+ return NULL;
+ }
+
+ buf += strcspn(buf, V3_XML_WS "/>");
+
+ while (isspace(*buf)) {
+ // null terminate tag name,
+ // this writes '\0' to spaces after first tag
+ *(buf++) = '\0';
+ }
+
+ // check if attribute follows tag
+ if ((*buf) && (*buf != '/') && (*buf != '>')) {
+ // there is an attribute
+ // find attributes for correct tag
+ for ((i = 0);
+ ((tmp_attr = root->attr[i]) &&
+ (strcasecmp(tmp_attr[0], tag_ptr) != 0));
+ (i++)) ;
+
+ // 'tmp_attr' now points to the attribute list associated with 'tag_ptr'
+ }
+
+ // attributes are name value pairs,
+ // 2nd to last entry is null (end of list)
+ // last entry points to a string map marking whether values have been malloced...
+ // loop through attributes until hitting the closing bracket
+ for (attr_idx = 0;
+ (*buf) && (*buf != '/') && (*buf != '>');
+ attr_idx += 2) {
+ // buf is incremented later on
+ // new attrib
+ int attr_cnt = (attr_idx / 2) + 1;
+ int val_idx = attr_idx + 1;
+ int term_idx = attr_idx + 2;
+ int last_idx = attr_idx + 3;
+
+ // attr = allocated space
+ // attr[val_idx] = mem for list of maloced vals
+ if (attr_cnt > 1) {
+ attr = tmp_realloc(attr,
+ (((attr_cnt - 1) * (2 * sizeof(char *))) +
+ (2 * sizeof(char *))),
+ ((attr_cnt * (2 * sizeof(char *))) +
+ (2 * sizeof(char *))));
+
+ attr[last_idx] = tmp_realloc(attr[last_idx - 2],
+ attr_cnt,
+ (attr_cnt + 1));
+ } else {
+ attr = V3_Malloc(4 * sizeof(char *));
+ attr[last_idx] = V3_Malloc(2);
+ }
+
+
+ attr[attr_idx] = buf; // set attribute name
+ attr[val_idx] = ""; // temporary attribute value
+ attr[term_idx] = NULL; // null terminate list
+ strcpy(attr[last_idx] + attr_cnt, " "); // value is not malloc'd, offset into the stringmap
+
+ buf += strcspn(buf, V3_XML_WS "=/>");
+
+ if ((*buf == '=') || isspace(*buf)) {
+
+ *(buf++) = '\0'; // null terminate tag attribute name
+
+ // eat whitespace (and more multiple '=' ?)
+ buf += strspn(buf, V3_XML_WS "=");
+
+ quote_char = *buf;
+
+ if ((quote_char == '"') || (quote_char == '\'')) { // attribute value
+ attr[val_idx] = ++buf;
+
+ while ((*buf) && (*buf != quote_char)) {
+ buf++;
+ }
+
+ if (*buf) {
+ // null terminate attribute val
+ *(buf++) = '\0';
+ } else {
+ v3_xml_free_attr(attr);
+ v3_xml_err(root, tag_ptr, "missing %c", quote_char);
+ return NULL;
+ }
+
+ for (j = 1;
+ ( (tmp_attr) && (tmp_attr[j]) &&
+ (strcasecmp(tmp_attr[j], attr[attr_idx]) != 0));
+ j += 3);
+
+ attr[val_idx] = v3_xml_decode(attr[val_idx], root->ent,
+ ((tmp_attr && tmp_attr[j]) ?
+ *tmp_attr[j + 2] :
+ ' '));
+
+ if ( (attr[val_idx] < tag_ptr) ||
+ (attr[val_idx] > buf) ) {
+ attr[last_idx][attr_cnt - 1] = V3_XML_TXTM; // value malloced
+ }
+ }
+ }
+
+ while (isspace(*buf)) {
+ buf++;
+ }
+ }
+
+ if (*buf == '/') {
+ // self closing tag
+ *(buf++) = '\0';
+
+ if ( ((*buf) && (*buf != '>')) ||
+ ((!*buf) && (last_char != '>'))) {
+
+ if (attr_idx > 0) {
+ v3_xml_free_attr(attr);
+ }
+ v3_xml_err(root, tag_ptr, "missing >");
+ return NULL;
+ }
+ v3_xml_open_tag(root, tag_ptr, attr);
+ v3_xml_close_tag(root, tag_ptr, buf);
+ } else if (((quote_char = *buf) == '>') ||
+ ((!*buf) && (last_char == '>'))) {
+ // open tag
+ *buf = '\0'; // temporarily null terminate tag name
+ v3_xml_open_tag(root, tag_ptr, attr);
+ *buf = quote_char;
+ } else {
+ if (attr_idx > 0) {
+ v3_xml_free_attr(attr);
+ }
+ v3_xml_err(root, tag_ptr, "missing >");
+ return NULL;
+ }
+ } else if (*buf == '/') {
+ // close tag
+
+ buf += strcspn(tag_ptr = buf + 1, V3_XML_WS ">") + 1;
+
+ quote_char = *buf;
+ if ((*buf == '\0') && (last_char != '>')) {
+ v3_xml_err(root, tag_ptr, "missing >");
+ return NULL;
+ }
+
+ *buf = '\0'; // temporarily null terminate tag name
+
+ if (v3_xml_close_tag(root, tag_ptr, buf) == -1) {
+ return NULL;
+ }
+
+ *buf = quote_char;
+ if (isspace(*buf)) {
+ buf += strspn(buf, V3_XML_WS);
+ }
+ } else if (strncmp(buf, "!--", 3) == 0) {
+ // xml comment
+ if ( ((buf = strstr(buf + 3, "--")) == 0) ||
+ ((*(buf += 2) != '>') && (*buf)) ||
+ ((!*buf) && (last_char != '>'))) {
+ v3_xml_err(root, tag_ptr, "unclosed <!--");
+ return NULL;
+ }
+ } else if (! strncmp(buf, "![CDATA[", 8)) {
+ // cdata
+ if ((buf = strstr(buf, "]]>"))) {
+ v3_xml_char_content(root, tag_ptr + 8, (buf += 2) - tag_ptr - 10, 'c');
+ } else {
+ v3_xml_err(root, tag_ptr, "unclosed <![CDATA[");
+ return NULL;
+ }
+ } else {
+ v3_xml_err(root, tag_ptr, "unexpected <");
+ return NULL;
+ }
+
+ if (! buf || ! *buf) {
+ break;
+ }
+
+ *buf = '\0';
+ tag_ptr = ++buf;
+
+ if (*buf && (*buf != '<')) {
+ // tag character content
+ while (*buf && (*buf != '<')) {
+ buf++;
+ }
+
+ if (*buf) {
+ v3_xml_char_content(root, tag_ptr, buf - tag_ptr, '&');
+ } else {
+ break;
+ }
+ } else if (*buf == '\0') {
+ break;
+ }
+ }
+
+ if (root->cur == NULL) {
+ return &root->xml;
+ } else if (root->cur->name == NULL) {
+ v3_xml_err(root, tag_ptr, "root tag missing");
+ return NULL;
+ } else {
+ v3_xml_err(root, tag_ptr, "unclosed tag <%s>", root->cur->name);
+ return NULL;
+ }
+}
+
+
+struct v3_xml * v3_xml_parse(char * buf) {
+ int str_len = 0;
+ char * xml_buf = NULL;
+
+ if (!buf) {
+ return NULL;
+ }
+
+ str_len = strlen(buf);
+ xml_buf = (char *)V3_Malloc(str_len + 1);
+ strcpy(xml_buf, buf);
+
+ return parse_str(xml_buf, str_len);
+}
+
+
+
+// free the memory allocated for the v3_xml structure
+void v3_xml_free(struct v3_xml * xml) {
+ struct v3_xml_root * root = (struct v3_xml_root *)xml;
+ int i, j;
+ char **a, *s;
+
+ if (xml == NULL) {
+ return;
+ }
+
+ v3_xml_free(xml->child);
+ v3_xml_free(xml->ordered);
+
+ if (xml->parent == NULL) {
+ // free root tag allocations
+
+ for (i = 10; root->ent[i]; i += 2) {
+ // 0 - 9 are default entites (<>&"')
+ if ((s = root->ent[i + 1]) < root->tmp_start || s > root->tmp_end) {
+ V3_Free(s);
+ }
+ }
+
+ V3_Free(root->ent); // free list of general entities
+
+ for (i = 0; (a = root->attr[i]); i++) {
+ for (j = 1; a[j++]; j += 2) {
+ // free malloced attribute values
+ if (a[j] && (a[j] < root->tmp_start || a[j] > root->tmp_end)) {
+ V3_Free(a[j]);
+ }
+ }
+ V3_Free(a);
+ }
+
+ if (root->attr[0]) {
+ // free default attribute list
+ V3_Free(root->attr);
+ }
+
+ V3_Free(root->str_ptr); // malloced xml data
+ }
+
+ v3_xml_free_attr(xml->attr); // tag attributes
+
+ if ((xml->flags & V3_XML_TXTM)) {
+ // character content
+ V3_Free(xml->txt);
+ }
+
+ if ((xml->flags & V3_XML_NAMEM)) {
+ // tag name
+ V3_Free(xml->name);
+ }
+
+ V3_Free(xml);
+}
+
--- /dev/null
+
+CC = gcc
+CFLAGS = -Wall -g
+LDFLAGS =
+
+
+OBJS = main.c ezxml.c
+
+all: builder
+
+
+builder: $(OBJS)
+ $(CC) $(CFLAGS) $(OBJS) -o build_vm
+
+clean:
+ rm -f *.o build_vm
\ No newline at end of file
--- /dev/null
+Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+
+<!-- This defines a PC VM. The class defines the initial cpu/memory state of the VM. This drives the initialization of CPU registers, as well as BIOS memory mappings.-->
+<vm class="PC">
+
+ <!-- Memory in MB -->
+ <memory>1024</memory>
+
+ <!-- Basic VMM system flags -->
+ <telemetry>enable</telemetry>
+ <paging>nested</paging>
+ <schedule_hz>100</schedule_hz>
+
+
+ <!-- Memory redirections -->
+ <!-- Redirects a guest's memory region to a host physical address -->
+ <memmap>
+ <!-- This region maps the VGA framebuffer to the host's framebuffer -->
+ <region>
+ <start>0xa0000</start>
+ <end>0xc0000</end>
+ <host_addr>0xa0000</host_addr>
+ </region>
+ </memmap>
+
+
+ <!-- List of binary files to include with configuration -->
+ <!-- This is where you add disk images -->
+ <files>
+ <!-- The file 'id' is used as a reference for other configuration components -->
+ <file id="boot-cd" filename="/home/jarusl/image.iso" />
+ <!--<file id="harddisk" filename="firefox.img" />-->
+ </files>
+
+
+ <!-- List of devices attached to guest -->
+ <!-- The device 'ID' is the device name in the global device registry -->
+ <!-- The device 'name' is the reference to the device instance associated with a VM -->
+ <!-- The name can be used as a reference by other devices -->
+ <devices>
+ <device id="8259A" name="PIC"/>
+ <device id="KEYBOARD" name="keyboard"/>
+ <device id="8254_PIT" name="PIC" />
+ <device id="BOCHS_DEBUG" name="bochs debug"/>
+ <device id="OS_DEBUG" name="os debug" />
+ <device id="LAPIC" name="apic"/>
+ <device id="IOAPIC" name="ioapic">
+ <irq_bus>apic</irq_bus>
+ </device>
+
+<!--
+ <device id="CGA_VIDEO" name="cga" passthrough="enable" />
+ <device id="TELNET_CONSOLE" name="telnet console">
+ <frontend tag="CGA_VIDEO" />
+ <port>19997</port>
+ </device>
+-->
+ <device id="PCI" name="pci0" />
+
+ <device id="i440FX" name="northbridge">
+ <bus>pci0</bus>
+ </device>
+
+ <device id="PIIX3" name="southbridge">
+ <bus>pci0</bus>
+ </device>
+
+ <device id="LNX_VIRTIO_SYM" name="sym_pci">
+ <bus>pci0</bus>
+ </device>
+
+ <device id="LNX_VIRTIO_BLK" name="blk_virtio">
+ <bus>pci0</bus>
+ </device>
+
+ <device id="LNX_VIRTIO_BALLOON" name="balloon">
+ <bus>pci0</bus>
+ </device>
+
+ <device id="IDE" name="ide">
+ <bus>pci0</bus>
+ <controller>southbridge</controller>
+ </device>
+
+ <device id="PCI_PASSTHROUGH" name="e1000">
+ <bus>pci0</bus>
+ <vendor_id>0x8086</vendor_id>
+ <device_id>0x100e</device_id>
+ </device>
+
+ <device id="PCI_PASSTHROUGH" name="e1000-hw">
+ <bus>pci0</bus>
+ <vendor_id>0x8086</vendor_id>
+ <device_id>0x107c</device_id>
+ <irq>59</irq>
+ </device>
+
+
+ <!-- This is a Storage Backend that connects to a frontend -->
+ <!-- The frontend section is passed to the frontend when the backend connects -->
+ <!-- The file tag refers to an 'id' already listed in the file list section above -->
+ <device id="RAMDISK" name="CD0">
+ <file>boot-cd</file>
+ <frontend tag="ide">
+ <model>V3Vee CDROM</model>
+ <type>CDROM</type>
+ <bus_num>0</bus_num>
+ <drive_num>0</drive_num>
+ </frontend>
+ </device>
+
+ <device id="SYM_SWAP" name="sym swap">
+ <frontend tag="blk_virtio" />
+ <size>150</size>
+ </device>
+
+
+<!--
+ <device id="RAMDISK" name="HD0">
+ <file>harddisk</file>
+ <frontend tag="blk_virtio" />
+ </device>
+-->
+
+ <device id="NVRAM" name="nvram">
+ <storage>ide</storage>
+ </device>
+
+ <device id="GENERIC" name="generic">
+ <ports>
+ <start>0x00</start>
+ <end>0x07</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <start>0xc0</start>
+ <end>0xc7</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- DMA 1 page registers -->
+ <start>0x81</start>
+ <end>0x87</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- DMA 2 page registers -->
+ <start>0x88</start>
+ <end>0x8f</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- DMA 1 Misc Registers -->
+ <start>0x08</start>
+ <end>0x0f</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- DMA 2 Misc Registers -->
+ <start>0xd0</start>
+ <end>0xde</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- Serial COM 1 -->
+ <start>0x3f8</start>
+ <end>0x3ff</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- Serial COM 2 -->
+ <start>0x2f8</start>
+ <end>0x2ff</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- Serial COM 3 -->
+ <start>0x3e8</start>
+ <end>0x3ef</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- Serial COM 4 -->
+ <start>0x2e8</start>
+ <end>0x2ef</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- Parallel Port -->
+ <start>0x378</start>
+ <end>0x37f</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- Graphics Card modeerations -->
+ <start>0x3b0</start>
+ <end>0x3bb</end>
+ <mode>PRINT_AND_PASSTHROUGH</mode>
+ </ports>
+ <ports>
+ <!-- Graphics Card modeerations -->
+ <start>0x3c0</start>
+ <end>0x3df</end>
+ <mode>PRINT_AND_PASSTHROUGH</mode>
+ </ports>
+ <ports>
+ <!-- ISA PNP -->
+ <start>0x274</start>
+ <end>0x277</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- ISA PNP -->
+ <start>0x279</start>
+ <end>0x279</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ <ports>
+ <!-- ISA PNP -->
+ <start>0xa79</start>
+ <end>0xa79</end>
+ <mode>PRINT_AND_IGNORE</mode>
+ </ports>
+ </device>
+ </devices>
+
+
+</vm>
+
+
--- /dev/null
+/* ezxml.c
+ *
+ * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/types.h>
+#ifndef EZXML_NOMMAP
+#include <sys/mman.h>
+#endif // EZXML_NOMMAP
+#include <sys/stat.h>
+#include "ezxml.h"
+
+#define EZXML_WS "\t\r\n " // whitespace
+#define EZXML_ERRL 128 // maximum error string length
+
+typedef struct ezxml_root *ezxml_root_t;
+struct ezxml_root { // additional data for the root tag
+ struct ezxml xml; // is a super-struct built on top of ezxml struct
+ ezxml_t cur; // current xml tree insertion point
+ char *m; // original xml string
+ size_t len; // length of allocated memory for mmap, -1 for malloc
+ char *u; // UTF-8 conversion of string if original was UTF-16
+ char *s; // start of work area
+ char *e; // end of work area
+ char **ent; // general entities (ampersand sequences)
+ char ***attr; // default attributes
+ char ***pi; // processing instructions
+ short standalone; // non-zero if <?xml standalone="yes"?>
+ char err[EZXML_ERRL]; // error string
+};
+
+char *EZXML_NIL[] = { NULL }; // empty, null terminated array of strings
+
+// returns the first child tag with the given name or NULL if not found
+ezxml_t ezxml_child(ezxml_t xml, const char *name)
+{
+ xml = (xml) ? xml->child : NULL;
+ while (xml && strcmp(name, xml->name)) xml = xml->sibling;
+ return xml;
+}
+
+// returns the Nth tag with the same name in the same subsection or NULL if not
+// found
+ezxml_t ezxml_idx(ezxml_t xml, int idx)
+{
+ for (; xml && idx; idx--) xml = xml->next;
+ return xml;
+}
+
+// returns the value of the requested tag attribute or NULL if not found
+const char *ezxml_attr(ezxml_t xml, const char *attr)
+{
+ int i = 0, j = 1;
+ ezxml_root_t root = (ezxml_root_t)xml;
+
+ if (! xml || ! xml->attr) return NULL;
+ while (xml->attr[i] && strcmp(attr, xml->attr[i])) i += 2;
+ if (xml->attr[i]) return xml->attr[i + 1]; // found attribute
+
+ while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+ for (i = 0; root->attr[i] && strcmp(xml->name, root->attr[i][0]); i++);
+ if (! root->attr[i]) return NULL; // no matching default attributes
+ while (root->attr[i][j] && strcmp(attr, root->attr[i][j])) j += 3;
+ return (root->attr[i][j]) ? root->attr[i][j + 1] : NULL; // found default
+}
+
+// same as ezxml_get but takes an already initialized va_list
+ezxml_t ezxml_vget(ezxml_t xml, va_list ap)
+{
+ char *name = va_arg(ap, char *);
+ int idx = -1;
+
+ if (name && *name) {
+ idx = va_arg(ap, int);
+ xml = ezxml_child(xml, name);
+ }
+ return (idx < 0) ? xml : ezxml_vget(ezxml_idx(xml, idx), ap);
+}
+
+// Traverses the xml tree to retrieve a specific subtag. Takes a variable
+// length list of tag names and indexes. The argument list must be terminated
+// by either an index of -1 or an empty string tag name. Example:
+// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1);
+// This retrieves the title of the 3rd book on the 1st shelf of library.
+// Returns NULL if not found.
+ezxml_t ezxml_get(ezxml_t xml, ...)
+{
+ va_list ap;
+ ezxml_t r;
+
+ va_start(ap, xml);
+ r = ezxml_vget(xml, ap);
+ va_end(ap);
+ return r;
+}
+
+// returns a null terminated array of processing instructions for the given
+// target
+const char **ezxml_pi(ezxml_t xml, const char *target)
+{
+ ezxml_root_t root = (ezxml_root_t)xml;
+ int i = 0;
+
+ if (! root) return (const char **)EZXML_NIL;
+ while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+ while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
+ return (const char **)((root->pi[i]) ? root->pi[i] + 1 : EZXML_NIL);
+}
+
+// set an error string and return root
+ezxml_t ezxml_err(ezxml_root_t root, char *s, const char *err, ...)
+{
+ va_list ap;
+ int line = 1;
+ char *t, fmt[EZXML_ERRL];
+
+ for (t = root->s; t < s; t++) if (*t == '\n') line++;
+ snprintf(fmt, EZXML_ERRL, "[error near line %d]: %s", line, err);
+
+ va_start(ap, err);
+ vsnprintf(root->err, EZXML_ERRL, fmt, ap);
+ va_end(ap);
+
+ return &root->xml;
+}
+
+// Recursively decodes entity and character references and normalizes new lines
+// ent is a null terminated array of alternating entity names and values. set t
+// to '&' for general entity decoding, '%' for parameter entity decoding, 'c'
+// for cdata sections, ' ' for attribute normalization, or '*' for non-cdata
+// attribute normalization. Returns s, or if the decoded string is longer than
+// s, returns a malloced string that must be freed.
+char *ezxml_decode(char *s, char **ent, char t)
+{
+ char *e, *r = s, *m = s;
+ long b, c, d, l;
+
+ for (; *s; s++) { // normalize line endings
+ while (*s == '\r') {
+ *(s++) = '\n';
+ if (*s == '\n') memmove(s, (s + 1), strlen(s));
+ }
+ }
+
+ for (s = r; ; ) {
+ while (*s && *s != '&' && (*s != '%' || t != '%') && !isspace(*s)) s++;
+
+ if (! *s) break;
+ else if (t != 'c' && ! strncmp(s, "&#", 2)) { // character reference
+ if (s[2] == 'x') c = strtol(s + 3, &e, 16); // base 16
+ else c = strtol(s + 2, &e, 10); // base 10
+ if (! c || *e != ';') { s++; continue; } // not a character ref
+
+ if (c < 0x80) *(s++) = c; // US-ASCII subset
+ else { // multi-byte UTF-8 sequence
+ for (b = 0, d = c; d; d /= 2) b++; // number of bits in c
+ b = (b - 2) / 5; // number of bytes in payload
+ *(s++) = (0xFF << (7 - b)) | (c >> (6 * b)); // head
+ while (b) *(s++) = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload
+ }
+
+ memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';')));
+ }
+ else if ((*s == '&' && (t == '&' || t == ' ' || t == '*')) ||
+ (*s == '%' && t == '%')) { // entity reference
+ for (b = 0; ent[b] && strncmp(s + 1, ent[b], strlen(ent[b]));
+ b += 2); // find entity in entity list
+
+ if (ent[b++]) { // found a match
+ if ((c = strlen(ent[b])) - 1 > (e = strchr(s, ';')) - s) {
+ l = (d = (s - r)) + c + strlen(e); // new length
+ r = (r == m) ? strcpy(malloc(l), r) : realloc(r, l);
+ e = strchr((s = r + d), ';'); // fix up pointers
+ }
+
+ memmove(s + c, e + 1, strlen(e)); // shift rest of string
+ strncpy(s, ent[b], c); // copy in replacement text
+ }
+ else s++; // not a known entity
+ }
+ else if ((t == ' ' || t == '*') && isspace(*s)) *(s++) = ' ';
+ else s++; // no decoding needed
+ }
+
+ if (t == '*') { // normalize spaces for non-cdata attributes
+ for (s = r; *s; s++) {
+ if ((l = strspn(s, " "))) memmove(s, s + l, strlen(s + l) + 1);
+ while (*s && *s != ' ') s++;
+ }
+ if (--s >= r && *s == ' ') *s = '\0'; // trim any trailing space
+ }
+ return r;
+}
+
+// called when parser finds start of new tag
+void ezxml_open_tag(ezxml_root_t root, char *name, char **attr)
+{
+ ezxml_t xml = root->cur;
+
+ if (xml->name) xml = ezxml_add_child(xml, name, strlen(xml->txt));
+ else xml->name = name; // first open tag
+
+ xml->attr = attr;
+ root->cur = xml; // update tag insertion point
+}
+
+// called when parser finds character content between open and closing tag
+void ezxml_char_content(ezxml_root_t root, char *s, size_t len, char t)
+{
+ ezxml_t xml = root->cur;
+ char *m = s;
+ size_t l;
+
+ if (! xml || ! xml->name || ! len) return; // sanity check
+
+ s[len] = '\0'; // null terminate text (calling functions anticipate this)
+ len = strlen(s = ezxml_decode(s, root->ent, t)) + 1;
+
+ if (! *(xml->txt)) xml->txt = s; // initial character content
+ else { // allocate our own memory and make a copy
+ xml->txt = (xml->flags & EZXML_TXTM) // allocate some space
+ ? realloc(xml->txt, (l = strlen(xml->txt)) + len)
+ : strcpy(malloc((l = strlen(xml->txt)) + len), xml->txt);
+ strcpy(xml->txt + l, s); // add new char content
+ if (s != m) free(s); // free s if it was malloced by ezxml_decode()
+ }
+
+ if (xml->txt != m) ezxml_set_flag(xml, EZXML_TXTM);
+}
+
+// called when parser finds closing tag
+ezxml_t ezxml_close_tag(ezxml_root_t root, char *name, char *s)
+{
+ if (! root->cur || ! root->cur->name || strcmp(name, root->cur->name))
+ return ezxml_err(root, s, "unexpected closing tag </%s>", name);
+
+ root->cur = root->cur->parent;
+ return NULL;
+}
+
+// checks for circular entity references, returns non-zero if no circular
+// references are found, zero otherwise
+int ezxml_ent_ok(char *name, char *s, char **ent)
+{
+ int i;
+
+ for (; ; s++) {
+ while (*s && *s != '&') s++; // find next entity reference
+ if (! *s) return 1;
+ if (! strncmp(s + 1, name, strlen(name))) return 0; // circular ref.
+ for (i = 0; ent[i] && strncmp(ent[i], s + 1, strlen(ent[i])); i += 2);
+ if (ent[i] && ! ezxml_ent_ok(name, ent[i + 1], ent)) return 0;
+ }
+}
+
+// called when the parser finds a processing instruction
+void ezxml_proc_inst(ezxml_root_t root, char *s, size_t len)
+{
+ int i = 0, j = 1;
+ char *target = s;
+
+ s[len] = '\0'; // null terminate instruction
+ if (*(s += strcspn(s, EZXML_WS))) {
+ *s = '\0'; // null terminate target
+ s += strspn(s + 1, EZXML_WS) + 1; // skip whitespace after target
+ }
+
+ if (! strcmp(target, "xml")) { // <?xml ... ?>
+ if ((s = strstr(s, "standalone")) && ! strncmp(s + strspn(s + 10,
+ EZXML_WS "='\"") + 10, "yes", 3)) root->standalone = 1;
+ return;
+ }
+
+ if (! root->pi[0]) *(root->pi = malloc(sizeof(char **))) = NULL; //first pi
+
+ while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
+ if (! root->pi[i]) { // new target
+ root->pi = realloc(root->pi, sizeof(char **) * (i + 2));
+ root->pi[i] = malloc(sizeof(char *) * 3);
+ root->pi[i][0] = target;
+ root->pi[i][1] = (char *)(root->pi[i + 1] = NULL); // terminate pi list
+ root->pi[i][2] = strdup(""); // empty document position list
+ }
+
+ while (root->pi[i][j]) j++; // find end of instruction list for this target
+ root->pi[i] = realloc(root->pi[i], sizeof(char *) * (j + 3));
+ root->pi[i][j + 2] = realloc(root->pi[i][j + 1], j + 1);
+ strcpy(root->pi[i][j + 2] + j - 1, (root->xml.name) ? ">" : "<");
+ root->pi[i][j + 1] = NULL; // null terminate pi list for this target
+ root->pi[i][j] = s; // set instruction
+}
+
+// called when the parser finds an internal doctype subset
+short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len)
+{
+ char q, *c, *t, *n = NULL, *v, **ent, **pe;
+ int i, j;
+
+ pe = memcpy(malloc(sizeof(EZXML_NIL)), EZXML_NIL, sizeof(EZXML_NIL));
+
+ for (s[len] = '\0'; s; ) {
+ while (*s && *s != '<' && *s != '%') s++; // find next declaration
+
+ if (! *s) break;
+ else if (! strncmp(s, "<!ENTITY", 8)) { // parse entity definitions
+ c = s += strspn(s + 8, EZXML_WS) + 8; // skip white space separator
+ n = s + strspn(s, EZXML_WS "%"); // find name
+ *(s = n + strcspn(n, EZXML_WS)) = ';'; // append ; to name
+
+ v = s + strspn(s + 1, EZXML_WS) + 1; // find value
+ if ((q = *(v++)) != '"' && q != '\'') { // skip externals
+ s = strchr(s, '>');
+ continue;
+ }
+
+ for (i = 0, ent = (*c == '%') ? pe : root->ent; ent[i]; i++);
+ ent = realloc(ent, (i + 3) * sizeof(char *)); // space for next ent
+ if (*c == '%') pe = ent;
+ else root->ent = ent;
+
+ *(++s) = '\0'; // null terminate name
+ if ((s = strchr(v, q))) *(s++) = '\0'; // null terminate value
+ ent[i + 1] = ezxml_decode(v, pe, '%'); // set value
+ ent[i + 2] = NULL; // null terminate entity list
+ if (! ezxml_ent_ok(n, ent[i + 1], ent)) { // circular reference
+ if (ent[i + 1] != v) free(ent[i + 1]);
+ ezxml_err(root, v, "circular entity declaration &%s", n);
+ break;
+ }
+ else ent[i] = n; // set entity name
+ }
+ else if (! strncmp(s, "<!ATTLIST", 9)) { // parse default attributes
+ t = s + strspn(s + 9, EZXML_WS) + 9; // skip whitespace separator
+ if (! *t) { ezxml_err(root, t, "unclosed <!ATTLIST"); break; }
+ if (*(s = t + strcspn(t, EZXML_WS ">")) == '>') continue;
+ else *s = '\0'; // null terminate tag name
+ for (i = 0; root->attr[i] && strcmp(n, root->attr[i][0]); i++);
+
+ while (*(n = ++s + strspn(s, EZXML_WS)) && *n != '>') {
+ if (*(s = n + strcspn(n, EZXML_WS))) *s = '\0'; // attr name
+ else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+ s += strspn(s + 1, EZXML_WS) + 1; // find next token
+ c = (strncmp(s, "CDATA", 5)) ? "*" : " "; // is it cdata?
+ if (! strncmp(s, "NOTATION", 8))
+ s += strspn(s + 8, EZXML_WS) + 8;
+ s = (*s == '(') ? strchr(s, ')') : s + strcspn(s, EZXML_WS);
+ if (! s) { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+ s += strspn(s, EZXML_WS ")"); // skip white space separator
+ if (! strncmp(s, "#FIXED", 6))
+ s += strspn(s + 6, EZXML_WS) + 6;
+ if (*s == '#') { // no default value
+ s += strcspn(s, EZXML_WS ">") - 1;
+ if (*c == ' ') continue; // cdata is default, nothing to do
+ v = NULL;
+ }
+ else if ((*s == '"' || *s == '\'') && // default value
+ (s = strchr(v = s + 1, *s))) *s = '\0';
+ else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+ if (! root->attr[i]) { // new tag name
+ root->attr = (! i) ? malloc(2 * sizeof(char **))
+ : realloc(root->attr,
+ (i + 2) * sizeof(char **));
+ root->attr[i] = malloc(2 * sizeof(char *));
+ root->attr[i][0] = t; // set tag name
+ root->attr[i][1] = (char *)(root->attr[i + 1] = NULL);
+ }
+
+ for (j = 1; root->attr[i][j]; j += 3); // find end of list
+ root->attr[i] = realloc(root->attr[i],
+ (j + 4) * sizeof(char *));
+
+ root->attr[i][j + 3] = NULL; // null terminate list
+ root->attr[i][j + 2] = c; // is it cdata?
+ root->attr[i][j + 1] = (v) ? ezxml_decode(v, root->ent, *c)
+ : NULL;
+ root->attr[i][j] = n; // attribute name
+ }
+ }
+ else if (! strncmp(s, "<!--", 4)) s = strstr(s + 4, "-->"); // comments
+ else if (! strncmp(s, "<?", 2)) { // processing instructions
+ if ((s = strstr(c = s + 2, "?>")))
+ ezxml_proc_inst(root, c, s++ - c);
+ }
+ else if (*s == '<') s = strchr(s, '>'); // skip other declarations
+ else if (*(s++) == '%' && ! root->standalone) break;
+ }
+
+ free(pe);
+ return ! *root->err;
+}
+
+// Converts a UTF-16 string to UTF-8. Returns a new string that must be freed
+// or NULL if no conversion was needed.
+char *ezxml_str2utf8(char **s, size_t *len)
+{
+ char *u;
+ size_t l = 0, sl, max = *len;
+ long c, d;
+ int b, be = (**s == '\xFE') ? 1 : (**s == '\xFF') ? 0 : -1;
+
+ if (be == -1) return NULL; // not UTF-16
+
+ u = malloc(max);
+ for (sl = 2; sl < *len - 1; sl += 2) {
+ c = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF) //UTF-16BE
+ : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); //UTF-16LE
+ if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) { // high-half
+ d = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)
+ : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF);
+ c = (((c & 0x3FF) << 10) | (d & 0x3FF)) + 0x10000;
+ }
+
+ while (l + 6 > max) u = realloc(u, max += EZXML_BUFSIZE);
+ if (c < 0x80) u[l++] = c; // US-ASCII subset
+ else { // multi-byte UTF-8 sequence
+ for (b = 0, d = c; d; d /= 2) b++; // bits in c
+ b = (b - 2) / 5; // bytes in payload
+ u[l++] = (0xFF << (7 - b)) | (c >> (6 * b)); // head
+ while (b) u[l++] = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload
+ }
+ }
+ return *s = realloc(u, *len = l);
+}
+
+// frees a tag attribute list
+void ezxml_free_attr(char **attr) {
+ int i = 0;
+ char *m;
+
+ if (! attr || attr == EZXML_NIL) return; // nothing to free
+ while (attr[i]) i += 2; // find end of attribute list
+ m = attr[i + 1]; // list of which names and values are malloced
+ for (i = 0; m[i]; i++) {
+ if (m[i] & EZXML_NAMEM) free(attr[i * 2]);
+ if (m[i] & EZXML_TXTM) free(attr[(i * 2) + 1]);
+ }
+ free(m);
+ free(attr);
+}
+
+// parse the given xml string and return an ezxml structure
+ezxml_t ezxml_parse_str(char *s, size_t len)
+{
+ ezxml_root_t root = (ezxml_root_t)ezxml_new(NULL);
+ char q, e, *d, **attr, **a = NULL; // initialize a to avoid compile warning
+ int l, i, j;
+
+ root->m = s;
+ if (! len) return ezxml_err(root, NULL, "root tag missing");
+ root->u = ezxml_str2utf8(&s, &len); // convert utf-16 to utf-8
+ root->e = (root->s = s) + len; // record start and end of work area
+
+ e = s[len - 1]; // save end char
+ s[len - 1] = '\0'; // turn end char into null terminator
+
+ while (*s && *s != '<') s++; // find first tag
+ if (! *s) return ezxml_err(root, s, "root tag missing");
+
+ for (; ; ) {
+ attr = (char **)EZXML_NIL;
+ d = ++s;
+
+ if (isalpha(*s) || *s == '_' || *s == ':' || *s < '\0') { // new tag
+ if (! root->cur)
+ return ezxml_err(root, d, "markup outside of root element");
+
+ s += strcspn(s, EZXML_WS "/>");
+ while (isspace(*s)) *(s++) = '\0'; // null terminate tag name
+
+ if (*s && *s != '/' && *s != '>') // find tag in default attr list
+ for (i = 0; (a = root->attr[i]) && strcmp(a[0], d); i++);
+
+ for (l = 0; *s && *s != '/' && *s != '>'; l += 2) { // new attrib
+ attr = (l) ? realloc(attr, (l + 4) * sizeof(char *))
+ : malloc(4 * sizeof(char *)); // allocate space
+ attr[l + 3] = (l) ? realloc(attr[l + 1], (l / 2) + 2)
+ : malloc(2); // mem for list of maloced vals
+ strcpy(attr[l + 3] + (l / 2), " "); // value is not malloced
+ attr[l + 2] = NULL; // null terminate list
+ attr[l + 1] = ""; // temporary attribute value
+ attr[l] = s; // set attribute name
+
+ s += strcspn(s, EZXML_WS "=/>");
+ if (*s == '=' || isspace(*s)) {
+ *(s++) = '\0'; // null terminate tag attribute name
+ q = *(s += strspn(s, EZXML_WS "="));
+ if (q == '"' || q == '\'') { // attribute value
+ attr[l + 1] = ++s;
+ while (*s && *s != q) s++;
+ if (*s) *(s++) = '\0'; // null terminate attribute val
+ else {
+ ezxml_free_attr(attr);
+ return ezxml_err(root, d, "missing %c", q);
+ }
+
+ for (j = 1; a && a[j] && strcmp(a[j], attr[l]); j +=3);
+ attr[l + 1] = ezxml_decode(attr[l + 1], root->ent, (a
+ && a[j]) ? *a[j + 2] : ' ');
+ if (attr[l + 1] < d || attr[l + 1] > s)
+ attr[l + 3][l / 2] = EZXML_TXTM; // value malloced
+ }
+ }
+ while (isspace(*s)) s++;
+ }
+
+ if (*s == '/') { // self closing tag
+ *(s++) = '\0';
+ if ((*s && *s != '>') || (! *s && e != '>')) {
+ if (l) ezxml_free_attr(attr);
+ return ezxml_err(root, d, "missing >");
+ }
+ ezxml_open_tag(root, d, attr);
+ ezxml_close_tag(root, d, s);
+ }
+ else if ((q = *s) == '>' || (! *s && e == '>')) { // open tag
+ *s = '\0'; // temporarily null terminate tag name
+ ezxml_open_tag(root, d, attr);
+ *s = q;
+ }
+ else {
+ if (l) ezxml_free_attr(attr);
+ return ezxml_err(root, d, "missing >");
+ }
+ }
+ else if (*s == '/') { // close tag
+ s += strcspn(d = s + 1, EZXML_WS ">") + 1;
+ if (! (q = *s) && e != '>') return ezxml_err(root, d, "missing >");
+ *s = '\0'; // temporarily null terminate tag name
+ if (ezxml_close_tag(root, d, s)) return &root->xml;
+ if (isspace(*s = q)) s += strspn(s, EZXML_WS);
+ }
+ else if (! strncmp(s, "!--", 3)) { // xml comment
+ if (! (s = strstr(s + 3, "--")) || (*(s += 2) != '>' && *s) ||
+ (! *s && e != '>')) return ezxml_err(root, d, "unclosed <!--");
+ }
+ else if (! strncmp(s, "![CDATA[", 8)) { // cdata
+ if ((s = strstr(s, "]]>")))
+ ezxml_char_content(root, d + 8, (s += 2) - d - 10, 'c');
+ else return ezxml_err(root, d, "unclosed <![CDATA[");
+ }
+ else if (! strncmp(s, "!DOCTYPE", 8)) { // dtd
+ for (l = 0; *s && ((! l && *s != '>') || (l && (*s != ']' ||
+ *(s + strspn(s + 1, EZXML_WS) + 1) != '>')));
+ l = (*s == '[') ? 1 : l) s += strcspn(s + 1, "[]>") + 1;
+ if (! *s && e != '>')
+ return ezxml_err(root, d, "unclosed <!DOCTYPE");
+ d = (l) ? strchr(d, '[') + 1 : d;
+ if (l && ! ezxml_internal_dtd(root, d, s++ - d)) return &root->xml;
+ }
+ else if (*s == '?') { // <?...?> processing instructions
+ do { s = strchr(s, '?'); } while (s && *(++s) && *s != '>');
+ if (! s || (! *s && e != '>'))
+ return ezxml_err(root, d, "unclosed <?");
+ else ezxml_proc_inst(root, d + 1, s - d - 2);
+ }
+ else return ezxml_err(root, d, "unexpected <");
+
+ if (! s || ! *s) break;
+ *s = '\0';
+ d = ++s;
+ if (*s && *s != '<') { // tag character content
+ while (*s && *s != '<') s++;
+ if (*s) ezxml_char_content(root, d, s - d, '&');
+ else break;
+ }
+ else if (! *s) break;
+ }
+
+ if (! root->cur) return &root->xml;
+ else if (! root->cur->name) return ezxml_err(root, d, "root tag missing");
+ else return ezxml_err(root, d, "unclosed tag <%s>", root->cur->name);
+}
+
+// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire
+// stream into memory and then parses it. For xml files, use ezxml_parse_file()
+// or ezxml_parse_fd()
+ezxml_t ezxml_parse_fp(FILE *fp)
+{
+ ezxml_root_t root;
+ size_t l, len = 0;
+ char *s;
+
+ if (! (s = malloc(EZXML_BUFSIZE))) return NULL;
+ do {
+ len += (l = fread((s + len), 1, EZXML_BUFSIZE, fp));
+ if (l == EZXML_BUFSIZE) s = realloc(s, len + EZXML_BUFSIZE);
+ } while (s && l == EZXML_BUFSIZE);
+
+ if (! s) return NULL;
+ root = (ezxml_root_t)ezxml_parse_str(s, len);
+ root->len = -1; // so we know to free s in ezxml_free()
+ return &root->xml;
+}
+
+// A wrapper for ezxml_parse_str() that accepts a file descriptor. First
+// attempts to mem map the file. Failing that, reads the file into memory.
+// Returns NULL on failure.
+ezxml_t ezxml_parse_fd(int fd)
+{
+ ezxml_root_t root;
+ struct stat st;
+ size_t l;
+ void *m;
+
+ if (fd < 0) return NULL;
+ fstat(fd, &st);
+
+#ifndef EZXML_NOMMAP
+ l = (st.st_size + sysconf(_SC_PAGESIZE) - 1) & ~(sysconf(_SC_PAGESIZE) -1);
+ if ((m = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) !=
+ MAP_FAILED) {
+ madvise(m, l, MADV_SEQUENTIAL); // optimize for sequential access
+ root = (ezxml_root_t)ezxml_parse_str(m, st.st_size);
+ madvise(m, root->len = l, MADV_NORMAL); // put it back to normal
+ }
+ else { // mmap failed, read file into memory
+#endif // EZXML_NOMMAP
+ l = read(fd, m = malloc(st.st_size), st.st_size);
+ root = (ezxml_root_t)ezxml_parse_str(m, l);
+ root->len = -1; // so we know to free s in ezxml_free()
+#ifndef EZXML_NOMMAP
+ }
+#endif // EZXML_NOMMAP
+ return &root->xml;
+}
+
+// a wrapper for ezxml_parse_fd that accepts a file name
+ezxml_t ezxml_parse_file(const char *file)
+{
+ int fd = open(file, O_RDONLY, 0);
+ ezxml_t xml = ezxml_parse_fd(fd);
+
+ if (fd >= 0) close(fd);
+ return xml;
+}
+
+// Encodes ampersand sequences appending the results to *dst, reallocating *dst
+// if length excedes max. a is non-zero for attribute encoding. Returns *dst
+char *ezxml_ampencode(const char *s, size_t len, char **dst, size_t *dlen,
+ size_t *max, short a)
+{
+ const char *e;
+
+ for (e = s + len; s != e; s++) {
+ while (*dlen + 10 > *max) *dst = realloc(*dst, *max += EZXML_BUFSIZE);
+
+ switch (*s) {
+ case '\0': return *dst;
+ case '&': *dlen += sprintf(*dst + *dlen, "&"); break;
+ case '<': *dlen += sprintf(*dst + *dlen, "<"); break;
+ case '>': *dlen += sprintf(*dst + *dlen, ">"); break;
+ case '"': *dlen += sprintf(*dst + *dlen, (a) ? """ : "\""); break;
+ case '\n': *dlen += sprintf(*dst + *dlen, (a) ? "
" : "\n"); break;
+ case '\t': *dlen += sprintf(*dst + *dlen, (a) ? "	" : "\t"); break;
+ case '\r': *dlen += sprintf(*dst + *dlen, "
"); break;
+ default: (*dst)[(*dlen)++] = *s;
+ }
+ }
+ return *dst;
+}
+
+// Recursively converts each tag to xml appending it to *s. Reallocates *s if
+// its length excedes max. start is the location of the previous tag in the
+// parent tag's character content. Returns *s.
+char *ezxml_toxml_r(ezxml_t xml, char **s, size_t *len, size_t *max,
+ size_t start, char ***attr)
+{
+ int i, j;
+ char *txt = (xml->parent) ? xml->parent->txt : "";
+ size_t off = 0;
+
+ // parent character content up to this tag
+ *s = ezxml_ampencode(txt + start, xml->off - start, s, len, max, 0);
+
+ while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, "<%s", xml->name); // open tag
+ for (i = 0; xml->attr[i]; i += 2) { // tag attributes
+ if (ezxml_attr(xml, xml->attr[i]) != xml->attr[i + 1]) continue;
+ while (*len + strlen(xml->attr[i]) + 7 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, " %s=\"", xml->attr[i]);
+ ezxml_ampencode(xml->attr[i + 1], -1, s, len, max, 1);
+ *len += sprintf(*s + *len, "\"");
+ }
+
+ for (i = 0; attr[i] && strcmp(attr[i][0], xml->name); i++);
+ for (j = 1; attr[i] && attr[i][j]; j += 3) { // default attributes
+ if (! attr[i][j + 1] || ezxml_attr(xml, attr[i][j]) != attr[i][j + 1])
+ continue; // skip duplicates and non-values
+ while (*len + strlen(attr[i][j]) + 7 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, " %s=\"", attr[i][j]);
+ ezxml_ampencode(attr[i][j + 1], -1, s, len, max, 1);
+ *len += sprintf(*s + *len, "\"");
+ }
+ *len += sprintf(*s + *len, ">");
+
+ *s = (xml->child) ? ezxml_toxml_r(xml->child, s, len, max, 0, attr) //child
+ : ezxml_ampencode(xml->txt, -1, s, len, max, 0); //data
+
+ while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, "</%s>", xml->name); // close tag
+
+ while (txt[off] && off < xml->off) off++; // make sure off is within bounds
+ return (xml->ordered) ? ezxml_toxml_r(xml->ordered, s, len, max, off, attr)
+ : ezxml_ampencode(txt + off, -1, s, len, max, 0);
+}
+
+// Converts an ezxml structure back to xml. Returns a string of xml data that
+// must be freed.
+char *ezxml_toxml(ezxml_t xml)
+{
+ ezxml_t p = (xml) ? xml->parent : NULL, o = (xml) ? xml->ordered : NULL;
+ ezxml_root_t root = (ezxml_root_t)xml;
+ size_t len = 0, max = EZXML_BUFSIZE;
+ char *s = strcpy(malloc(max), ""), *t, *n;
+ int i, j, k;
+
+ if (! xml || ! xml->name) return realloc(s, len + 1);
+ while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+
+ for (i = 0; ! p && root->pi[i]; i++) { // pre-root processing instructions
+ for (k = 2; root->pi[i][k - 1]; k++);
+ for (j = 1; (n = root->pi[i][j]); j++) {
+ if (root->pi[i][k][j - 1] == '>') continue; // not pre-root
+ while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
+ s = realloc(s, max += EZXML_BUFSIZE);
+ len += sprintf(s + len, "<?%s%s%s?>\n", t, *n ? " " : "", n);
+ }
+ }
+
+ xml->parent = xml->ordered = NULL;
+ s = ezxml_toxml_r(xml, &s, &len, &max, 0, root->attr);
+ xml->parent = p;
+ xml->ordered = o;
+
+ for (i = 0; ! p && root->pi[i]; i++) { // post-root processing instructions
+ for (k = 2; root->pi[i][k - 1]; k++);
+ for (j = 1; (n = root->pi[i][j]); j++) {
+ if (root->pi[i][k][j - 1] == '<') continue; // not post-root
+ while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
+ s = realloc(s, max += EZXML_BUFSIZE);
+ len += sprintf(s + len, "\n<?%s%s%s?>", t, *n ? " " : "", n);
+ }
+ }
+ return realloc(s, len + 1);
+}
+
+// free the memory allocated for the ezxml structure
+void ezxml_free(ezxml_t xml)
+{
+ ezxml_root_t root = (ezxml_root_t)xml;
+ int i, j;
+ char **a, *s;
+
+ if (! xml) return;
+ ezxml_free(xml->child);
+ ezxml_free(xml->ordered);
+
+ if (! xml->parent) { // free root tag allocations
+ for (i = 10; root->ent[i]; i += 2) // 0 - 9 are default entites (<>&"')
+ if ((s = root->ent[i + 1]) < root->s || s > root->e) free(s);
+ free(root->ent); // free list of general entities
+
+ for (i = 0; (a = root->attr[i]); i++) {
+ for (j = 1; a[j++]; j += 2) // free malloced attribute values
+ if (a[j] && (a[j] < root->s || a[j] > root->e)) free(a[j]);
+ free(a);
+ }
+ if (root->attr[0]) free(root->attr); // free default attribute list
+
+ for (i = 0; root->pi[i]; i++) {
+ for (j = 1; root->pi[i][j]; j++);
+ free(root->pi[i][j + 1]);
+ free(root->pi[i]);
+ }
+ if (root->pi[0]) free(root->pi); // free processing instructions
+
+ if (root->len == -1) free(root->m); // malloced xml data
+#ifndef EZXML_NOMMAP
+ else if (root->len) munmap(root->m, root->len); // mem mapped xml data
+#endif // EZXML_NOMMAP
+ if (root->u) free(root->u); // utf8 conversion
+ }
+
+ ezxml_free_attr(xml->attr); // tag attributes
+ if ((xml->flags & EZXML_TXTM)) free(xml->txt); // character content
+ if ((xml->flags & EZXML_NAMEM)) free(xml->name); // tag name
+ free(xml);
+}
+
+// return parser error message or empty string if none
+const char *ezxml_error(ezxml_t xml)
+{
+ while (xml && xml->parent) xml = xml->parent; // find root tag
+ return (xml) ? ((ezxml_root_t)xml)->err : "";
+}
+
+// returns a new empty ezxml structure with the given root tag name
+ezxml_t ezxml_new(const char *name)
+{
+ static char *ent[] = { "lt;", "<", "gt;", ">", "quot;", """,
+ "apos;", "'", "amp;", "&", NULL };
+ ezxml_root_t root = (ezxml_root_t)memset(malloc(sizeof(struct ezxml_root)),
+ '\0', sizeof(struct ezxml_root));
+ root->xml.name = (char *)name;
+ root->cur = &root->xml;
+ strcpy(root->err, root->xml.txt = "");
+ root->ent = memcpy(malloc(sizeof(ent)), ent, sizeof(ent));
+ root->attr = root->pi = (char ***)(root->xml.attr = EZXML_NIL);
+ return &root->xml;
+}
+
+// inserts an existing tag into an ezxml structure
+ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off)
+{
+ ezxml_t cur, prev, head;
+
+ xml->next = xml->sibling = xml->ordered = NULL;
+ xml->off = off;
+ xml->parent = dest;
+
+ if ((head = dest->child)) { // already have sub tags
+ if (head->off <= off) { // not first subtag
+ for (cur = head; cur->ordered && cur->ordered->off <= off;
+ cur = cur->ordered);
+ xml->ordered = cur->ordered;
+ cur->ordered = xml;
+ }
+ else { // first subtag
+ xml->ordered = head;
+ dest->child = xml;
+ }
+
+ for (cur = head, prev = NULL; cur && strcmp(cur->name, xml->name);
+ prev = cur, cur = cur->sibling); // find tag type
+ if (cur && cur->off <= off) { // not first of type
+ while (cur->next && cur->next->off <= off) cur = cur->next;
+ xml->next = cur->next;
+ cur->next = xml;
+ }
+ else { // first tag of this type
+ if (prev && cur) prev->sibling = cur->sibling; // remove old first
+ xml->next = cur; // old first tag is now next
+ for (cur = head, prev = NULL; cur && cur->off <= off;
+ prev = cur, cur = cur->sibling); // new sibling insert point
+ xml->sibling = cur;
+ if (prev) prev->sibling = xml;
+ }
+ }
+ else dest->child = xml; // only sub tag
+
+ return xml;
+}
+
+// Adds a child tag. off is the offset of the child tag relative to the start
+// of the parent tag's character content. Returns the child tag.
+ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off)
+{
+ ezxml_t child;
+
+ if (! xml) return NULL;
+ child = (ezxml_t)memset(malloc(sizeof(struct ezxml)), '\0',
+ sizeof(struct ezxml));
+ child->name = (char *)name;
+ child->attr = EZXML_NIL;
+ child->txt = "";
+
+ return ezxml_insert(child, xml, off);
+}
+
+// sets the character content for the given tag and returns the tag
+ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt)
+{
+ if (! xml) return NULL;
+ if (xml->flags & EZXML_TXTM) free(xml->txt); // existing txt was malloced
+ xml->flags &= ~EZXML_TXTM;
+ xml->txt = (char *)txt;
+ return xml;
+}
+
+// Sets the given tag attribute or adds a new attribute if not found. A value
+// of NULL will remove the specified attribute. Returns the tag given.
+ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value)
+{
+ int l = 0, c;
+
+ if (! xml) return NULL;
+ while (xml->attr[l] && strcmp(xml->attr[l], name)) l += 2;
+ if (! xml->attr[l]) { // not found, add as new attribute
+ if (! value) return xml; // nothing to do
+ if (xml->attr == EZXML_NIL) { // first attribute
+ xml->attr = malloc(4 * sizeof(char *));
+ xml->attr[1] = strdup(""); // empty list of malloced names/vals
+ }
+ else xml->attr = realloc(xml->attr, (l + 4) * sizeof(char *));
+
+ xml->attr[l] = (char *)name; // set attribute name
+ xml->attr[l + 2] = NULL; // null terminate attribute list
+ xml->attr[l + 3] = realloc(xml->attr[l + 1],
+ (c = strlen(xml->attr[l + 1])) + 2);
+ strcpy(xml->attr[l + 3] + c, " "); // set name/value as not malloced
+ if (xml->flags & EZXML_DUP) xml->attr[l + 3][c] = EZXML_NAMEM;
+ }
+ else if (xml->flags & EZXML_DUP) free((char *)name); // name was strduped
+
+ for (c = l; xml->attr[c]; c += 2); // find end of attribute list
+ if (xml->attr[c + 1][l / 2] & EZXML_TXTM) free(xml->attr[l + 1]); //old val
+ if (xml->flags & EZXML_DUP) xml->attr[c + 1][l / 2] |= EZXML_TXTM;
+ else xml->attr[c + 1][l / 2] &= ~EZXML_TXTM;
+
+ if (value) xml->attr[l + 1] = (char *)value; // set attribute value
+ else { // remove attribute
+ if (xml->attr[c + 1][l / 2] & EZXML_NAMEM) free(xml->attr[l]);
+ memmove(xml->attr + l, xml->attr + l + 2, (c - l + 2) * sizeof(char*));
+ xml->attr = realloc(xml->attr, (c + 2) * sizeof(char *));
+ memmove(xml->attr[c + 1] + (l / 2), xml->attr[c + 1] + (l / 2) + 1,
+ (c / 2) - (l / 2)); // fix list of which name/vals are malloced
+ }
+ xml->flags &= ~EZXML_DUP; // clear strdup() flag
+ return xml;
+}
+
+// sets a flag for the given tag and returns the tag
+ezxml_t ezxml_set_flag(ezxml_t xml, short flag)
+{
+ if (xml) xml->flags |= flag;
+ return xml;
+}
+
+// removes a tag along with its subtags without freeing its memory
+ezxml_t ezxml_cut(ezxml_t xml)
+{
+ ezxml_t cur;
+
+ if (! xml) return NULL; // nothing to do
+ if (xml->next) xml->next->sibling = xml->sibling; // patch sibling list
+
+ if (xml->parent) { // not root tag
+ cur = xml->parent->child; // find head of subtag list
+ if (cur == xml) xml->parent->child = xml->ordered; // first subtag
+ else { // not first subtag
+ while (cur->ordered != xml) cur = cur->ordered;
+ cur->ordered = cur->ordered->ordered; // patch ordered list
+
+ cur = xml->parent->child; // go back to head of subtag list
+ if (strcmp(cur->name, xml->name)) { // not in first sibling list
+ while (strcmp(cur->sibling->name, xml->name))
+ cur = cur->sibling;
+ if (cur->sibling == xml) { // first of a sibling list
+ cur->sibling = (xml->next) ? xml->next
+ : cur->sibling->sibling;
+ }
+ else cur = cur->sibling; // not first of a sibling list
+ }
+
+ while (cur->next && cur->next != xml) cur = cur->next;
+ if (cur->next) cur->next = cur->next->next; // patch next list
+ }
+ }
+ xml->ordered = xml->sibling = xml->next = NULL;
+ return xml;
+}
+
+#ifdef EZXML_TEST // test harness
+int main(int argc, char **argv)
+{
+ ezxml_t xml;
+ char *s;
+ int i;
+
+ if (argc != 2) return fprintf(stderr, "usage: %s xmlfile\n", argv[0]);
+
+ xml = ezxml_parse_file(argv[1]);
+ printf("%s\n", (s = ezxml_toxml(xml)));
+ free(s);
+ i = fprintf(stderr, "%s", ezxml_error(xml));
+ ezxml_free(xml);
+ return (i) ? 1 : 0;
+}
+#endif // EZXML_TEST
--- /dev/null
+/* ezxml.h
+ *
+ * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _EZXML_H
+#define _EZXML_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EZXML_BUFSIZE 1024 // size of internal memory buffers
+#define EZXML_NAMEM 0x80 // name is malloced
+#define EZXML_TXTM 0x40 // txt is malloced
+#define EZXML_DUP 0x20 // attribute name and value are strduped
+
+typedef struct ezxml *ezxml_t;
+struct ezxml {
+ char *name; // tag name
+ char **attr; // tag attributes { name, value, name, value, ... NULL }
+ char *txt; // tag character content, empty string if none
+ size_t off; // tag offset from start of parent tag character content
+ ezxml_t next; // next tag with same name in this section at this depth
+ ezxml_t sibling; // next tag with different name in same section and depth
+ ezxml_t ordered; // next tag, same section and depth, in original order
+ ezxml_t child; // head of sub tag list, NULL if none
+ ezxml_t parent; // parent tag, NULL if current tag is root tag
+ short flags; // additional information
+};
+
+// Given a string of xml data and its length, parses it and creates an ezxml
+// structure. For efficiency, modifies the data by adding null terminators
+// and decoding ampersand sequences. If you don't want this, copy the data and
+// pass in the copy. Returns NULL on failure.
+ezxml_t ezxml_parse_str(char *s, size_t len);
+
+// A wrapper for ezxml_parse_str() that accepts a file descriptor. First
+// attempts to mem map the file. Failing that, reads the file into memory.
+// Returns NULL on failure.
+ezxml_t ezxml_parse_fd(int fd);
+
+// a wrapper for ezxml_parse_fd() that accepts a file name
+ezxml_t ezxml_parse_file(const char *file);
+
+// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire
+// stream into memory and then parses it. For xml files, use ezxml_parse_file()
+// or ezxml_parse_fd()
+ezxml_t ezxml_parse_fp(FILE *fp);
+
+// returns the first child tag (one level deeper) with the given name or NULL
+// if not found
+ezxml_t ezxml_child(ezxml_t xml, const char *name);
+
+// returns the next tag of the same name in the same section and depth or NULL
+// if not found
+#define ezxml_next(xml) ((xml) ? xml->next : NULL)
+
+// Returns the Nth tag with the same name in the same section at the same depth
+// or NULL if not found. An index of 0 returns the tag given.
+ezxml_t ezxml_idx(ezxml_t xml, int idx);
+
+// returns the name of the given tag
+#define ezxml_name(xml) ((xml) ? xml->name : NULL)
+
+// returns the given tag's character content or empty string if none
+#define ezxml_txt(xml) ((xml) ? xml->txt : "")
+
+// returns the value of the requested tag attribute, or NULL if not found
+const char *ezxml_attr(ezxml_t xml, const char *attr);
+
+// Traverses the ezxml sturcture to retrieve a specific subtag. Takes a
+// variable length list of tag names and indexes. The argument list must be
+// terminated by either an index of -1 or an empty string tag name. Example:
+// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1);
+// This retrieves the title of the 3rd book on the 1st shelf of library.
+// Returns NULL if not found.
+ezxml_t ezxml_get(ezxml_t xml, ...);
+
+// Converts an ezxml structure back to xml. Returns a string of xml data that
+// must be freed.
+char *ezxml_toxml(ezxml_t xml);
+
+// returns a NULL terminated array of processing instructions for the given
+// target
+const char **ezxml_pi(ezxml_t xml, const char *target);
+
+// frees the memory allocated for an ezxml structure
+void ezxml_free(ezxml_t xml);
+
+// returns parser error message or empty string if none
+const char *ezxml_error(ezxml_t xml);
+
+// returns a new empty ezxml structure with the given root tag name
+ezxml_t ezxml_new(const char *name);
+
+// wrapper for ezxml_new() that strdup()s name
+#define ezxml_new_d(name) ezxml_set_flag(ezxml_new(strdup(name)), EZXML_NAMEM)
+
+// Adds a child tag. off is the offset of the child tag relative to the start
+// of the parent tag's character content. Returns the child tag.
+ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off);
+
+// wrapper for ezxml_add_child() that strdup()s name
+#define ezxml_add_child_d(xml, name, off) \
+ ezxml_set_flag(ezxml_add_child(xml, strdup(name), off), EZXML_NAMEM)
+
+// sets the character content for the given tag and returns the tag
+ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt);
+
+// wrapper for ezxml_set_txt() that strdup()s txt
+#define ezxml_set_txt_d(xml, txt) \
+ ezxml_set_flag(ezxml_set_txt(xml, strdup(txt)), EZXML_TXTM)
+
+// Sets the given tag attribute or adds a new attribute if not found. A value
+// of NULL will remove the specified attribute. Returns the tag given.
+ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value);
+
+// Wrapper for ezxml_set_attr() that strdup()s name/value. Value cannot be NULL
+#define ezxml_set_attr_d(xml, name, value) \
+ ezxml_set_attr(ezxml_set_flag(xml, EZXML_DUP), strdup(name), strdup(value))
+
+// sets a flag for the given tag and returns the tag
+ezxml_t ezxml_set_flag(ezxml_t xml, short flag);
+
+// removes a tag along with its subtags without freeing its memory
+ezxml_t ezxml_cut(ezxml_t xml);
+
+// inserts an existing tag into an ezxml structure
+ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off);
+
+// Moves an existing tag to become a subtag of dest at the given offset from
+// the start of dest's character content. Returns the moved tag.
+#define ezxml_move(xml, dest, off) ezxml_insert(ezxml_cut(xml), dest, off)
+
+// removes a tag along with all its subtags
+#define ezxml_remove(xml) ezxml_free(ezxml_cut(xml))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _EZXML_H
--- /dev/null
+ezXML - XML Parsing C Library
+version 0.8.5
+
+ezXML is a C library for parsing XML documents inspired by simpleXML for PHP.
+As the name implies, it's easy to use. It's ideal for parsing XML configuration
+files or REST web service responses. It's also fast and lightweight (less than
+20k compiled). The latest verions is available here:
+http://prdownloads.sf.net/ezxml/ezxml-0.8.6.tar.gz?download
+
+Example Usage
+
+Given the following example XML document:
+
+<?xml version="1.0"?>
+<formula1>
+ <team name="McLaren">
+ <driver>
+ <name>Kimi Raikkonen</name>
+ <points>112</points>
+ </driver>
+ <driver>
+ <name>Juan Pablo Montoya</name>
+ <points>60</points>
+ </driver>
+ </team>
+</formula1>
+
+This code snippet prints out a list of drivers, which team they drive for,
+and how many championship points they have:
+
+ezxml_t f1 = ezxml_parse_file("formula1.xml"), team, driver;
+const char *teamname;
+
+for (team = ezxml_child(f1, "team"); team; team = team->next) {
+ teamname = ezxml_attr(team, "name");
+ for (driver = ezxml_child(team, "driver"); driver; driver = driver->next) {
+ printf("%s, %s: %s\n", ezxml_child(driver, "name")->txt, teamname,
+ ezxml_child(driver, "points")->txt);
+ }
+}
+ezxml_free(f1);
+
+Alternately, the following would print out the name of the second driver on the
+first team:
+
+ezxml_t f1 = ezxml_parse_file("formula1.xml");
+
+printf("%s\n", ezxml_get(f1, "team", 0, "driver", 1, "name", -1)->txt);
+ezxml_free(f1);
+
+The -1 indicates the end of the argument list. That's pretty much all
+there is to it. Complete API documentation can be found in ezxml.h.
+
+Known Limitations
+
+- ezXML is not a validating parser
+
+- Loads the entire XML document into memory at once and does not allow for
+ documents to be passed in a chunk at a time. Large XML files can still be
+ handled though through ezxml_parse_file() and ezxml_parse_fd(), which use mmap
+ to map the file to a virtual address space and rely on the virtual memory
+ system to page in data as needed.
+
+- Does not currently recognize all possible well-formedness errors. It should
+ correctly handle all well-formed XML documents and will either ignore or halt
+ XML processing on well-formedness errors. More well-formedness checking will
+ be added in subsiquent releases.
+
+- In making the character content of tags easy to access, there is no way
+ provided to keep track of the location of sub tags relative to the character
+ data. Example:
+
+ <doc>line one<br/>
+ line two</doc>
+
+ The character content of the doc tag is reported as "line one\nline two", and
+ <br/> is reported as a sub tag, but the location of <br/> within the
+ character data is not. The function ezxml_toxml() will convert an ezXML
+ structure back to XML with sub tag locations intact.
+
+Licensing
+
+ezXML was written by Aaron Voisine <aaron@voisine.org> and is distributed under
+the terms of the MIT license, described in license.txt.
--- /dev/null
+#include "ezxml.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define MAX_FILES 256
+
+struct file_info {
+ int size;
+ char id[256];
+ char * data;
+ unsigned long long * offset_ptr;
+};
+
+int num_files = 0;
+struct file_info files[MAX_FILES];
+
+
+int parse_config_input(ezxml_t cfg_input);
+int write_output(char * filename, ezxml_t cfg_output);
+
+void usage() {
+ printf("Usage: build_vm <infile> [-o outfile]\n");
+}
+
+int main(int argc, char ** argv) {
+ int c;
+ char * outfile = NULL;
+ char * infile = NULL;
+
+ memset((char *)files, 0, sizeof(files));
+
+ opterr = 0;
+
+ while ((c = getopt(argc, argv, "ho:")) != -1) {
+ switch (c) {
+ case 'o':
+ outfile = optarg;
+ break;
+ case 'h':
+ usage();
+ return 1;
+ default:
+ abort();
+ }
+ }
+
+ if (optind >= argc) {
+ usage();
+ return 1;
+ }
+
+ infile = argv[optind];
+
+
+ printf("Reading Input file: %s\n", infile);
+
+ ezxml_t cfg_input = ezxml_parse_file(infile);
+
+ if (cfg_input == NULL) {
+ printf("Could not open configuration input file: %s\n", infile);
+ return 1;
+ }
+
+
+
+
+ // parse input
+ if (parse_config_input(cfg_input) == -1) {
+ printf("Error parsing configuration input\n");
+ return 1;
+ }
+
+ printf("xml : %s\n", ezxml_toxml(cfg_input));
+
+
+
+ // write output
+
+ if (outfile == NULL) {
+ char * endptr = rindex(infile, '.');
+
+ outfile = malloc(strlen(infile) + strlen(".dat") + 1);
+
+ if (endptr) {
+ *endptr = '\0';
+ }
+
+ sprintf(outfile, "%s.dat", infile);
+ }
+
+
+ write_output(outfile, cfg_input);
+
+
+ return 0;
+}
+
+char * get_val(ezxml_t cfg, char * tag) {
+ char * attrib = (char *)ezxml_attr(cfg, tag);
+ ezxml_t txt = ezxml_child(cfg, tag);
+
+ if ((txt != NULL) && (attrib != NULL)) {
+ printf("Invalid Cfg file: Duplicate value for %s (attr=%s, txt=%s)\n",
+ tag, attrib, ezxml_txt(txt));
+ exit(-1);
+ }
+
+ return (attrib == NULL) ? ezxml_txt(txt) : attrib;
+}
+
+
+int write_output(char * filename, ezxml_t cfg_output) {
+ FILE * data_file = fopen(filename, "w+");
+ char * new_cfg_str = ezxml_toxml(cfg_output);
+ unsigned int cfg_len = strlen(new_cfg_str);
+ unsigned long long zero = 0;
+ int i = 0;
+ unsigned long long offset = 0;
+ unsigned long long file_cnt = num_files;
+
+ fwrite("v3vee\0\0\0", 8, 1, data_file);
+ offset += 8;
+
+ // printf("New config: \n%s\n", new_cfg_str);
+
+ fwrite(&cfg_len, sizeof(unsigned int), 1, data_file);
+ offset += sizeof(unsigned int);
+
+ fwrite(new_cfg_str, cfg_len, 1, data_file);
+ offset += cfg_len;
+
+ fwrite(&zero, 1, 8, data_file);
+ offset += 8;
+
+ printf("setting number of files to %llu\n", file_cnt);
+ printf("sizeof(file_cnt)=%d \n", sizeof(file_cnt));
+
+ fwrite(&file_cnt, 8, 1, data_file);
+ offset += 8;
+
+ // each index entry is 16 bytes long plus end padding
+ offset += (16 * num_files) + 8;
+
+ for (i = 0; i < num_files; i++) {
+ fwrite(&i, 4, 1, data_file);
+ fwrite(&(files[i].size), 4, 1, data_file);
+ fwrite(&offset, 8, 1, data_file);
+
+ offset += files[i].size;
+ }
+
+ fwrite(&zero, 1, 8, data_file);
+
+ for (i = 0; i < num_files; i++) {
+ if (fwrite(files[i].data, 1, files[i].size, data_file) != files[i].size) {
+ printf("Error writing data file contents");
+ exit(-1);
+ }
+ }
+
+
+
+ fclose(data_file);
+
+ return 0;
+}
+
+
+
+int parse_config_input(ezxml_t cfg_input) {
+ ezxml_t file_tags = NULL;
+ ezxml_t tmp_file_tag = NULL;
+
+ // files are transformed into blobs that are slapped to the end of the file
+
+ file_tags = ezxml_child(cfg_input, "files");
+
+ tmp_file_tag = ezxml_child(file_tags, "file");
+
+ while (tmp_file_tag) {
+ char * filename = get_val(tmp_file_tag, "filename");
+ struct stat file_stats;
+ FILE * data_file = NULL;
+ char * id = get_val(tmp_file_tag, "id");
+ char index_buf[256];
+
+ snprintf(index_buf, 256, "%d", num_files);
+
+
+ strncpy(files[num_files].id, ezxml_attr(tmp_file_tag, "id"), 256);
+
+ printf("file id=%s, name=%s\n",
+ id,
+ filename);
+
+
+ if (stat(filename, &file_stats) != 0) {
+ perror(filename);
+ exit(-1);
+ }
+
+ files[num_files].size = (unsigned int)file_stats.st_size;
+ printf("file size = %d\n", files[num_files].size);
+
+ files[num_files].data = malloc(files[num_files].size);
+
+ data_file = fopen(filename, "r");
+
+ if (fread(files[num_files].data, files[num_files].size, 1, data_file) == 0) {
+ printf("Error reading data file %s\n", filename);
+ exit(-1);
+ }
+
+ fclose(data_file);
+
+
+ ezxml_set_attr_d(tmp_file_tag, "index", index_buf);
+
+ num_files++;
+ tmp_file_tag = ezxml_next(tmp_file_tag);
+ }
+
+
+ return 0;
+}
--- /dev/null
+v3vee\0\0\0 : 8 bytes
+<length of xml> : 4 bytes
+<xml> : xml configuration string
+<zero's> : 8 bytes of zeroes
+
+<num files> : 8 bytes
+
+<index> : 4 bytes
+<size> : 4 bytes
+<offset> : 8 bytes
+... other files ...
+
+<zero's> : 8 bytes of zeroes
+
+<file> : raw file data
+
+... other raw file data ...
+++ /dev/null
---- Makefile.in 2005-01-14 17:05:31.000000000 -0600
-+++ ../Makefile.in 2008-01-08 18:57:47.861088072 -0600
-@@ -20,7 +20,7 @@
- LIBS = @LIBS@
- PERL = perl
-
--INSTALL = @INSTALL@
-+INSTALL = @INSTALL@ -D
- INSTALL_PROGRAM = @INSTALL_PROGRAM@
- INSTALL_DATA = @INSTALL_DATA@
-
+++ /dev/null
-Index: insns.dat
-===================================================================
-RCS file: /home/jarusl/nasm-0.98.39-vmx/insns.dat
-retrieving revision 1.46
-diff -u -p -w -r1.46 insns.dat
---- insns.dat 2 Sep 2003 21:38:48 -0000 1.46
-+++ insns.dat 28 Feb 2006 00:43:59 -0000
-@@ -1673,3 +1673,17 @@ MOVSHDUP xmmreg,mem \301\3\xF3\x0F\x16\
- MOVSHDUP xmmreg,xmmreg \3\xF3\x0F\x16\110 PRESCOTT,SSE3
- MOVSLDUP xmmreg,mem \301\3\xF3\x0F\x12\110 PRESCOTT,SSE3
- MOVSLDUP xmmreg,xmmreg \3\xF3\x0F\x12\110 PRESCOTT,SSE3
-+
-+; VMX Instructions
-+VMCALL void \3\x0F\x01\xC1 VMX
-+VMCLEAR mem \3\x66\x0F\xC7\206 VMX
-+VMLAUNCH void \3\x0F\x01\xC2 VMX
-+VMPTRLD mem \2\x0F\xC7\206 VMX
-+VMPTRST mem \2\x0F\xC7\207 VMX
-+VMREAD mem,reg32 \2\x0F\x78\101 VMX
-+VMREAD reg32,reg32 \2\x0F\x78\101 VMX
-+VMRESUME void \3\x0F\x01\xC3 VMX
-+VMWRITE reg32,mem \2\x0F\x79\110 VMX
-+VMWRITE reg32,reg32 \2\x0F\x79\110 VMX
-+VMXOFF void \3\x0F\x01\xC4 VMX
-+VMXON mem \3\xF3\x0F\xC7\206 VMX
-Index: insns.h
-===================================================================
-RCS file: /home/jarusl/nasm-0.98.39-vmx/insns.h
-retrieving revision 1.31
-diff -u -p -w -r1.31 insns.h
---- insns.h 15 Jan 2005 22:15:51 -0000 1.31
-+++ insns.h 28 Feb 2006 00:43:59 -0000
-@@ -78,6 +78,7 @@ struct itemplate {
- #define IF_SSE 0x00010000UL /* it's a SSE (KNI, MMX2) instruction */
- #define IF_SSE2 0x00020000UL /* it's a SSE2 instruction */
- #define IF_SSE3 0x00040000UL /* it's a SSE3 (PNI) instruction */
-+#define IF_VMX 0x00080000UL /* it's a VMX instruction */
- #define IF_PMASK 0xFF000000UL /* the mask for processor types */
- #define IF_PLEVEL 0x0F000000UL /* the mask for processor instr. level */
- /* also the highest possible processor */
-