Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio...
Lei Xia [Fri, 18 Feb 2011 01:04:52 +0000 (19:04 -0600)]
12 files changed:
Kconfig
palacios/include/palacios/vmm_time.h
palacios/include/palacios/vmm_xml.h
palacios/src/devices/8254.c
palacios/src/devices/Kconfig
palacios/src/devices/apic.c
palacios/src/devices/cirrus_gfx_card.c
palacios/src/devices/io_apic.c
palacios/src/palacios/svm.c
palacios/src/palacios/vmm_time.c
palacios/src/palacios/vmm_xml.c
test/geekos_test_vm/build/depend.mak [deleted file]

diff --git a/Kconfig b/Kconfig
index dcee752..0eb9692 100644 (file)
--- a/Kconfig
+++ b/Kconfig
@@ -226,14 +226,40 @@ endmenu
 
 menu "Time Management"
 
+config TIME_HIDE_VM_COST
+        bool "Hide VMM Run Cost"
+       default n
+       help
+           Offset guest time from host time sufficiently to hide the cost of
+           running in the virtual machine. This can aid the consistency of
+           time between multiple timers, but can cause the guest to run 
+           slightly slower than the host.
+
+config TIME_HIDE_EXIT_COST
+        bool "Hide VMM Exit Cost"
+       default n
+       depends on TIME_HIDE_VM_COST
+       help
+           Add additional TSC offset to hide VMM exit costs from the guest.
+
+config TIME_EXIT_COST_ADJUST
+       int "Exit cost adjustment for hiding VM exits"
+       default 2000
+       depends on TIME_HIDE_EXIT_COST
+       help
+           Amount to adjust the time to hide the exit cost of fully virtualizing
+          the timestamp counter. Used to hide the cost of fully virtualizing 
+          the TSC for OSes that assume that reading the TSC is inexpensive 
+          (e.g. Linux TSC-based timer calibration).
+
 config TIME_VIRTUALIZE_TSC
-       bool "Virtualize guest TSC"
+       bool "Fully virtualize guest TSC"
        default n
        help
            Virtualize the processor time stamp counter in the guest, 
            generally increasing consistency between various time sources 
            but also potentially making guest time run slower than real time.
-
+        
 endmenu
 
 menu "Symbiotic Functions"
index 9f1c432..6513e30 100644 (file)
@@ -7,11 +7,13 @@
  * and the University of New Mexico.  You can find out more at 
  * http://www.v3vee.org
  *
+ * Copyright (c) 2010, Patrick Bridges <bridges@cs.unm.edu>
  * 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>
+ *         Patrick Bridges <bridges@cs.unm.edu>
  *
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
@@ -32,15 +34,15 @@ struct guest_info;
 struct vm_time {
     uint32_t host_cpu_freq;    // in kHZ 
     uint32_t guest_cpu_freq;   // can be lower than host CPU freq!
-         
+
     sint64_t guest_host_offset;// Offset of monotonic guest time from host time
     sint64_t tsc_guest_offset; // Offset of guest TSC from monotonic guest time
-    
+
     uint64_t last_update;      // Last time (in monotonic guest time) the 
                                // timers were updated
 
     uint64_t initial_time;     // Time when VMM started. 
-    
+    uint64_t pause_time;       // Host time when VM entered and paused.
     struct v3_msr tsc_aux;     // Auxilliary MSR for RDTSCP
 
     // Installed Timers slaved off of the guest monotonic TSC
@@ -67,9 +69,12 @@ int v3_init_time_vm(struct v3_vm_info * vm);
 void v3_deinit_time_core(struct guest_info * core);
 void v3_deinit_time_vm(struct v3_vm_info * vm);
 
-
 int v3_start_time(struct guest_info * core);
+
 int v3_adjust_time(struct guest_info * core);
+int v3_pause_time(struct guest_info * core);
+int v3_offset_time(struct guest_info * core, sint64_t offset);
+int v3_restart_time(struct guest_info * core);
 
 // Basic functions for attaching timers to the passage of time
 struct v3_timer * v3_add_timer(struct guest_info * info, struct v3_timer_ops * ops, void * private_data);
@@ -85,7 +90,11 @@ static inline uint64_t v3_get_host_time(struct vm_time *t) {
 
 // Returns *monotonic* guest time.
 static inline uint64_t v3_get_guest_time(struct vm_time *t) {
-    return v3_get_host_time(t) + t->guest_host_offset;
+    if (t->pause_time) {
+        return t->pause_time + t->guest_host_offset;
+    } else {
+        return v3_get_host_time(t) + t->guest_host_offset;
+    }
 }
 
 // Returns the TSC value seen by the guest
index f45f804..680c41a 100644 (file)
@@ -76,6 +76,8 @@ struct v3_xml * v3_xml_idx(struct v3_xml * xml, int idx);
 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: 
@@ -88,4 +90,18 @@ 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);
     
+
+
+
+
+
+char * v3_xml_tostr(struct v3_xml * xml);
+
+struct v3_xml * v3_xml_insert(struct v3_xml * xml, struct v3_xml * dest, size_t off) 
+struct v3_xml *  v3_xml_set_txt(struct v3_xml * xml, const char *txt);
+
+
+struct v3_xml * v3_xml_set_attr(struct v3_xml * xml, const char * name, const char * value);
+
+
 #endif // __VMM_XML_H
index 7bf6a8c..ffae665 100644 (file)
@@ -299,10 +299,13 @@ static void pit_update_timer(struct guest_info * info, ullong_t cpu_cycles, ullo
        // update counter with remainder (mod reload)
        state->pit_counter = state->pit_reload - cpu_cycles;    
 
-       //PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
+       if (oscillations) {
+           PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
+       }
+
        if (handle_crystal_tics(state, &(state->ch_0), oscillations) == 1) {
            // raise interrupt
-           PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
+           // PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
            v3_raise_irq(info->vm_info, 0);
        }
 
index b4bccb7..873792d 100644 (file)
@@ -3,7 +3,6 @@ menu "Virtual Devices"
 config APIC
        bool "APIC" 
        default y
-       depends on EXPERIMENTAL
        help 
          Includes the Virtual APIC device
 
@@ -19,7 +18,6 @@ config DEBUG_APIC
 
 config IO_APIC
        bool "IOAPIC"
-       depends on EXPERIMENTAL
        default y
        help 
          Includes the Virtual IO APIC
index 1872bb3..4387480 100644 (file)
@@ -11,7 +11,8 @@
  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
  * All rights reserved.
  *
- * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ * Authors: Jack Lange <jarusl@cs.northwestern.edu>
+ *          Peter Dinda <pdinda@northwestern.edu> (SMP)
  *
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
 #include <palacios/vmm_types.h>
 
 
+//
+//   MUST DO APIC SCAN FOR PHYSICAL DELIVERY
+//
+
+
+
 #ifndef CONFIG_DEBUG_APIC
 #undef PrintDebug
 #define PrintDebug(fmt, args...)
 #endif
 
-#ifdef CONFIG_DEBUG_APIC
 static char * shorthand_str[] = { 
     "(no shorthand)",
     "(self)",
@@ -50,17 +56,34 @@ static char * deliverymode_str[] = {
     "(Start Up)",
     "(ExtInt)",
 };
+#ifdef CONFIG_DEBUG_APIC
 #endif
 
+
+#define v3_lock(p) p=p
+#define v3_unlock(p) p=p
+
+
 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
               APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
 
 #define APIC_FIXED_DELIVERY  0x0
+#define APIC_LOWEST_DELIVERY 0x1
 #define APIC_SMI_DELIVERY    0x2
+#define APIC_RES1_DELIVERY   0x3
 #define APIC_NMI_DELIVERY    0x4
 #define APIC_INIT_DELIVERY   0x5
+#define APIC_SIPI_DELIVERY   0x6
 #define APIC_EXTINT_DELIVERY 0x7
 
+#define APIC_SHORTHAND_NONE        0x0
+#define APIC_SHORTHAND_SELF        0x1
+#define APIC_SHORTHAND_ALL         0x2
+#define APIC_SHORTHAND_ALL_BUT_ME  0x3
+
+#define APIC_DEST_PHYSICAL    0x0
+#define APIC_DEST_LOGICAL     0x1
+
 
 #define BASE_ADDR_MSR     0x0000001B
 #define DEFAULT_BASE_ADDR 0xfee00000
@@ -214,6 +237,9 @@ struct apic_state {
     uint32_t eoi;
 
     v3_lock_t  lock;
+
+    // debug
+    uint8_t in_icr;   
 };
 
 
@@ -221,6 +247,7 @@ struct apic_state {
 
 struct apic_dev_state {
     int num_apics;
+    //    v3_lock_t ipi_lock;   // acquired by route_ipi - only one IPI active at a time
 
     struct apic_state apics[0];
 } __attribute__((packed));
@@ -232,6 +259,7 @@ struct apic_dev_state {
 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
 
+// No lcoking done
 static void init_apic_state(struct apic_state * apic, uint32_t id) {
     apic->base_addr = DEFAULT_BASE_ADDR;
 
@@ -289,11 +317,15 @@ static void init_apic_state(struct apic_state * apic, uint32_t id) {
     apic->spec_eoi.val = 0x00000000;
 
     v3_lock_init(&(apic->lock));
+
+    //debug
+    apic->in_icr=0;
 }
 
 
 
 
+// MSR handler - locks apic itself
 static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data;
     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
@@ -305,7 +337,7 @@ static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, v
     return 0;
 }
 
-
+// MSR handler - locks apic itself
 static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data;
     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
@@ -342,7 +374,12 @@ static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, vo
 
 
 // irq_num is the bit offset into a 256 bit buffer...
-static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
+// return values
+//    -1 = error
+//     0 = OK, no interrupt needed now
+//     1 = OK, interrupt needed now
+// the caller is expeced to have locked the apic
+static int activate_apic_irq_nolock(struct apic_state * apic, uint32_t irq_num) {
     int major_offset = (irq_num & ~0x00000007) >> 3;
     int minor_offset = irq_num & 0x00000007;
     uint8_t * req_location = apic->int_req_reg + major_offset;
@@ -350,8 +387,7 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
     uint8_t flag = 0x1 << minor_offset;
 
 
-
-    if (irq_num <= 15) {
+    if (irq_num <= 15 || irq_num>255) {
        PrintError("apic %u: core %d: Attempting to raise an invalid interrupt: %d\n", 
                   apic->lapic_id.val, apic->core->cpu_id, irq_num);
        return -1;
@@ -362,21 +398,28 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
 
     if (*req_location & flag) {
        PrintDebug("Interrupt %d  coallescing\n", irq_num);
+       return 0;
     }
 
     if (*en_location & flag) {
        *req_location |= flag;
+
+       if (apic->in_icr) { 
+           PrintError("apic %u: core %d: activate_apic_irq_nolock to deliver irq 0x%x when in_icr=1\n",  apic->lapic_id.val, apic->core->cpu_id, irq_num);
+           //      return 0;
+       }
+
+       return 1;
     } else {
        PrintDebug("apic %u: core %d: Interrupt  not enabled... %.2x\n", 
                   apic->lapic_id.val, apic->core->cpu_id,*en_location);
        return 0;
     }
 
-    return 0;
 }
 
 
-
+// Caller is expected to have locked the apic
 static int get_highest_isr(struct apic_state * apic) {
     int i = 0, j = 0;
 
@@ -398,7 +441,7 @@ static int get_highest_isr(struct apic_state * apic) {
 }
  
 
-
+// Caller is expected to have locked the apic
 static int get_highest_irr(struct apic_state * apic) {
     int i = 0, j = 0;
 
@@ -421,7 +464,7 @@ static int get_highest_irr(struct apic_state * apic) {
  
 
 
-
+// Caller is expected to have locked the apic
 static int apic_do_eoi(struct apic_state * apic) {
     int isr_irq = get_highest_isr(apic);
 
@@ -453,8 +496,8 @@ static int apic_do_eoi(struct apic_state * apic) {
     return 0;
 }
  
-
-static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
+// Caller is expected to have locked the apic
+static int activate_internal_irq_nolock(struct apic_state * apic, apic_irq_type_t int_type) {
     uint32_t vec_num = 0;
     uint32_t del_mode = 0;
     int masked = 0;
@@ -504,7 +547,7 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
 
     if (del_mode == APIC_FIXED_DELIVERY) {
        //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
-       return activate_apic_irq(apic, vec_num);
+       return activate_apic_irq_nolock(apic, vec_num);
     } else {
        PrintError("apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.val);
        return -1;
@@ -512,12 +555,12 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
 }
 
 
-
+// Caller is expected to have locked the destination apic
 static inline int should_deliver_cluster_ipi(struct guest_info * dst_core, 
                                             struct apic_state * dst_apic, uint8_t mda) {
 
-    if         ( ((mda & 0xf0) == (dst_apic->log_dst.dst_log_id & 0xf0)) &&     // (I am in the cluster and
-         ((mda & 0x0f) & (dst_apic->log_dst.dst_log_id & 0x0f)) ) {  //  I am in the set)
+    if         ( ((mda & 0xf0) == (dst_apic->log_dst.dst_log_id & 0xf0)) &&  /* (I am in the cluster and */
+         ((mda & 0x0f) & (dst_apic->log_dst.dst_log_id & 0x0f)) ) {  /*  I am in the set)        */
 
        PrintDebug("apic %u core %u: accepting clustered IRQ (mda 0x%x == log_dst 0x%x)\n",
                   dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
@@ -532,6 +575,7 @@ static inline int should_deliver_cluster_ipi(struct guest_info * dst_core,
     }
 }
 
+// Caller is expected to have locked the destiation apic
 static inline int should_deliver_flat_ipi(struct guest_info * dst_core,
                                          struct apic_state * dst_apic, uint8_t mda) {
 
@@ -540,17 +584,20 @@ static inline int should_deliver_flat_ipi(struct guest_info * dst_core,
        PrintDebug("apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n",
                   dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
                   dst_apic->log_dst.dst_log_id);
-      return 1;
+
+       return 1;
+
   } else {
+
        PrintDebug("apic %u core %u: rejecting flat IRQ (mda 0x%x != log_dst 0x%x)\n",
                   dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
                   dst_apic->log_dst.dst_log_id);
-      return 0;
+       return 0;
   }
 }
 
 
-
+// Caller is expected to have locked the destiation apic
 static int should_deliver_ipi(struct guest_info * dst_core, 
                              struct apic_state * dst_apic, uint8_t mda) {
 
@@ -558,19 +605,21 @@ static int should_deliver_ipi(struct guest_info * dst_core,
     if (dst_apic->dst_fmt.model == 0xf) {
 
        if (mda == 0xff) {
-           // always deliver broadcast
+           /* always deliver broadcast */
            return 1;
        }
 
        return should_deliver_flat_ipi(dst_core, dst_apic, mda);
+
     } else if (dst_apic->dst_fmt.model == 0x0) {
 
        if (mda == 0xff) {
-           // always deliver broadcast
+           /*  always deliver broadcast */
            return 1;
        }
 
        return should_deliver_cluster_ipi(dst_core, dst_apic, mda);
+
     } else {
        PrintError("apic %u core %u: invalid destination format register value 0x%x for logical mode delivery.\n", 
                   dst_apic->lapic_id.val, dst_core->cpu_id, dst_apic->dst_fmt.model);
@@ -578,28 +627,39 @@ static int should_deliver_ipi(struct guest_info * dst_core,
     }
 }
 
-
+// Caller is expected to have locked the destination apic
+// Only the src_apic pointer is used
 static int deliver_ipi(struct apic_state * src_apic, 
                       struct apic_state * dst_apic, 
                       uint32_t vector, uint8_t del_mode) {
 
+
     struct guest_info * dst_core = dst_apic->core;
+    int do_xcall;
 
     switch (del_mode) {
 
-       case 0:  //fixed
-       case 1: // lowest priority
+       case APIC_FIXED_DELIVERY:  
+       case APIC_LOWEST_DELIVERY:
+           // lowest priority - 
+           // caller needs to have decided which apic to deliver to!
+
            PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->cpu_id); 
 
-           activate_apic_irq(dst_apic, vector);
+           do_xcall=activate_apic_irq_nolock(dst_apic, vector);
+           
+           if (do_xcall<0) { 
+               PrintError("Failed to activate apic irq!\n");
+               return -1;
+           }
 
-           if (dst_apic != src_apic) { 
+           if (do_xcall && (dst_apic != src_apic)) { 
                // Assume core # is same as logical processor for now
                // TODO FIX THIS FIX THIS
                // THERE SHOULD BE:  guestapicid->virtualapicid map,
                //                   cpu_id->logical processor map
                //     host maitains logical proc->phsysical proc
-               PrintDebug(" non-local core, forcing it to exit\n"); 
+               PrintDebug(" non-local core with new interrupt, forcing it to exit now\n"); 
 
 #ifdef CONFIG_MULTITHREAD_OS
                v3_interrupt_cpu(dst_core->vm_info, dst_core->cpu_id, 0);
@@ -609,7 +669,8 @@ static int deliver_ipi(struct apic_state * src_apic,
            }
 
            break;
-       case 5: { //INIT
+
+       case APIC_INIT_DELIVERY: { 
 
            PrintDebug(" INIT delivery to core %u\n", dst_core->cpu_id);
 
@@ -617,7 +678,7 @@ static int deliver_ipi(struct apic_state * src_apic,
 
            // Sanity check
            if (dst_apic->ipi_state != INIT_ST) { 
-               PrintError(" Warning: core %u is not in INIT state (mode = %d), ignored\n",
+               PrintError(" Warning: core %u is not in INIT state (mode = %d), ignored (assuming this is the deassert)\n",
                           dst_core->cpu_id, dst_apic->ipi_state);
                // Only a warning, since INIT INIT SIPI is common
                break;
@@ -636,7 +697,7 @@ static int deliver_ipi(struct apic_state * src_apic,
 
            break;                                                      
        }
-       case 6: { //SIPI
+       case APIC_SIPI_DELIVERY: { 
 
            // Sanity check
            if (dst_apic->ipi_state != SIPI) { 
@@ -674,10 +735,10 @@ static int deliver_ipi(struct apic_state * src_apic,
 
            break;                                                      
        }
-       case 2: // SMI                  
-       case 3: // reserved                                             
-       case 4: // NMI                                  
-       case 7: // ExtInt
+       case APIC_SMI_DELIVERY: 
+       case APIC_RES1_DELIVERY: // reserved                                            
+       case APIC_NMI_DELIVERY:
+       case APIC_EXTINT_DELIVERY: // ExtInt
        default:
            PrintError("IPI %d delivery is unsupported\n", del_mode); 
            return -1;
@@ -687,119 +748,252 @@ static int deliver_ipi(struct apic_state * src_apic,
 
 }
 
-
+// route_ipi is responsible for all locking
+// the assumption is that you enter with no locks
+// there is a global lock for the icc bus, so only
+// one route_ipi progresses at any time
+// destination apics are locked as needed
+// if multiple apic locks are acquired at any point,
+// this is done in the order of the array, so no
+// deadlock should be possible
 static int route_ipi(struct apic_dev_state * apic_dev,
                     struct apic_state * src_apic, 
                     struct int_cmd_reg * icr) {
     struct apic_state * dest_apic = NULL;
 
-    PrintDebug("route_ipi: src_apic=%p, icr_data=%p\n", 
-              src_apic, (void *)(addr_t)icr->val);
-
-
-    if ((icr->dst_mode == 0) && (icr->dst >= apic_dev->num_apics)) { 
-       PrintError("route_ipi: Attempted send to unregistered apic id=%u\n", 
-                  icr->dst);
-       return -1;
-    }
 
-    dest_apic =  &(apic_dev->apics[icr->dst]);
+    //v3_lock(apic_dev->ipi_lock);  // this may not be needed
+    // now I know only one IPI is being routed, this one
+    // also, I do not have any apic locks
+    // I need to acquire locks on pairs of src/dest apics
+    // and I will do that using the total order
+    // given by their cores
 
 
-    PrintDebug("route_ipi: IPI %s %u from apic %p to %s %s %u (icr=0x%llx) (destapic=%p\n",
+    PrintDebug("apic: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n",
               deliverymode_str[icr->del_mode], 
               icr->vec, 
               src_apic,               
               (icr->dst_mode == 0) ? "(physical)" : "(logical)", 
               shorthand_str[icr->dst_shorthand], 
               icr->dst,
-              icr->val,
-              dest_apic);
+              icr->val);
+
+#if 1
+        if (icr->vec!=48) { 
+           V3_Print("apic: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n",
+                   deliverymode_str[icr->del_mode], 
+                   icr->vec, 
+                   src_apic,          
+                   (icr->dst_mode == 0) ? "(physical)" : "(logical)", 
+                   shorthand_str[icr->dst_shorthand], 
+                   icr->dst,
+                   icr->val);
+       }
+
+#endif
+
 
     switch (icr->dst_shorthand) {
 
-       case 0:  // no shorthand
-           if (icr->dst_mode == 0) { 
-               // physical delivery
+       case APIC_SHORTHAND_NONE:  // no shorthand
+           if (icr->dst_mode == APIC_DEST_PHYSICAL) { 
+
+               if (icr->dst >= apic_dev->num_apics) { 
+                   PrintError("apic: Attempted send to unregistered apic id=%u\n", icr->dst);
+                   goto route_ipi_out_bad;
+               }
+
+
+               dest_apic =  &(apic_dev->apics[icr->dst]);
+               
+               V3_Print("apic: phsyical destination of %u (apic %u at 0x%p)\n", icr->dst,dest_apic->lapic_id.val,dest_apic);
+
+               v3_lock(dest_apic->lock);
 
                if (deliver_ipi(src_apic, dest_apic, 
                                icr->vec, icr->del_mode) == -1) {
-                   PrintError("Error: Could not deliver IPI\n");
-                   return -1;
+                   PrintError("apic: Could not deliver IPI\n");
+                   v3_unlock(dest_apic->lock);
+                   goto route_ipi_out_bad;
                }
 
-           } else {
-               // logical delivery
-               int i;
-               uint8_t mda = icr->dst;
-               for (i = 0; i < apic_dev->num_apics; i++) { 
-                    dest_apic = &(apic_dev->apics[i]);
-                    int del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
-                    
-                    if (del_flag == -1) {
-                        PrintError("Error checking delivery mode\n");
-                        return -1;
-                    } else if (del_flag == 1) {
-                       if (deliver_ipi(src_apic, dest_apic, 
+               v3_unlock(dest_apic->lock);
+
+               V3_Print("apic: done\n");
+
+           } else if (icr->dst_mode == APIC_DEST_LOGICAL) {
+               
+               if (icr->del_mode!=APIC_LOWEST_DELIVERY ) { 
+                   // logical, but not lowest priority
+                   // we immediately trigger
+                   // fixed, smi, reserved, nmi, init, sipi, etc
+                   int i;
+                   
+                   uint8_t mda = icr->dst;
+                   
+                   for (i = 0; i < apic_dev->num_apics; i++) { 
+                       
+                       dest_apic = &(apic_dev->apics[i]);
+                       
+                       v3_lock(dest_apic->lock);
+                       
+                       int del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
+                       
+                       if (del_flag == -1) {
+                           PrintError("apic: Error checking delivery mode\n");
+                           v3_unlock(dest_apic->lock);
+                           goto route_ipi_out_bad;
+                       } else if (del_flag == 1) {
+                           if (deliver_ipi(src_apic, dest_apic, 
+                                           icr->vec, icr->del_mode) == -1) {
+                               PrintError("apic: Error: Could not deliver IPI\n");
+                               v3_unlock(dest_apic->lock);
+                               goto route_ipi_out_bad;
+                           }
+                       }
+                       
+                       v3_unlock(dest_apic->lock);
+                   }
+               } else {  //APIC_LOWEST_DELIVERY
+                   // logical, lowest priority
+                   // scan, keeping a lock on the current best, then trigger
+                   int i;
+                   int have_cur_lock;
+                   struct apic_state * cur_best_apic = NULL;
+                   
+                   uint8_t mda = icr->dst;
+                   
+                   have_cur_lock=0;
+
+
+                   // Note that even if there are multiple concurrent 
+                   // copies of this loop executing, they are all 
+                   // locking in the same order
+
+                   for (i = 0; i < apic_dev->num_apics; i++) { 
+                       
+                       dest_apic = &(apic_dev->apics[i]);
+                       
+                       v3_lock(dest_apic->lock);
+                       have_cur_lock=1;
+                       
+                       int del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
+                       
+                       if (del_flag == -1) {
+                           PrintError("apic: Error checking delivery mode\n");
+                           v3_unlock(dest_apic->lock);
+                           if (cur_best_apic && cur_best_apic!=dest_apic) { 
+                               v3_unlock(cur_best_apic->lock);
+                           }
+                           goto route_ipi_out_bad;
+                       } else if (del_flag == 1) {
+                           // update priority for lowest priority scan
+                           if (!cur_best_apic) {
+                               cur_best_apic=dest_apic;  // note we leave it locked
+                               have_cur_lock=0;          // we will unlock as cur_best_apic
+                           } else if (dest_apic->task_prio.val < cur_best_apic->task_prio.val) {
+                               // we now unlock the current best one and then switch
+                               // so in the end we have a lock on the new cur_best_apic
+                               v3_unlock(cur_best_apic->lock);
+                               cur_best_apic=dest_apic;
+                               have_cur_lock=0; // will unlock as cur_best_apic
+                           } 
+                       }
+                       if (have_cur_lock) {
+                           v3_unlock(dest_apic->lock);
+                       }
+                       
+                   }
+                   // now we will deliver to the best one if it exists
+                   // and it is locked
+                   if (!cur_best_apic) { 
+                       PrintDebug("apic: lowest priority deliver, but no destinations!\n");
+                   } else {
+                       if (deliver_ipi(src_apic, cur_best_apic, 
                                        icr->vec, icr->del_mode) == -1) {
-                           PrintError("Error: Could not deliver IPI\n");
-                           return -1;
+                           PrintError("apic: Error: Could not deliver IPI\n");
+                           v3_unlock(cur_best_apic->lock);
+                           goto route_ipi_out_bad;
+                       } else {
+                           v3_unlock(cur_best_apic->lock);
                        }
+                           //V3_Print("apic: logical, lowest priority delivery to apic %u\n",cur_best_apic->lapic_id.val);
                    }
                }
            }
-           
+
            break;
            
-       case 1:  // self
+       case APIC_SHORTHAND_SELF:  // self
 
-           if (src_apic == NULL) {
-               PrintError("Sending IPI to self from generic IPI sender\n");
+           /* I assume I am already locked! */
+
+           if (src_apic == NULL) {    /* this is not an apic, but it's trying to send to itself??? */
+               PrintError("apic: Sending IPI to self from generic IPI sender\n");
                break;
            }
 
-           if (icr->dst_mode == 0) { 
+           v3_lock(src_apic->lock);
+
+           if (icr->dst_mode == APIC_DEST_PHYSICAL)  {  /* physical delivery */
                if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
-                   PrintError("Could not deliver IPI\n");
-                   return -1;
+                   PrintError("apic: Could not deliver IPI to self (physical)\n");
+                   v3_unlock(src_apic->lock);
+                   goto route_ipi_out_bad;
+               }
+           } else if (icr->dst_mode == APIC_DEST_LOGICAL) {  /* logical delivery */
+               PrintError("apic: use of logical delivery in self (untested)\n");
+               if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
+                   PrintError("apic: Could not deliver IPI to self (logical)\n");
+                   v3_unlock(src_apic->lock);
+                   goto route_ipi_out_bad;
                }
-           } else {
-               // logical delivery
-               PrintError("use of logical delivery in self is not yet supported.\n");
-               return -1;
            }
+           v3_unlock(src_apic->lock);
            break;
            
-       case 2: 
-       case 3: { // all and all-but-me
-           // assuming that logical verus physical doesn't matter
-           // although it is odd that both are used
+       case APIC_SHORTHAND_ALL: 
+       case APIC_SHORTHAND_ALL_BUT_ME: { /* all and all-but-me */
+           /* assuming that logical verus physical doesn't matter
+              although it is odd that both are used */
+
            int i;
 
            for (i = 0; i < apic_dev->num_apics; i++) { 
                dest_apic = &(apic_dev->apics[i]);
-
-               if ((dest_apic != src_apic) || (icr->dst_shorthand == 2)) { 
+               
+               
+               if ((dest_apic != src_apic) || (icr->dst_shorthand == APIC_SHORTHAND_ALL)) { 
+                   v3_lock(dest_apic->lock);
                    if (deliver_ipi(src_apic, dest_apic, icr->vec, icr->del_mode) == -1) {
-                       PrintError("Error: Could not deliver IPI\n");
-                       return -1;
+                       PrintError("apic: Error: Could not deliver IPI\n");
+                       v3_unlock(dest_apic->lock);
+                       goto route_ipi_out_bad;
                    }
+                   v3_unlock(dest_apic->lock);
                }
-           }   
-
-           break;
+               
+           }
        }
+           break;
        default:
-           PrintError("Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand);
-           return -1;
+           PrintError("apic: Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand);
+           goto route_ipi_out_bad;
     }
-    
 
+
+    // route_ipi_out_good:
+    //v3_unlock(apic_dev->ipi_lock);  
     return 0;
-}
 
+ route_ipi_out_bad:
+    //v3_unlock(apic_dev->ipi_lock);  
+    return -1;
+}
 
 
+// External function, expected to acquire lock on apic
 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
@@ -807,6 +1001,7 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui
     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
     uint32_t val = 0;
 
+    v3_lock(apic->lock);
 
     PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",
               apic->lapic_id.val, core->cpu_id, apic, (void *)guest_addr);
@@ -815,7 +1010,7 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui
        PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",
                   apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
 
-       return -1;
+       goto apic_read_out_bad;
     }
 
 
@@ -1028,7 +1223,7 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui
        default:
            PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", 
                       apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
-           return -1;
+           goto apic_read_out_bad;
     }
 
 
@@ -1051,13 +1246,20 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui
     } else {
        PrintError("apic %u: core %u: Invalid apic read length (%d)\n", 
                   apic->lapic_id.val, core->cpu_id, length);
-       return -1;
+       goto apic_read_out_bad;
     }
 
     PrintDebug("apic %u: core %u: Read finished (val=%x)\n", 
               apic->lapic_id.val, core->cpu_id, *(uint32_t *)dst);
 
+
+    // apic_read_out_good:
+    v3_unlock(apic->lock);
     return length;
+
+ apic_read_out_bad:
+    v3_unlock(apic->lock);
+    return -1;
 }
 
 
@@ -1071,6 +1273,9 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
     uint32_t op_val = *(uint32_t *)src;
 
+
+    v3_lock(apic->lock);
+
     PrintDebug("apic %u: core %u: at %p and priv_data is at %p\n",
               apic->lapic_id.val, core->cpu_id, apic, priv_data);
 
@@ -1080,14 +1285,14 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
     if (msr->apic_enable == 0) {
        PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",
                   apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
-       return -1;
+       goto apic_write_out_bad;
     }
 
 
     if (length != 4) {
        PrintError("apic %u: core %u: Invalid apic write length (%d)\n", 
                   apic->lapic_id.val, length, core->cpu_id);
-       return -1;
+       goto apic_write_out_bad;
     }
 
     switch (reg_addr) {
@@ -1123,13 +1328,13 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
 
            PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", 
                       apic->lapic_id.val, core->cpu_id, (void *)reg_addr);
-           //  return -1;
+           //  goto apic_write_out_bad;
 
            break;
 
            // Data registers
        case APIC_ID_OFFSET:
-           PrintDebug("apic %u: core %u: my id is being changed to %u\n", 
+           V3_Print("apic %u: core %u: my id is being changed to %u\n", 
                       apic->lapic_id.val, core->cpu_id, op_val);
 
            apic->lapic_id.val = op_val;
@@ -1223,26 +1428,48 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
 
            // Action Registers
        case EOI_OFFSET:
-           // do eoi
+           // do eoi (we already have the lock)
            apic_do_eoi(apic);
            break;
 
-       case INT_CMD_LO_OFFSET:
+       case INT_CMD_LO_OFFSET: {
+           // execute command (we already have the lock)
+
+           struct int_cmd_reg tmp_icr;
+
            apic->int_cmd.lo = op_val;
 
-           PrintDebug("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
-                      apic->lapic_id.val, core->cpu_id,
-                      apic->int_cmd.val, apic->int_cmd.dst);
+           tmp_icr=apic->int_cmd;
 
-           if (route_ipi(apic_dev, apic, &(apic->int_cmd)) == -1) { 
+           //      V3_Print("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
+           //       apic->lapic_id.val, core->cpu_id,
+           //       apic->int_cmd.val, apic->int_cmd.dst);
+
+           apic->in_icr=0;
+
+           v3_unlock(apic->lock);
+
+           // route_ipi is responsible for locking apics, so we go in unlocked)
+           if (route_ipi(apic_dev, apic, &tmp_icr) == -1) { 
                PrintError("IPI Routing failure\n");
-               return -1;
+               goto apic_write_out_bad;
            }
 
+           //      v3_lock(apic->lock);  // expected for leaving this function
+
+       }
            break;
 
-       case INT_CMD_HI_OFFSET:
+       case INT_CMD_HI_OFFSET: {
+           // already have the lock
+           if (apic->in_icr) { 
+               PrintError("apic %u: core %u: writing command high=0x%x while in_icr=1\n", apic->lapic_id.val, core->cpu_id,apic->int_cmd.hi);
+           }
+
            apic->int_cmd.hi = op_val;
+           //V3_Print("apic %u: core %u: writing command high=0x%x\n", apic->lapic_id.val, core->cpu_id,apic->int_cmd.hi);
+           apic->in_icr=1;
+       }
            break;
 
 
@@ -1253,20 +1480,26 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
            PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", 
                       apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
 
-           return -1;
+           goto apic_write_out_bad;
     }
 
     PrintDebug("apic %u: core %u: Write finished\n", apic->lapic_id.val, core->cpu_id);
 
+    // apic_write_out_good:
+    v3_unlock(apic->lock);
     return length;
+
+ apic_write_out_bad:
+    v3_unlock(apic->lock);
+    return -1;
 }
 
 
 
 /* Interrupt Controller Functions */
 
-// returns 1 if an interrupt is pending, 0 otherwise
-static int apic_intr_pending(struct guest_info * core, void * private_data) {
+// internally used, expects caller to lock
+static int apic_intr_pending_nolock(struct guest_info * core, void * private_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
     int req_irq = get_highest_irr(apic);
@@ -1282,7 +1515,23 @@ static int apic_intr_pending(struct guest_info * core, void * private_data) {
     return 0;
 }
 
-static int apic_get_intr_number(struct guest_info * core, void * private_data) {
+// externally visible, so must lock itself
+static int apic_intr_pending(struct guest_info * core, void * private_data) {
+    struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
+    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
+    int rc;
+
+    v3_lock(apic->lock);
+    
+    rc=apic_intr_pending_nolock(core,private_data);
+    
+    v3_unlock(apic->lock);
+
+    return rc;
+}
+
+// Internal - no lock
+static int apic_get_intr_number_nolock(struct guest_info * core, void * private_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
     int req_irq = get_highest_irr(apic);
@@ -1298,6 +1547,25 @@ static int apic_get_intr_number(struct guest_info * core, void * private_data) {
 }
 
 
+// Externally visible, so must lock itself
+static int apic_get_intr_number(struct guest_info * core, void * private_data) {
+    struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
+    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
+    int rc;
+
+    v3_lock(apic->lock);
+    
+    rc=apic_get_intr_number_nolock(core,private_data);
+
+    v3_unlock(apic->lock);
+
+    return rc;
+}
+
+
+//
+// Here there is no source APIC, so there is no need to lock it
+// Furthermore, the expectation is that route_ipi will lock the destiation apic
 int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)
        (((struct vm_device *)dev_data)->private_data);
@@ -1312,8 +1580,8 @@ int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev
     tmp_icr.trig_mode = ipi->trigger_mode;
     tmp_icr.dst_shorthand = ipi->dst_shorthand;
     tmp_icr.dst = ipi->dst;
-    
 
+    // route_ipi is responsible for locking the destination apic
     return route_ipi(apic_dev, NULL, &tmp_icr);
 }
 
@@ -1322,31 +1590,41 @@ int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)
        (((struct vm_device*)dev_data)->private_data);
     struct apic_state * apic = &(apic_dev->apics[dst]); 
+    int do_xcall;
 
     PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
 
-    activate_apic_irq(apic, irq);
+    v3_lock(apic->lock);
+
+    do_xcall=activate_apic_irq_nolock(apic, irq);
 
-    if (V3_Get_CPU() != dst) {
+    if (do_xcall<0) { 
+       PrintError("Failed to activate apic irq\n");
+       v3_unlock(apic->lock);
+       return -1;
+    }
+    
+    if (do_xcall>0 && (V3_Get_CPU() != dst)) {
 #ifdef CONFIG_MULTITHREAD_OS
        v3_interrupt_cpu(vm, dst, 0);
 #else
        V3_ASSERT(0);
 #endif
-    }
 
+    }
+    v3_unlock(apic->lock);
     return 0;
 }
 
 
-
-static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
+// internal - caller must lock
+static int apic_begin_irq_nolock(struct guest_info * core, void * private_data, int irq) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
     int major_offset = (irq & ~0x00000007) >> 3;
     int minor_offset = irq & 0x00000007;
-    uint8_t * req_location = apic->int_req_reg + major_offset;
-    uint8_t * svc_location = apic->int_svc_reg + major_offset;
+    uint8_t *req_location = apic->int_req_reg + major_offset;
+    uint8_t *svc_location = apic->int_svc_reg + major_offset;
     uint8_t flag = 0x01 << minor_offset;
 
     if (*req_location & flag) {
@@ -1363,11 +1641,26 @@ static int apic_begin_irq(struct guest_info * core, void * private_data, int irq
     return 0;
 }
 
+// Since this is called, externally, it should lock the apic
+static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
+    struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
+    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
+    int rc;
+
+    v3_lock(apic->lock);
+
+    rc=apic_begin_irq_nolock(core,private_data,irq);
+
+    v3_unlock(apic->lock);
+
+    return rc;
+}
 
 
 
 /* Timer Functions */
-static void apic_update_time(struct guest_info * core, 
+// Caller will lock the apic
+static void apic_update_time_nolock(struct guest_info * core, 
                             uint64_t cpu_cycles, uint64_t cpu_freq, 
                             void * priv_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
@@ -1440,13 +1733,13 @@ static void apic_update_time(struct guest_info * core,
                   apic->lapic_id.val, core->cpu_id,
                   apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
 
-       if (apic_intr_pending(core, priv_data)) {
+       if (apic_intr_pending_nolock(core, priv_data)) {
            PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
                       apic->lapic_id.val, core->cpu_id, 
                       apic_get_intr_number(core, priv_data));
        }
 
-       if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
+       if (activate_internal_irq_nolock(apic, APIC_TMR_INT) == -1) {
            PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
                       apic->lapic_id.val, core->cpu_id);
        }
@@ -1457,10 +1750,25 @@ static void apic_update_time(struct guest_info * core,
        }
     }
 
-
+    return;
 }
 
 
+static void apic_update_time(struct guest_info * core, 
+                            uint64_t cpu_cycles, uint64_t cpu_freq, 
+                            void * priv_data) {
+    struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
+    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
+
+    v3_lock(apic->lock);
+
+    apic_update_time_nolock(core,cpu_cycles,cpu_freq,priv_data);
+
+    v3_unlock(apic->lock);
+    
+    return;
+}
+
 static struct intr_ctrl_ops intr_ops = {
     .intr_pending = apic_intr_pending,
     .get_intr_number = apic_get_intr_number,
@@ -1508,8 +1816,6 @@ static struct v3_device_ops dev_ops = {
 
 
 
-
-
 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     char * dev_id = v3_cfg_val(cfg, "ID");
     struct apic_dev_state * apic_dev = NULL;
@@ -1522,6 +1828,8 @@ static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
     apic_dev->num_apics = vm->num_cores;
 
+    //v3_lock_init(&(apic_dev->ipi_lock));
+
     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, apic_dev);
 
     if (dev == NULL) {
index d3b09c3..ca1e0ba 100644 (file)
@@ -19,7 +19,6 @@
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-
 #include <devices/cirrus_gfx_card.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_emulator.h>
@@ -34,7 +33,7 @@
 #include <devices/pci.h>
 #include <devices/pci_types.h>
 
-#include "network_console.h"
+//#include "network_console.h"
 
 
 
@@ -114,14 +113,14 @@ void video_do_out(uint16_t port, void * src, uint_t length){
 #endif
 }
 
-static int video_write_mem(addr_t guest_addr, void * dest, uint_t length, void * priv_data) {
+static int video_write_mem(struct guest_info * core, addr_t guest_addr, void * dest, uint_t length, void * priv_data) {
     struct vm_device * dev = (struct vm_device *)priv_data;
     struct video_internal * data = (struct video_internal *)dev->private_data;
     addr_t write_offset = guest_addr - START_ADDR;
-    uint_t difference = 0x18000;
-    int i = 0;
-
+//    uint_t difference = 0x18000;
+//    int i = 0;
 
+    /*
     PrintDebug("\n\nInside Video Write Memory.\n\n");
     PrintDebug("Guest address: %p length = %d\n", (void *)guest_addr, length);
 
@@ -131,67 +130,66 @@ static int video_write_mem(addr_t guest_addr, void * dest, uint_t length, void *
     for (i = 0; i < length; i += 2) {
        PrintDebug("%c", ((char *)(V3_VAddr((void *)guest_addr)))[i]);
     }
-
+    */
 #if PASSTHROUGH
     memcpy(data->video_memory + write_offset, V3_VAddr((void*)guest_addr), length);
 #endif
 
 
-
-    if (send_update(data->client_fd, data->video_memory + difference, write_offset-difference, data->start_addr_offset, length) == -1) {
+/*    if (send_update(data->client_fd, data->video_memory + difference, write_offset-difference, data->start_addr_offset, length) == -1) {
        PrintError("Error sending update to client\n");
        return -1;
     }
-
-    PrintDebug(" Done.\n");
+*/
+    // PrintDebug(" Done.\n");
     return length;
 }
 
-static int video_read_port(uint16_t port, void * dest, uint_t length, struct vm_device * dev) {
-    //PrintDebug("Video: Read port 0x%x\n",port);
+static int video_read_port(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data ) {
+    PrintDebug("Video: Read port 0x%x\n",port);
     video_do_in(port, dest, length);
     return length;
 }
 
-static int video_read_port_generic(uint16_t port, void * dest, uint_t length, struct vm_device * dev) {
+static int video_read_port_generic(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
     memset(dest, 0, length);
     video_do_in(port, dest, length);
     return length;
 }
 
 
-static int video_write_port(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
-    /*
+static int video_write_port(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
+    
       PrintDebug("Video: write port 0x%x...Wrote: ", port);
       uint_t i;
       for(i = 0; i < length; i++){
-      PrintDebug("%x", ((uint8_t*)src)[i]);
+      PrintDebug("%x", ((uint8_t*)dest)[i]);
       }
-      PrintDebug("...Done\n"); */
-    video_do_out(port, src, length);
+      PrintDebug("...Done\n");
+    video_do_out(port, dest, length);
     return length;
 }
 
-static int video_write_port_store(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
-    /*
+static int video_write_port_store(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
+    
       PrintDebug("Entering video_write_port_store...port 0x%x\n", port);
       uint_t i;
       for(i = 0; i < length; i++){
-      PrintDebug("%x", ((uint8_t*)src)[i]);
+      PrintDebug("%x", ((uint8_t*)dest)[i]);
       }
       PrintDebug("...Done\n"); 
-    */
-    struct video_internal * video_state = (struct video_internal *)dev->private_data;
+    
+    struct video_internal * video_state = (struct video_internal *)priv_data;
 
     video_state->ports[port - PORT_OFFSET] = 0;
-    memcpy(video_state->ports + (port - PORT_OFFSET), src, length); 
-    video_do_out(port, src, length);
+    memcpy(video_state->ports + (port - PORT_OFFSET), dest, length); 
+    video_do_out(port, dest, length);
 
     return length;
 }
 
-static int video_write_port_3D5(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
-    struct video_internal * video_state = (struct video_internal *)dev->private_data;
+static int video_write_port_3D5(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
+    struct video_internal * video_state = (struct video_internal *)priv_data;
     uint8_t new_start = 0;
     uint_t index = 0;
 
@@ -199,21 +197,21 @@ static int video_write_port_3D5(uint16_t port, void * src, uint_t length, struct
     {
        uint_t i = 0;
        for (i = 0; i < length; i++){
-           PrintDebug("%x", ((uint8_t*)src)[i]);
+           PrintDebug("%x", ((uint8_t*)dest)[i]);
        }
        PrintDebug("...Done\n");
     }
 
     video_state->ports[port - PORT_OFFSET] = 0;
 
-    memcpy(video_state->ports + (port - PORT_OFFSET), src, length);
+    memcpy(video_state->ports + (port - PORT_OFFSET), dest, length);
 
-    memcpy(&(video_state->reg_3D5[index]), src, length);
+    memcpy(&(video_state->reg_3D5[index]), dest, length);
 
     index = video_state->ports[port - 1 - PORT_OFFSET];
 
     // JRL: Add length check
-    new_start = *((uint8_t *)src);
+    new_start = *((uint8_t *)dest);
 
 
     switch (index) {
@@ -233,7 +231,7 @@ static int video_write_port_3D5(uint16_t port, void * src, uint_t length, struct
 
            PrintDebug("Scroll lines = %d\n", diff);
 
-           send_scroll(video_state->client_fd, diff, video_state->video_memory);
+//         send_scroll(video_state->client_fd, diff, video_state->video_memory);
 
            break;
        }
@@ -252,21 +250,21 @@ static int video_write_port_3D5(uint16_t port, void * src, uint_t length, struct
            
            PrintDebug("New Cursor Location; X=%d Y=%d\n", x, y);
            
-           send_cursor_update(video_state->client_fd, x, y);
+//         send_cursor_update(video_state->client_fd, x, y);
            break;
        }
        default:
            break;
     }
 
-    video_do_out(port, src, length);
+    video_do_out(port, dest, length);
 
     return length;
 }
 
 
-static int video_write_port_3C5(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
-    struct video_internal * video_state = (struct video_internal *)dev->private_data;
+static int video_write_port_3C5(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data ) {
+    struct video_internal * video_state = (struct video_internal *)priv_data;
     uint_t index = 0;
 
 
@@ -274,56 +272,56 @@ static int video_write_port_3C5(uint16_t port, void * src, uint_t length, struct
     {
        uint_t i = 0;
        for(i = 0; i < length; i++){
-           PrintDebug("%x", ((uint8_t*)src)[i]);
+           PrintDebug("%x", ((uint8_t*)dest)[i]);
        }
        PrintDebug("...Done\n");
     }
 
     video_state->ports[port - PORT_OFFSET] = 0;
-    memcpy(video_state->ports + (port - PORT_OFFSET), src, length); 
+    memcpy(video_state->ports + (port - PORT_OFFSET), dest, length); 
 
     index = video_state->ports[port - 1 - PORT_OFFSET];
 
-    memcpy(&(video_state->reg_3C4[index]), src, length);
-    video_do_out(port, src, length);
+    memcpy(&(video_state->reg_3C4[index]), dest, length);
+    video_do_out(port, dest, length);
 
     return length;
 }
 
-static int video_write_port_3CF(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
-    struct video_internal * video_state = (struct video_internal *)dev->private_data;
+static int video_write_port_3CF(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
+    struct video_internal * video_state = (struct video_internal *)priv_data;
 
     PrintDebug("Entering write_port_3CF....port 0x%x\n", port);
 
     {
        uint_t i = 0;
        for(i = 0; i < length; i++){
-           PrintDebug("%x", ((uint8_t*)src)[i]);
+           PrintDebug("%x", ((uint8_t*)dest)[i]);
        }
        PrintDebug("...Done\n");
     }
 
     video_state->ports[port - PORT_OFFSET] = 0;
-    memcpy(video_state->ports + (port - PORT_OFFSET), src, length); 
+    memcpy(video_state->ports + (port - PORT_OFFSET), dest, length); 
 
     uint_t index = video_state->ports[port - 1 - PORT_OFFSET];
-    memcpy(&(video_state->reg_3CE[index]), src, length);
-    video_do_out(port, src, length);
+    memcpy(&(video_state->reg_3CE[index]), dest, length);
+    video_do_out(port, dest, length);
     return length;
 }
 
-static int video_write_port_3D4(uint16_t port, void * src, uint_t length, struct vm_device * dev){
-    struct video_internal * video_state = (struct video_internal *) dev -> private_data;
+static int video_write_port_3D4(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data){
+    struct video_internal * video_state = (struct video_internal *)priv_data;
 
 #if 1
     if (length == 1) {
 
        video_state->ports[port - PORT_OFFSET] = 0;
-       memcpy(video_state->ports + (port - PORT_OFFSET), src, length);
+       memcpy(video_state->ports + (port - PORT_OFFSET), dest, length);
 
     } else if (length == 2) {
-       uint16_t new_start = *((uint16_t *)src);
-       uint16_t cursor_start = *((uint16_t *)src);;
+       uint16_t new_start = *((uint16_t *)dest);
+       uint16_t cursor_start = *((uint16_t *)dest);;
 
        //Updating the cursor
        if ((cursor_start & 0x00FF) == 0x000E) {
@@ -342,7 +340,7 @@ static int video_write_port_3D4(uint16_t port, void * src, uint_t length, struct
 
            PrintDebug("New Cursor Location; X=%d Y=%d\n", x, y);
 
-           send_cursor_update(video_state->client_fd, x, y);
+//         send_cursor_update(video_state->client_fd, x, y);
        }
 
        //Checking to see if scrolling is needed
@@ -362,42 +360,43 @@ static int video_write_port_3D4(uint16_t port, void * src, uint_t length, struct
 
            PrintDebug("Scroll lines = %d\n", diff);
 
-           send_scroll(video_state->client_fd, diff, video_state->video_memory+0x18000);
+//         send_scroll(video_state->client_fd, diff, video_state->video_memory+0x18000);
        }
     } else {
        // JRL ??
        return -1;
     }
 #endif 
-    video_do_out(port, src, length);
+    video_do_out(port, dest, length);
     return length;
 }
 
-static int video_write_mem_region(addr_t guest_addr, void * src, uint_t length, void * priv_data) {;
-    PrintDebug("Video write mem region guest_addr: 0x%p, src: 0x%p, length: %d, Value?= %x\n", (void *)guest_addr, src, length, *((uint32_t *)V3_VAddr((void *)guest_addr)));
+static int video_write_mem_region(struct guest_info * core, addr_t guest_addr, void * dest, uint_t length, void * priv_data) {;
+    PrintDebug("Video write mem region guest_addr: 0x%p, src: 0x%p, length: %d, Value?= %x\n", (void *)guest_addr, dest, length, *((uint32_t *)V3_VAddr((void *)guest_addr)));
     return length;
 }
 
-static int video_read_mem_region(addr_t guest_addr, void * dest, uint_t length, void * priv_data){
+static int video_read_mem_region(struct guest_info * core, addr_t guest_addr, void * dest, uint_t length, void * priv_data){
     PrintDebug("Video:  Within video_read_mem_region\n");
     return length;
 }
 
-static int video_write_io_region(addr_t guest_addr, void * src, uint_t length, void * priv_data){
+static int video_write_io_region(struct guest_info * core, addr_t guest_addr, void * dest, uint_t length, void * priv_data){
     PrintDebug("Video:  Within video_write_io_region\n");
     return length;
 }
 
-static int video_read_io_region(addr_t guest_addr, void * dest, uint_t length, void * priv_data){
+static int video_read_io_region(struct guest_info * core, addr_t guest_addr, void * dest, uint_t length, void * priv_data){
     PrintDebug("Video:  Within video_read_io_region\n");
     return length;
 }
 
 static int cirrus_gfx_card_free(struct vm_device * dev) {
-    v3_unhook_mem(dev->vm, START_ADDR);
+    v3_unhook_mem(dev->vm, V3_MEM_CORE_ANY, START_ADDR);
     return 0;
 }
 
+/*
 static int cirrus_gfx_card_reset_device(struct vm_device * dev) {
     PrintDebug("Video: reset device\n");
     return 0;
@@ -412,22 +411,23 @@ static int cirrus_gfx_card_stop_device(struct vm_device * dev) {
     PrintDebug("Video: stop device\n");
     return 0;
 }
-
+*/
 static struct v3_device_ops dev_ops = {
-    .free = cirrus_gfx_card_free,
-    .reset = cirrus_gfx_card_reset_device,
-    .start = cirrus_gfx_card_start_device,
-    .stop = cirrus_gfx_card_stop_device,
+    .free = (int (*)(void *))cirrus_gfx_card_free,
+//    .reset = cirrus_gfx_card_reset_device,
+//    .start = cirrus_gfx_card_start_device,
+//    .stop = cirrus_gfx_card_stop_device,
 };
 
-static int cirrus_gfx_card_init(struct guest_info * vm, v3_cfg_tree_t * cfg){
+static int cirrus_gfx_card_init(struct v3_vm_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);
+//    struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
+    struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
     char * dev_id = v3_cfg_val(cfg, "ID");
 
-    struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, video_state);
+    struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, video_state);
 
-    if (v3_attach_device(vm, dev) == -1) {
+    if (dev == NULL) {
        PrintError("Could not attach device %s\n", dev_id);
        return -1;
     }
@@ -491,18 +491,18 @@ static int cirrus_gfx_card_init(struct guest_info * vm, v3_cfg_tree_t * cfg){
 
 
 #if PASSTHROUGH
-    if (v3_hook_write_mem(vm, START_ADDR, END_ADDR, START_ADDR, &video_write_mem, dev) == -1){
+    if (v3_hook_write_mem(vm, V3_MEM_CORE_ANY, START_ADDR, END_ADDR, START_ADDR, &video_write_mem, dev) == -1){
        PrintDebug("\n\nVideo Hook failed.\n\n");
     }
 #else
-    if (v3_hook_write_mem(vm, START_ADDR, END_ADDR, video_memory_pa, &video_write_mem, dev) == -1){
+    if (v3_hook_write_mem(vm, V3_MEM_CORE_ANY, START_ADDR, END_ADDR, video_memory_pa, &video_write_mem, dev) == -1){
        PrintDebug("\n\nVideo Hook failed.\n\n");
     }
 #endif
 
     PrintDebug("Video: Getting client connection\n");
 
-    video_state->client_fd = get_client_connection(vm);
+    //video_state->client_fd = get_client_connection(vm);
 
     PrintDebug("Video: Client connection established\n");
 
index 010f4ab..b9375a8 100644 (file)
@@ -288,6 +288,9 @@ static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq
        ipi.dst = irq_entry->dst_field;
        ipi.dst_shorthand = 0;
 
+
+       PrintDebug("ioapic %u: IPI: vector 0x%x, mode 0x%x, logical 0x%x, trigger 0x%x, dst 0x%x, shorthand 0x%x\n",
+                  ioapic->ioapic_id.id, ipi.vector, ipi.mode, ipi.logical, ipi.trigger_mode, ipi.dst, ipi.dst_shorthand);
        // Need to add destination argument here...
        if (v3_apic_send_ipi(vm, &ipi, ioapic->apic_dev_data) == -1) {
            PrintError("Error sending IPI to apic %d\n", ipi.dst);
index 20adea3..7b1b919 100644 (file)
@@ -451,11 +451,11 @@ int v3_svm_enter(struct guest_info * info) {
     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); 
     addr_t exit_code = 0, exit_info1 = 0, exit_info2 = 0;
 
-    v3_adjust_time(info);
-
     // Conditionally yield the CPU if the timeslice has expired
     v3_yield_cond(info);
 
+    v3_adjust_time(info);
+
     // disable global interrupts for vm state transition
     v3_clgi();
 
@@ -504,6 +504,9 @@ int v3_svm_enter(struct guest_info * info) {
 #endif
 
     v3_update_timers(info);
+#ifdef CONFIG_TIME_HIDE_VM_COST
+    v3_restart_time(info);
+#endif
     guest_ctrl->TSC_OFFSET = v3_tsc_host_offset(&info->time_state);
 
     //V3_Print("Calling v3_svm_launch\n");
@@ -514,6 +517,13 @@ int v3_svm_enter(struct guest_info * info) {
 
     v3_last_exit = (uint32_t)(guest_ctrl->exit_code);
 
+#ifdef CONFIG_TIME_HIDE_VM_COST
+    v3_pause_time(info);
+#ifdef CONFIG_TIME_HIDE_EXIT_COST
+    v3_offset_time(info, -CONFIG_TIME_EXIT_COST_ADJUST);
+#endif
+#endif
+
     //PrintDebug("SVM Returned\n");
     
     info->num_exits++;
index 51fbba7..1cb6478 100644 (file)
@@ -86,6 +86,11 @@ int v3_start_time(struct guest_info * info) {
     uint64_t t = v3_get_host_time(&info->time_state); 
 
     PrintDebug("Starting initial guest time as %llu\n", t);
+#ifdef CONFIG_TIME_HIDE_VM_COST
+    info->time_state.pause_time = t; 
+#else
+    info->time_state.pause_time = 0; 
+#endif
     info->time_state.last_update = t;
     info->time_state.initial_time = t;
     info->yield_start_cycle = t;
@@ -97,9 +102,7 @@ int v3_start_time(struct guest_info * info) {
 int v3_adjust_time(struct guest_info * info) {
     struct vm_time * time_state = &(info->time_state);
 
-    if (time_state->host_cpu_freq == time_state->guest_cpu_freq) {
-       time_state->guest_host_offset = 0;
-    } else {
+    if (time_state->host_cpu_freq != time_state->guest_cpu_freq) {
        uint64_t guest_time, guest_elapsed, desired_elapsed;
        uint64_t host_time, target_host_time;
 
@@ -118,12 +121,52 @@ int v3_adjust_time(struct guest_info * info) {
            host_time = v3_get_host_time(time_state);
        }
 
+       // This overrides any pause/unpause times because the difference 
+       // is going to be too big for any pause/unpause the notice.
        time_state->guest_host_offset = (sint64_t)guest_time - (sint64_t)host_time;
     }
 
     return 0;
 }
 
+int 
+v3_pause_time( struct guest_info * info ) 
+{
+    struct vm_time * time_state = &(info->time_state);
+    if (time_state->pause_time == 0) {
+        time_state->pause_time = v3_get_host_time(time_state);
+//     PrintDebug("Pausing at host time %llu.\n", time_state->pause_time);
+    } else {
+        PrintError("Palacios timekeeping paused when already paused.\n");
+    }
+    return 0;
+}
+
+int 
+v3_restart_time( struct guest_info * info )
+{
+    struct vm_time * time_state = &(info->time_state);
+
+    if (time_state->pause_time) {
+        sint64_t pause_diff = (v3_get_host_time(time_state) - time_state->pause_time);
+        time_state->guest_host_offset -= pause_diff;
+        time_state->pause_time = 0;
+//     PrintDebug("Resuming time after %lld cycles with offset %lld.\n", pause_diff, time_state->guest_host_offset);
+    } else {
+        PrintError( "Palacios time keeping restarted when not paused.");
+    }
+
+    return 0;
+}
+       
+int v3_offset_time( struct guest_info * info, sint64_t offset )
+{
+    struct vm_time * time_state = &(info->time_state);
+//    PrintDebug("Adding additional offset of %lld to guest time.\n", offset);
+    time_state->guest_host_offset += offset;
+    return 0;
+}
+          
 struct v3_timer * v3_add_timer(struct guest_info * info, 
                               struct v3_timer_ops * ops, 
                               void * private_data) {
@@ -149,15 +192,19 @@ int v3_remove_timer(struct guest_info * info, struct v3_timer * timer) {
 }
 
 void v3_update_timers(struct guest_info * info) {
+    struct vm_time *time_state = &info->time_state;
     struct v3_timer * tmp_timer;
     uint64_t old_time = info->time_state.last_update;
-    uint64_t cycles;
+    sint64_t cycles;
+
+    time_state->last_update = v3_get_guest_time(time_state);
+    cycles = time_state->last_update - old_time;
 
-    info->time_state.last_update = v3_get_guest_time(&info->time_state);
-    cycles = info->time_state.last_update - old_time;
+    //    PrintDebug("Updating timer for %lld elapsed cycles (pt=%llu, offset=%lld).\n", 
+    //        cycles, time_state->pause_time, time_state->guest_host_offset);
 
-    list_for_each_entry(tmp_timer, &(info->time_state.timers), timer_link) {
-       tmp_timer->ops->update_timer(info, cycles, info->time_state.guest_cpu_freq, tmp_timer->private_data);
+    list_for_each_entry(tmp_timer, &(time_state->timers), timer_link) {
+       tmp_timer->ops->update_timer(info, cycles, time_state->guest_cpu_freq, tmp_timer->private_data);
     }
 }
 
@@ -172,12 +219,14 @@ void v3_update_timers(struct guest_info * info) {
 
 int v3_rdtsc(struct guest_info * info) {
     uint64_t tscval = v3_get_guest_tsc(&info->time_state);
+    PrintDebug("Returning %llu as TSC.\n", tscval);
     info->vm_regs.rdx = tscval >> 32;
     info->vm_regs.rax = tscval & 0xffffffffLL;
     return 0;
 }
 
 int v3_handle_rdtsc(struct guest_info * info) {
+  PrintDebug("Handling virtual RDTSC call.\n");
     v3_rdtsc(info);
     
     info->vm_regs.rax &= 0x00000000ffffffffLL;
@@ -213,9 +262,10 @@ int v3_rdtscp(struct guest_info * info) {
 
 
 int v3_handle_rdtscp(struct guest_info * info) {
+  PrintDebug("Handling virtual RDTSCP call.\n");
 
     v3_rdtscp(info);
-    
+
     info->vm_regs.rax &= 0x00000000ffffffffLL;
     info->vm_regs.rcx &= 0x00000000ffffffffLL;
     info->vm_regs.rdx &= 0x00000000ffffffffLL;
index f3641be..4b4a8f6 100644 (file)
@@ -41,6 +41,8 @@
 #define V3_XML_DUP     0x20 // attribute name and value are strduped
 //
 
+static char * V3_XML_NIL[] = { NULL }; // empty, null terminated array of strings
+
 
 #define V3_XML_WS   "\t\r\n "  // whitespace
 #define V3_XML_ERRL 128        // maximum error string length
@@ -201,7 +203,9 @@ struct v3_xml * v3_xml_get(struct v3_xml * xml, ...) {
 // 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;
+    if (xml) {
+       xml->flags |= flag;
+    }
     return xml;
 }
 
@@ -454,7 +458,7 @@ static struct v3_xml * v3_xml_new(const char * name) {
 }
 
 // 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 * v3_xml_insert(struct v3_xml * xml, struct v3_xml * dest, size_t off) {
     struct v3_xml * cur, * prev, * head;
 
     xml->next = NULL;
@@ -900,3 +904,294 @@ void v3_xml_free(struct v3_xml * xml) {
     V3_Free(xml);
 }
 
+
+
+
+
+
+
+// sets the character content for the given tag and returns the tag
+struct v3_xml *  v3_xml_set_txt(struct v3_xml * xml, const char *txt) {
+    if (! xml) {
+       return NULL;
+    }
+
+    if (xml->flags & V3_XML_TXTM) {
+       // existing txt was malloced
+       V3_Free(xml->txt); 
+    }
+
+    xml->flags &= ~V3_XML_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.
+struct v3_xml * v3_xml_set_attr(struct v3_xml * xml, const char * name, const char * value) {
+    int l = 0;
+    int 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) {
+           // nothing to do
+           return xml;
+       }
+       
+       if (xml->attr == V3_XML_NIL) { 
+           // first attribute
+            xml->attr = V3_Malloc(4 * sizeof(char *));
+
+           // empty list of malloced names/vals
+            xml->attr[1] = strdup(""); 
+        } else {
+           xml->attr = tmp_realloc(xml->attr, l * sizeof(char *), (l + 4) * sizeof(char *));
+       }
+
+       // set attribute name
+        xml->attr[l] = (char *)name; 
+
+       // null terminate attribute list
+        xml->attr[l + 2] = NULL; 
+
+        xml->attr[l + 3] = tmp_realloc(xml->attr[l + 1],
+                                      strlen(xml->attr[l + 1]),
+                                      (c = strlen(xml->attr[l + 1])) + 2);
+
+       // set name/value as not malloced
+        strcpy(xml->attr[l + 3] + c, " "); 
+
+        if (xml->flags & V3_XML_DUP) {
+           xml->attr[l + 3][c] = V3_XML_NAMEM;
+       }
+    } else if (xml->flags & V3_XML_DUP) {
+       // name was strduped
+       V3_Free((char *)name); 
+    }
+
+
+    // find end of attribute list
+    for (c = l; xml->attr[c]; c += 2); 
+
+    if (xml->attr[c + 1][l / 2] & V3_XML_TXTM) {
+       //old val
+       V3_Free(xml->attr[l + 1]); 
+    }
+
+    if (xml->flags & V3_XML_DUP) {
+       xml->attr[c + 1][l / 2] |= V3_XML_TXTM;
+    } else {
+       xml->attr[c + 1][l / 2] &= ~V3_XML_TXTM;
+    }
+
+
+    if (value) {
+       // set attribute value
+       xml->attr[l + 1] = (char *)value; 
+    } else { 
+       // remove attribute
+        
+       if (xml->attr[c + 1][l / 2] & V3_XML_NAMEM) {
+           V3_Free(xml->attr[l]);
+       }
+
+        memmove(xml->attr + l, xml->attr + l + 2, (c - l + 2) * sizeof(char*));
+
+        xml->attr = tmp_realloc(xml->attr, c * sizeof(char *), (c + 2) * sizeof(char *));
+
+       // fix list of which name/vals are malloced
+        memmove(xml->attr[c + 1] + (l / 2), xml->attr[c + 1] + (l / 2) + 1,
+                (c / 2) - (l / 2)); 
+    }
+
+    // clear strdup() flag
+    xml->flags &= ~V3_XML_DUP; 
+
+    return xml;
+}
+
+// removes a tag along with its subtags without freeing its memory
+struct v3_xml * v3_xml_cut(struct v3_xml * xml) {
+    struct v3_xml * cur;
+
+    if (! xml) {
+       // nothing to do
+       return NULL; 
+    }
+
+    if (xml->next) {
+       // patch sibling list
+       xml->next->sibling = xml->sibling; 
+    }
+
+
+    if (xml->parent) { 
+       // not root tag
+
+       // find head of subtag list
+        cur = xml->parent->child; 
+
+        if (cur == xml) {
+           // first subtag
+           xml->parent->child = xml->ordered; 
+       } else { 
+       // not first subtag
+
+            while (cur->ordered != xml) {
+               cur = cur->ordered;
+           }
+
+           // patch ordered list
+            cur->ordered = cur->ordered->ordered; 
+
+           // go back to head of subtag list
+            cur = xml->parent->child; 
+
+            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 {
+                   // not first of a sibling list
+                   cur = cur->sibling;
+               }
+            }
+
+            while (cur->next && cur->next != xml) {
+               cur = cur->next;
+           }
+
+            if (cur->next) {
+               // patch next list
+               cur->next = cur->next->next; 
+           }
+        } 
+   }
+    xml->ordered = xml->sibling = xml->next = NULL;
+    return xml;
+}
+
+
+
+
+/* ************************** */
+/* *** XML ENCODING       *** */
+/* ************************** */
+
+// Encodes ampersand sequences appending the results to *dst, reallocating *dst
+// if length excedes max. a is non-zero for attribute encoding. Returns *dst
+static char *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 = tmp_realloc(*dst, *max, *max += V3_XML_BUFSIZE);
+
+        switch (*s) {
+        case '\0': return *dst;
+        case '&': *dlen += sprintf(*dst + *dlen, "&amp;"); break;
+        case '<': *dlen += sprintf(*dst + *dlen, "&lt;"); break;
+        case '>': *dlen += sprintf(*dst + *dlen, "&gt;"); break;
+        case '"': *dlen += sprintf(*dst + *dlen, (a) ? "&quot;" : "\""); break;
+        case '\n': *dlen += sprintf(*dst + *dlen, (a) ? "&#xA;" : "\n"); break;
+        case '\t': *dlen += sprintf(*dst + *dlen, (a) ? "&#x9;" : "\t"); break;
+        case '\r': *dlen += sprintf(*dst + *dlen, "&#xD;"); 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.
+static char *toxml_r(struct v3_xml * 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 = ampencode(txt + start, xml->off - start, s, len, max, 0);
+
+    while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+        *s = tmp_realloc(*s, *max, *max += V3_XML_BUFSIZE);
+
+    *len += sprintf(*s + *len, "<%s", xml->name); // open tag
+    for (i = 0; xml->attr[i]; i += 2) { // tag attributes
+        if (v3_xml_attr(xml, xml->attr[i]) != xml->attr[i + 1]) continue;
+        while (*len + strlen(xml->attr[i]) + 7 > *max) // reallocate s
+            *s = tmp_realloc(*s, *max, *max += V3_XML_BUFSIZE);
+
+        *len += sprintf(*s + *len, " %s=\"", xml->attr[i]);
+        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] || v3_xml_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 = tmp_realloc(*s, *max, *max += V3_XML_BUFSIZE);
+
+        *len += sprintf(*s + *len, " %s=\"", attr[i][j]);
+        ampencode(attr[i][j + 1], -1, s, len, max, 1);
+        *len += sprintf(*s + *len, "\"");
+    }
+    *len += sprintf(*s + *len, ">");
+
+    *s = (xml->child) ? toxml_r(xml->child, s, len, max, 0, attr) //child
+                      : ampencode(xml->txt, -1, s, len, max, 0);  //data
+    
+    while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+        *s = tmp_realloc(*s, *max, *max += V3_XML_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) ? toxml_r(xml->ordered, s, len, max, off, attr)
+                          : ampencode(txt + off, -1, s, len, max, 0);
+}
+
+// Converts an xml structure back to xml. Returns a string of xml data that
+// must be freed.
+char * v3_xml_tostr(struct v3_xml * xml) {
+    struct v3_xml * p = (xml) ? xml->parent : NULL;
+    struct v3_xml * o = (xml) ? xml->ordered : NULL;
+    struct v3_xml_root * root = (struct v3_xml_root *)xml;
+    size_t len = 0, max = V3_XML_BUFSIZE;
+    char *s = strcpy(V3_Malloc(max), "");
+
+    if (! xml || ! xml->name) return tmp_realloc(s, max, len + 1);
+    while (root->xml.parent) root = (struct v3_xml_root *)root->xml.parent; // root tag
+
+
+    xml->parent = xml->ordered = NULL;
+    s = toxml_r(xml, &s, &len, &max, 0, root->attr);
+    xml->parent = p;
+    xml->ordered = o;
+
+
+    return tmp_realloc(s, max, len + 1);
+}
diff --git a/test/geekos_test_vm/build/depend.mak b/test/geekos_test_vm/build/depend.mak
deleted file mode 100644 (file)
index e69de29..0000000