mirror of
https://github.com/xen-project/xen.git
synced 2026-10-30 03:00:05 +01:00
merge with xen-unstable.hg
This commit is contained in:
commit
ebdb5845be
103 files changed
+2987
-1025
No files matched your search
@@ -36,6 +36,12 @@ endif
|
||||
cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
|
||||
/dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;)
|
||||
|
||||
# cc-ver
|
||||
# Usage: ifeq ($(call cc-ver,$(CC),0x030400),y)
|
||||
cc-ver = $(shell if [ $$((`$(1) -dumpversion | awk -F. \
|
||||
'{ printf "0x%02x%02x%02x", $$1, $$2, $$3}'`)) -ge $$(($(2))) ]; \
|
||||
then echo y; else echo n; fi ;)
|
||||
|
||||
ifneq ($(debug),y)
|
||||
CFLAGS += -DNDEBUG
|
||||
else
|
||||
|
||||
@@ -9359,10 +9359,10 @@ $\mathit{RO}_\mathit{run}$ & {\tt VBDs} & (VBD ref) Set & list of vbds that ref
|
||||
$\mathit{RO}_\mathit{run}$ & {\tt crash\_dumps} & (crashdump ref) Set & list of crash dumps that refer to this disk \\
|
||||
$\mathit{RW}$ & {\tt virtual\_size} & int & size of disk as presented to the guest (in bytes). Note that, depending on storage backend type, requested size may not be respected exactly \\
|
||||
$\mathit{RO}_\mathit{run}$ & {\tt physical\_utilisation} & int & amount of physical space that the disk image is currently taking up on the storage repository (in bytes) \\
|
||||
$\mathit{RO}_\mathit{ins}$ & {\tt sector\_size} & int & sector size of VDI (in bytes) \\
|
||||
$\mathit{RO}_\mathit{ins}$ & {\tt type} & vdi\_type & type of the VDI \\
|
||||
$\mathit{RW}$ & {\tt sharable} & bool & true if this disk may be shared \\
|
||||
$\mathit{RW}$ & {\tt read\_only} & bool & true if this disk may ONLY be mounted read-only \\
|
||||
$\mathit{RW}$ & {\tt other\_config} & (string $\rightarrow$ string) Map & additional configuration \\
|
||||
\hline
|
||||
\end{longtable}
|
||||
\subsection{RPCs associated with class: VDI}
|
||||
@@ -9808,38 +9808,6 @@ int
|
||||
}
|
||||
|
||||
|
||||
value of the field
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
\subsubsection{RPC name:~get\_sector\_size}
|
||||
|
||||
{\bf Overview:}
|
||||
Get the sector\_size field of the given VDI.
|
||||
|
||||
\noindent {\bf Signature:}
|
||||
\begin{verbatim} int get_sector_size (session_id s, VDI ref self)\end{verbatim}
|
||||
|
||||
|
||||
\noindent{\bf Arguments:}
|
||||
|
||||
|
||||
\vspace{0.3cm}
|
||||
\begin{tabular}{|c|c|p{7cm}|}
|
||||
\hline
|
||||
{\bf type} & {\bf name} & {\bf description} \\ \hline
|
||||
{\tt VDI ref } & self & reference to the object \\ \hline
|
||||
|
||||
\end{tabular}
|
||||
|
||||
\vspace{0.3cm}
|
||||
|
||||
\noindent {\bf Return Type:}
|
||||
{\tt
|
||||
int
|
||||
}
|
||||
|
||||
|
||||
value of the field
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
@@ -10005,6 +9973,143 @@ void
|
||||
|
||||
|
||||
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
\subsubsection{RPC name:~get\_other\_config}
|
||||
|
||||
{\bf Overview:}
|
||||
Get the other\_config field of the given VDI.
|
||||
|
||||
\noindent {\bf Signature:}
|
||||
\begin{verbatim} ((string -> string) Map) get_other_config (session_id s, VDI ref self)\end{verbatim}
|
||||
|
||||
|
||||
\noindent{\bf Arguments:}
|
||||
|
||||
|
||||
\vspace{0.3cm}
|
||||
\begin{tabular}{|c|c|p{7cm}|}
|
||||
\hline
|
||||
{\bf type} & {\bf name} & {\bf description} \\ \hline
|
||||
{\tt VDI ref } & self & reference to the object \\ \hline
|
||||
|
||||
\end{tabular}
|
||||
|
||||
\vspace{0.3cm}
|
||||
|
||||
\noindent {\bf Return Type:}
|
||||
{\tt
|
||||
(string $\rightarrow$ string) Map
|
||||
}
|
||||
|
||||
|
||||
value of the field
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
\subsubsection{RPC name:~set\_other\_config}
|
||||
|
||||
{\bf Overview:}
|
||||
Set the other\_config field of the given VDI.
|
||||
|
||||
\noindent {\bf Signature:}
|
||||
\begin{verbatim} void set_other_config (session_id s, VDI ref self, (string -> string) Map value)\end{verbatim}
|
||||
|
||||
|
||||
\noindent{\bf Arguments:}
|
||||
|
||||
|
||||
\vspace{0.3cm}
|
||||
\begin{tabular}{|c|c|p{7cm}|}
|
||||
\hline
|
||||
{\bf type} & {\bf name} & {\bf description} \\ \hline
|
||||
{\tt VDI ref } & self & reference to the object \\ \hline
|
||||
|
||||
{\tt (string $\rightarrow$ string) Map } & value & New value to set \\ \hline
|
||||
|
||||
\end{tabular}
|
||||
|
||||
\vspace{0.3cm}
|
||||
|
||||
\noindent {\bf Return Type:}
|
||||
{\tt
|
||||
void
|
||||
}
|
||||
|
||||
|
||||
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
\subsubsection{RPC name:~add\_to\_other\_config}
|
||||
|
||||
{\bf Overview:}
|
||||
Add the given key-value pair to the other\_config field of the given VDI.
|
||||
|
||||
\noindent {\bf Signature:}
|
||||
\begin{verbatim} void add_to_other_config (session_id s, VDI ref self, string key, string value)\end{verbatim}
|
||||
|
||||
|
||||
\noindent{\bf Arguments:}
|
||||
|
||||
|
||||
\vspace{0.3cm}
|
||||
\begin{tabular}{|c|c|p{7cm}|}
|
||||
\hline
|
||||
{\bf type} & {\bf name} & {\bf description} \\ \hline
|
||||
{\tt VDI ref } & self & reference to the object \\ \hline
|
||||
|
||||
{\tt string } & key & Key to add \\ \hline
|
||||
|
||||
{\tt string } & value & Value to add \\ \hline
|
||||
|
||||
\end{tabular}
|
||||
|
||||
\vspace{0.3cm}
|
||||
|
||||
\noindent {\bf Return Type:}
|
||||
{\tt
|
||||
void
|
||||
}
|
||||
|
||||
|
||||
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
\subsubsection{RPC name:~remove\_from\_other\_config}
|
||||
|
||||
{\bf Overview:}
|
||||
Remove the given key and its corresponding value from the other\_config
|
||||
field of the given VDI. If the key is not in that Map, then do nothing.
|
||||
|
||||
\noindent {\bf Signature:}
|
||||
\begin{verbatim} void remove_from_other_config (session_id s, VDI ref self, string key)\end{verbatim}
|
||||
|
||||
|
||||
\noindent{\bf Arguments:}
|
||||
|
||||
|
||||
\vspace{0.3cm}
|
||||
\begin{tabular}{|c|c|p{7cm}|}
|
||||
\hline
|
||||
{\bf type} & {\bf name} & {\bf description} \\ \hline
|
||||
{\tt VDI ref } & self & reference to the object \\ \hline
|
||||
|
||||
{\tt string } & key & Key to remove \\ \hline
|
||||
|
||||
\end{tabular}
|
||||
|
||||
\vspace{0.3cm}
|
||||
|
||||
\noindent {\bf Return Type:}
|
||||
{\tt
|
||||
void
|
||||
}
|
||||
|
||||
|
||||
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
\vspace{0.3cm}
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
#endif
|
||||
|
||||
unsigned long *phys_to_machine_mapping;
|
||||
extern char *stack;
|
||||
extern char stack[];
|
||||
extern void page_walk(unsigned long virt_addr);
|
||||
|
||||
void new_pt_frame(unsigned long *pt_pfn, unsigned long prev_l_mfn,
|
||||
@@ -453,7 +453,7 @@ void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p)
|
||||
printk(" _text: %p\n", &_text);
|
||||
printk(" _etext: %p\n", &_etext);
|
||||
printk(" _edata: %p\n", &_edata);
|
||||
printk(" stack start: %p\n", &stack);
|
||||
printk(" stack start: %p\n", stack);
|
||||
printk(" _end: %p\n", &_end);
|
||||
|
||||
/* First page follows page table pages and 3 more pages (store page etc) */
|
||||
|
||||
@@ -135,7 +135,7 @@ gnttab_alloc_and_grant(void **map)
|
||||
return gref;
|
||||
}
|
||||
|
||||
static const char *gnttabop_error_msgs[] = GNTTABOP_error_msgs;
|
||||
static const char * const gnttabop_error_msgs[] = GNTTABOP_error_msgs;
|
||||
|
||||
const char *
|
||||
gnttabop_error(int16_t status)
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
|
||||
void do_hypervisor_callback(struct pt_regs *regs)
|
||||
{
|
||||
u32 l1, l2;
|
||||
unsigned int l1i, l2i, port;
|
||||
unsigned long l1, l2, l1i, l2i;
|
||||
unsigned int port;
|
||||
int cpu = 0;
|
||||
shared_info_t *s = HYPERVISOR_shared_info;
|
||||
vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
|
||||
|
||||
@@ -74,6 +74,13 @@ static inline void wake_up(struct wait_queue_head *head)
|
||||
local_irq_restore(flags); \
|
||||
} while (0)
|
||||
|
||||
#define remove_waiter(w) do { \
|
||||
unsigned long flags; \
|
||||
local_irq_save(flags); \
|
||||
remove_wait_queue(&w); \
|
||||
local_irq_restore(flags); \
|
||||
} while (0)
|
||||
|
||||
#define wait_event(wq, condition) do{ \
|
||||
unsigned long flags; \
|
||||
if(condition) \
|
||||
|
||||
@@ -13,6 +13,7 @@ void init_xenbus(void);
|
||||
char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value);
|
||||
|
||||
char *xenbus_watch_path(xenbus_transaction_t xbt, const char *path);
|
||||
void wait_for_watch(void);
|
||||
char* xenbus_wait_for_value(const char*,const char*);
|
||||
|
||||
/* Associates a value with a path. Returns a malloc'd error string on
|
||||
|
||||
@@ -72,11 +72,12 @@ static void memcpy_from_ring(const void *Ring,
|
||||
memcpy(dest + c1, ring, c2);
|
||||
}
|
||||
|
||||
static inline void wait_for_watch(void)
|
||||
void wait_for_watch(void)
|
||||
{
|
||||
DEFINE_WAIT(w);
|
||||
add_waiter(w,watch_queue);
|
||||
schedule();
|
||||
remove_waiter(w);
|
||||
wake(current);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,5 +28,5 @@
|
||||
#define NOTE_KERNELCAP_END ASM_ELF_NOTE_END
|
||||
|
||||
NOTE_KERNELCAP_BEGIN(1, 1)
|
||||
NOTE_KERNELCAP(1, "nosegneg") /* Change 1 back to 0 when glibc is fixed! */
|
||||
NOTE_KERNELCAP(0, "nosegneg")
|
||||
NOTE_KERNELCAP_END
|
||||
@@ -256,8 +256,9 @@ void pte_free(struct page *pte)
|
||||
unsigned long va = (unsigned long)__va(pfn << PAGE_SHIFT);
|
||||
|
||||
if (!pte_write(*virt_to_ptep(va)))
|
||||
BUG_ON(HYPERVISOR_update_va_mapping(
|
||||
va, pfn_pte(pfn, PAGE_KERNEL), 0));
|
||||
if (HYPERVISOR_update_va_mapping(
|
||||
va, pfn_pte(pfn, PAGE_KERNEL), 0))
|
||||
BUG();
|
||||
} else
|
||||
clear_bit(PG_pinned, &pte->flags);
|
||||
|
||||
@@ -672,14 +673,23 @@ void mm_unpin(struct mm_struct *mm)
|
||||
void mm_pin_all(void)
|
||||
{
|
||||
struct page *page;
|
||||
unsigned long flags;
|
||||
|
||||
if (xen_feature(XENFEAT_writable_page_tables))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Allow uninterrupted access to the pgd_list. Also protects
|
||||
* __pgd_pin() by disabling preemption.
|
||||
* All other CPUs must be at a safe point (e.g., in stop_machine
|
||||
* or offlined entirely).
|
||||
*/
|
||||
spin_lock_irqsave(&pgd_lock, flags);
|
||||
for (page = pgd_list; page; page = (struct page *)page->index) {
|
||||
if (!test_bit(PG_pinned, &page->flags))
|
||||
__pgd_pin((pgd_t *)page_address(page));
|
||||
}
|
||||
spin_unlock_irqrestore(&pgd_lock, flags);
|
||||
}
|
||||
|
||||
void _arch_dup_mmap(struct mm_struct *mm)
|
||||
|
||||
@@ -597,8 +597,10 @@ void __init xen_init_pt(void)
|
||||
early_make_page_readonly(level2_kernel_pgt,
|
||||
XENFEAT_writable_page_tables);
|
||||
|
||||
xen_pgd_pin(__pa_symbol(init_level4_pgt));
|
||||
xen_pgd_pin(__pa_symbol(init_level4_user_pgt));
|
||||
if (!xen_feature(XENFEAT_writable_page_tables)) {
|
||||
xen_pgd_pin(__pa_symbol(init_level4_pgt));
|
||||
xen_pgd_pin(__pa_symbol(init_level4_user_pgt));
|
||||
}
|
||||
|
||||
set_pgd((pgd_t *)(init_level4_user_pgt + 511),
|
||||
mk_kernel_pgd(__pa_symbol(level3_user_pgt)));
|
||||
|
||||
@@ -79,14 +79,17 @@ void mm_pin(struct mm_struct *mm)
|
||||
spin_lock(&mm->page_table_lock);
|
||||
|
||||
mm_walk(mm, PAGE_KERNEL_RO);
|
||||
BUG_ON(HYPERVISOR_update_va_mapping(
|
||||
(unsigned long)mm->pgd,
|
||||
pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL_RO),
|
||||
UVMF_TLB_FLUSH));
|
||||
BUG_ON(HYPERVISOR_update_va_mapping(
|
||||
(unsigned long)__user_pgd(mm->pgd),
|
||||
pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT, PAGE_KERNEL_RO),
|
||||
UVMF_TLB_FLUSH));
|
||||
if (HYPERVISOR_update_va_mapping(
|
||||
(unsigned long)mm->pgd,
|
||||
pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL_RO),
|
||||
UVMF_TLB_FLUSH))
|
||||
BUG();
|
||||
if (HYPERVISOR_update_va_mapping(
|
||||
(unsigned long)__user_pgd(mm->pgd),
|
||||
pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT,
|
||||
PAGE_KERNEL_RO),
|
||||
UVMF_TLB_FLUSH))
|
||||
BUG();
|
||||
xen_pgd_pin(__pa(mm->pgd)); /* kernel */
|
||||
xen_pgd_pin(__pa(__user_pgd(mm->pgd))); /* user */
|
||||
mm->context.pinned = 1;
|
||||
@@ -106,12 +109,15 @@ void mm_unpin(struct mm_struct *mm)
|
||||
|
||||
xen_pgd_unpin(__pa(mm->pgd));
|
||||
xen_pgd_unpin(__pa(__user_pgd(mm->pgd)));
|
||||
BUG_ON(HYPERVISOR_update_va_mapping(
|
||||
(unsigned long)mm->pgd,
|
||||
pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL), 0));
|
||||
BUG_ON(HYPERVISOR_update_va_mapping(
|
||||
(unsigned long)__user_pgd(mm->pgd),
|
||||
pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT, PAGE_KERNEL), 0));
|
||||
if (HYPERVISOR_update_va_mapping(
|
||||
(unsigned long)mm->pgd,
|
||||
pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL), 0))
|
||||
BUG();
|
||||
if (HYPERVISOR_update_va_mapping(
|
||||
(unsigned long)__user_pgd(mm->pgd),
|
||||
pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT,
|
||||
PAGE_KERNEL), 0))
|
||||
BUG();
|
||||
mm_walk(mm, PAGE_KERNEL);
|
||||
xen_tlb_flush();
|
||||
mm->context.pinned = 0;
|
||||
@@ -127,43 +133,50 @@ void mm_pin_all(void)
|
||||
if (xen_feature(XENFEAT_writable_page_tables))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Allow uninterrupted access to the mm_unpinned list. We don't
|
||||
* actually take the mm_unpinned_lock as it is taken inside mm_pin().
|
||||
* All other CPUs must be at a safe point (e.g., in stop_machine
|
||||
* or offlined entirely).
|
||||
*/
|
||||
preempt_disable();
|
||||
while (!list_empty(&mm_unpinned))
|
||||
mm_pin(list_entry(mm_unpinned.next, struct mm_struct,
|
||||
context.unpinned));
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
void _arch_dup_mmap(struct mm_struct *mm)
|
||||
{
|
||||
if (!mm->context.pinned)
|
||||
mm_pin(mm);
|
||||
if (!mm->context.pinned)
|
||||
mm_pin(mm);
|
||||
}
|
||||
|
||||
void _arch_exit_mmap(struct mm_struct *mm)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
struct task_struct *tsk = current;
|
||||
|
||||
task_lock(tsk);
|
||||
task_lock(tsk);
|
||||
|
||||
/*
|
||||
* We aggressively remove defunct pgd from cr3. We execute unmap_vmas()
|
||||
* *much* faster this way, as no tlb flushes means bigger wrpt batches.
|
||||
*/
|
||||
if ( tsk->active_mm == mm )
|
||||
{
|
||||
tsk->active_mm = &init_mm;
|
||||
atomic_inc(&init_mm.mm_count);
|
||||
/*
|
||||
* We aggressively remove defunct pgd from cr3. We execute unmap_vmas()
|
||||
* *much* faster this way, as no tlb flushes means bigger wrpt batches.
|
||||
*/
|
||||
if (tsk->active_mm == mm) {
|
||||
tsk->active_mm = &init_mm;
|
||||
atomic_inc(&init_mm.mm_count);
|
||||
|
||||
switch_mm(mm, &init_mm, tsk);
|
||||
switch_mm(mm, &init_mm, tsk);
|
||||
|
||||
atomic_dec(&mm->mm_count);
|
||||
BUG_ON(atomic_read(&mm->mm_count) == 0);
|
||||
}
|
||||
atomic_dec(&mm->mm_count);
|
||||
BUG_ON(atomic_read(&mm->mm_count) == 0);
|
||||
}
|
||||
|
||||
task_unlock(tsk);
|
||||
task_unlock(tsk);
|
||||
|
||||
if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) &&
|
||||
!mm->context.has_foreign_mappings )
|
||||
mm_unpin(mm);
|
||||
if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) &&
|
||||
!mm->context.has_foreign_mappings )
|
||||
mm_unpin(mm);
|
||||
}
|
||||
|
||||
struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
|
||||
@@ -183,8 +196,9 @@ void pte_free(struct page *pte)
|
||||
unsigned long va = (unsigned long)__va(page_to_pfn(pte)<<PAGE_SHIFT);
|
||||
|
||||
if (!pte_write(*virt_to_ptep(va)))
|
||||
BUG_ON(HYPERVISOR_update_va_mapping(
|
||||
va, pfn_pte(page_to_pfn(pte), PAGE_KERNEL), 0));
|
||||
if (HYPERVISOR_update_va_mapping(
|
||||
va, pfn_pte(page_to_pfn(pte), PAGE_KERNEL), 0))
|
||||
BUG();
|
||||
|
||||
ClearPageForeign(pte);
|
||||
init_page_count(pte);
|
||||
|
||||
@@ -1267,7 +1267,7 @@ static void net_tx_action(unsigned long unused)
|
||||
|
||||
/* Check the remap error code. */
|
||||
if (unlikely(netbk_tx_check_mop(skb, &mop))) {
|
||||
printk(KERN_ALERT "#### netback grant fails\n");
|
||||
DPRINTK("netback grant failed.\n");
|
||||
skb_shinfo(skb)->nr_frags = 0;
|
||||
kfree_skb(skb);
|
||||
continue;
|
||||
|
||||
@@ -110,7 +110,6 @@ int xb_write(const void *data, unsigned len)
|
||||
/* Read indexes, then verify. */
|
||||
cons = intf->req_cons;
|
||||
prod = intf->req_prod;
|
||||
mb();
|
||||
if (!check_indexes(cons, prod)) {
|
||||
intf->req_cons = intf->req_prod = 0;
|
||||
return -EIO;
|
||||
@@ -122,15 +121,18 @@ int xb_write(const void *data, unsigned len)
|
||||
if (avail > len)
|
||||
avail = len;
|
||||
|
||||
/* Must write data /after/ reading the consumer index. */
|
||||
mb();
|
||||
|
||||
memcpy(dst, data, avail);
|
||||
data += avail;
|
||||
len -= avail;
|
||||
|
||||
/* Other side must not see new header until data is there. */
|
||||
/* Other side must not see new producer until data is there. */
|
||||
wmb();
|
||||
intf->req_prod += avail;
|
||||
|
||||
/* This implies mb() before other side sees interrupt. */
|
||||
/* Implies mb(): other side will see the updated producer. */
|
||||
notify_remote_via_evtchn(xen_store_evtchn);
|
||||
}
|
||||
|
||||
@@ -165,7 +167,6 @@ int xb_read(void *data, unsigned len)
|
||||
/* Read indexes, then verify. */
|
||||
cons = intf->rsp_cons;
|
||||
prod = intf->rsp_prod;
|
||||
mb();
|
||||
if (!check_indexes(cons, prod)) {
|
||||
intf->rsp_cons = intf->rsp_prod = 0;
|
||||
return -EIO;
|
||||
@@ -177,7 +178,7 @@ int xb_read(void *data, unsigned len)
|
||||
if (avail > len)
|
||||
avail = len;
|
||||
|
||||
/* We must read header before we read data. */
|
||||
/* Must read data /after/ reading the producer index. */
|
||||
rmb();
|
||||
|
||||
memcpy(data, src, avail);
|
||||
@@ -190,7 +191,7 @@ int xb_read(void *data, unsigned len)
|
||||
|
||||
pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
|
||||
|
||||
/* Implies mb(): they will see new header. */
|
||||
/* Implies mb(): other side will see the updated consumer. */
|
||||
notify_remote_via_evtchn(xen_store_evtchn);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,9 @@
|
||||
/* The native architecture */
|
||||
#define KEXEC_ARCH KEXEC_ARCH_386
|
||||
|
||||
/* We can also handle crash dumps from 64 bit kernel. */
|
||||
#define vmcore_elf_check_arch_cross(x) ((x)->e_machine == EM_X86_64)
|
||||
|
||||
#define MAX_NOTE_BYTES 1024
|
||||
|
||||
/* CPU does not save ss and esp on stack if execution is already
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
config SELECT_MEMORY_MODEL
|
||||
def_bool y
|
||||
depends on EXPERIMENTAL || ARCH_SELECT_MEMORY_MODEL
|
||||
|
||||
choice
|
||||
prompt "Memory model"
|
||||
depends on SELECT_MEMORY_MODEL
|
||||
default DISCONTIGMEM_MANUAL if ARCH_DISCONTIGMEM_DEFAULT
|
||||
default SPARSEMEM_MANUAL if ARCH_SPARSEMEM_DEFAULT
|
||||
default FLATMEM_MANUAL
|
||||
|
||||
config FLATMEM_MANUAL
|
||||
bool "Flat Memory"
|
||||
depends on !(ARCH_DISCONTIGMEM_ENABLE || ARCH_SPARSEMEM_ENABLE) || ARCH_FLATMEM_ENABLE
|
||||
help
|
||||
This option allows you to change some of the ways that
|
||||
Linux manages its memory internally. Most users will
|
||||
only have one option here: FLATMEM. This is normal
|
||||
and a correct option.
|
||||
|
||||
Some users of more advanced features like NUMA and
|
||||
memory hotplug may have different options here.
|
||||
DISCONTIGMEM is an more mature, better tested system,
|
||||
but is incompatible with memory hotplug and may suffer
|
||||
decreased performance over SPARSEMEM. If unsure between
|
||||
"Sparse Memory" and "Discontiguous Memory", choose
|
||||
"Discontiguous Memory".
|
||||
|
||||
If unsure, choose this option (Flat Memory) over any other.
|
||||
|
||||
config DISCONTIGMEM_MANUAL
|
||||
bool "Discontiguous Memory"
|
||||
depends on ARCH_DISCONTIGMEM_ENABLE
|
||||
help
|
||||
This option provides enhanced support for discontiguous
|
||||
memory systems, over FLATMEM. These systems have holes
|
||||
in their physical address spaces, and this option provides
|
||||
more efficient handling of these holes. However, the vast
|
||||
majority of hardware has quite flat address spaces, and
|
||||
can have degraded performance from extra overhead that
|
||||
this option imposes.
|
||||
|
||||
Many NUMA configurations will have this as the only option.
|
||||
|
||||
If unsure, choose "Flat Memory" over this option.
|
||||
|
||||
config SPARSEMEM_MANUAL
|
||||
bool "Sparse Memory"
|
||||
depends on ARCH_SPARSEMEM_ENABLE
|
||||
help
|
||||
This will be the only option for some systems, including
|
||||
memory hotplug systems. This is normal.
|
||||
|
||||
For many other systems, this will be an alternative to
|
||||
"Discontiguous Memory". This option provides some potential
|
||||
performance benefits, along with decreased code complexity,
|
||||
but it is newer, and more experimental.
|
||||
|
||||
If unsure, choose "Discontiguous Memory" or "Flat Memory"
|
||||
over this option.
|
||||
|
||||
endchoice
|
||||
|
||||
config DISCONTIGMEM
|
||||
def_bool y
|
||||
depends on (!SELECT_MEMORY_MODEL && ARCH_DISCONTIGMEM_ENABLE) || DISCONTIGMEM_MANUAL
|
||||
|
||||
config SPARSEMEM
|
||||
def_bool y
|
||||
depends on SPARSEMEM_MANUAL
|
||||
|
||||
config FLATMEM
|
||||
def_bool y
|
||||
depends on (!DISCONTIGMEM && !SPARSEMEM) || FLATMEM_MANUAL
|
||||
|
||||
config FLAT_NODE_MEM_MAP
|
||||
def_bool y
|
||||
depends on !SPARSEMEM
|
||||
|
||||
#
|
||||
# Both the NUMA code and DISCONTIGMEM use arrays of pg_data_t's
|
||||
# to represent different areas of memory. This variable allows
|
||||
# those dependencies to exist individually.
|
||||
#
|
||||
config NEED_MULTIPLE_NODES
|
||||
def_bool y
|
||||
depends on DISCONTIGMEM || NUMA
|
||||
|
||||
config HAVE_MEMORY_PRESENT
|
||||
def_bool y
|
||||
depends on ARCH_HAVE_MEMORY_PRESENT || SPARSEMEM
|
||||
|
||||
#
|
||||
# SPARSEMEM_EXTREME (which is the default) does some bootmem
|
||||
# allocations when memory_present() is called. If this can not
|
||||
# be done on your architecture, select this option. However,
|
||||
# statically allocating the mem_section[] array can potentially
|
||||
# consume vast quantities of .bss, so be careful.
|
||||
#
|
||||
# This option will also potentially produce smaller runtime code
|
||||
# with gcc 3.4 and later.
|
||||
#
|
||||
config SPARSEMEM_STATIC
|
||||
def_bool n
|
||||
|
||||
#
|
||||
# Architectecture platforms which require a two level mem_section in SPARSEMEM
|
||||
# must select this option. This is usually for architecture platforms with
|
||||
# an extremely sparse physical address space.
|
||||
#
|
||||
config SPARSEMEM_EXTREME
|
||||
def_bool y
|
||||
depends on SPARSEMEM && !SPARSEMEM_STATIC
|
||||
|
||||
# eventually, we can have this option just 'select SPARSEMEM'
|
||||
config MEMORY_HOTPLUG
|
||||
bool "Allow for memory hot-add"
|
||||
depends on SPARSEMEM && HOTPLUG && !SOFTWARE_SUSPEND && ARCH_ENABLE_MEMORY_HOTPLUG
|
||||
depends on (IA64 || X86 || PPC64)
|
||||
|
||||
comment "Memory hotplug is currently incompatible with Software Suspend"
|
||||
depends on SPARSEMEM && HOTPLUG && SOFTWARE_SUSPEND
|
||||
|
||||
# Heavily threaded applications may benefit from splitting the mm-wide
|
||||
# page_table_lock, so that faults on different parts of the user address
|
||||
# space can be handled with less contention: split it at this NR_CPUS.
|
||||
# Default to 4 for wider testing, though 8 might be more appropriate.
|
||||
# ARM's adjust_pte (unused if VIPT) depends on mm-wide page_table_lock.
|
||||
# PA-RISC 7xxx's spinlock_t would enlarge struct page from 32 to 44 bytes.
|
||||
# XEN on x86 architecture uses the mapping field on pagetable pages to store a
|
||||
# pointer to the destructor. This conflicts with pte_lock_deinit().
|
||||
#
|
||||
config SPLIT_PTLOCK_CPUS
|
||||
int
|
||||
default "4096" if ARM && !CPU_CACHE_VIPT
|
||||
default "4096" if PARISC && !PA20
|
||||
default "4096" if X86_XEN || X86_64_XEN
|
||||
default "4"
|
||||
|
||||
#
|
||||
# support for page migration
|
||||
#
|
||||
config MIGRATION
|
||||
bool "Page migration"
|
||||
def_bool y
|
||||
depends on NUMA
|
||||
help
|
||||
Allows the migration of the physical location of pages of processes
|
||||
while the virtual addresses are not changed. This is useful for
|
||||
example on NUMA systems to put pages nearer to the processors accessing
|
||||
the page.
|
||||
|
||||
config RESOURCES_64BIT
|
||||
bool "64 bit Memory and IO resources (EXPERIMENTAL)" if (!64BIT && EXPERIMENTAL)
|
||||
default 64BIT
|
||||
help
|
||||
This option allows memory and IO resources to be 64 bit.
|
||||
@@ -0,0 +1,30 @@
|
||||
From: Andrew Morton <akpm@linux-foundation.org>
|
||||
|
||||
In file included from arch/i386/kernel/setup.c:46:
|
||||
include/linux/crash_dump.h:19:36: warning: extra tokens at end of #ifndef directive
|
||||
|
||||
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
Cc: Andi Kleen <ak@suse.de>
|
||||
Cc: Horms <horms@verge.net.au>
|
||||
Cc: Ian Campbell <ian.campbell@xensource.com>
|
||||
Cc: Magnus Damm <magnus.damm@gmail.com>
|
||||
Cc: Vivek Goyal <vgoyal@in.ibm.com>
|
||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
---
|
||||
|
||||
include/linux/crash_dump.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff -puN include/linux/crash_dump.h~allow-i386-crash-kernels-to-handle-x86_64-dumps-fix include/linux/crash_dump.h
|
||||
--- a/include/linux/crash_dump.h~allow-i386-crash-kernels-to-handle-x86_64-dumps-fix
|
||||
+++ a/include/linux/crash_dump.h
|
||||
@@ -16,7 +16,7 @@ extern struct proc_dir_entry *proc_vmcor
|
||||
|
||||
/* Architecture code defines this if there are other possible ELF
|
||||
* machine types, e.g. on bi-arch capable hardware. */
|
||||
-#ifndef vmcore_elf_check_arch_cross(x)
|
||||
+#ifndef vmcore_elf_check_arch_cross
|
||||
#define vmcore_elf_check_arch_cross(x) 0
|
||||
#endif
|
||||
|
||||
_
|
||||
@@ -0,0 +1,66 @@
|
||||
From: Ian Campbell <ian.campbell@xensource.com>
|
||||
|
||||
The specific case I am encountering is kdump under Xen with a 64 bit
|
||||
hypervisor and 32 bit kernel/userspace. The dump created is 64 bit due to
|
||||
the hypervisor but the dump kernel is 32 bit for maximum compatibility.
|
||||
|
||||
It's possibly less likely to be useful in a purely native scenario but I
|
||||
see no reason to disallow it.
|
||||
|
||||
Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
|
||||
Acked-by: Vivek Goyal <vgoyal@in.ibm.com>
|
||||
Cc: Horms <horms@verge.net.au>
|
||||
Cc: Magnus Damm <magnus.damm@gmail.com>
|
||||
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
Cc: Andi Kleen <ak@suse.de>
|
||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
---
|
||||
|
||||
fs/proc/vmcore.c | 2 +-
|
||||
include/asm-i386/kexec.h | 3 +++
|
||||
include/linux/crash_dump.h | 8 ++++++++
|
||||
3 files changed, 12 insertions(+), 1 deletion(-)
|
||||
|
||||
diff -puN fs/proc/vmcore.c~allow-i386-crash-kernels-to-handle-x86_64-dumps fs/proc/vmcore.c
|
||||
--- a/fs/proc/vmcore.c~allow-i386-crash-kernels-to-handle-x86_64-dumps
|
||||
+++ a/fs/proc/vmcore.c
|
||||
@@ -514,7 +514,7 @@ static int __init parse_crash_elf64_head
|
||||
/* Do some basic Verification. */
|
||||
if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
|
||||
(ehdr.e_type != ET_CORE) ||
|
||||
- !elf_check_arch(&ehdr) ||
|
||||
+ !vmcore_elf_check_arch(&ehdr) ||
|
||||
ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
|
||||
ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
|
||||
ehdr.e_version != EV_CURRENT ||
|
||||
diff -puN include/asm-i386/kexec.h~allow-i386-crash-kernels-to-handle-x86_64-dumps include/asm-i386/kexec.h
|
||||
--- a/include/asm-i386/kexec.h~allow-i386-crash-kernels-to-handle-x86_64-dumps
|
||||
+++ a/include/asm-i386/kexec.h
|
||||
@@ -47,6 +47,9 @@
|
||||
/* The native architecture */
|
||||
#define KEXEC_ARCH KEXEC_ARCH_386
|
||||
|
||||
+/* We can also handle crash dumps from 64 bit kernel. */
|
||||
+#define vmcore_elf_check_arch_cross(x) ((x)->e_machine == EM_X86_64)
|
||||
+
|
||||
#define MAX_NOTE_BYTES 1024
|
||||
|
||||
/* CPU does not save ss and esp on stack if execution is already
|
||||
diff -puN include/linux/crash_dump.h~allow-i386-crash-kernels-to-handle-x86_64-dumps include/linux/crash_dump.h
|
||||
--- a/include/linux/crash_dump.h~allow-i386-crash-kernels-to-handle-x86_64-dumps
|
||||
+++ a/include/linux/crash_dump.h
|
||||
@@ -14,5 +14,13 @@ extern ssize_t copy_oldmem_page(unsigned
|
||||
extern const struct file_operations proc_vmcore_operations;
|
||||
extern struct proc_dir_entry *proc_vmcore;
|
||||
|
||||
+/* Architecture code defines this if there are other possible ELF
|
||||
+ * machine types, e.g. on bi-arch capable hardware. */
|
||||
+#ifndef vmcore_elf_check_arch_cross(x)
|
||||
+#define vmcore_elf_check_arch_cross(x) 0
|
||||
+#endif
|
||||
+
|
||||
+#define vmcore_elf_check_arch(x) (elf_check_arch(x) || vmcore_elf_check_arch_cross(x))
|
||||
+
|
||||
#endif /* CONFIG_CRASH_DUMP */
|
||||
#endif /* LINUX_CRASHDUMP_H */
|
||||
_
|
||||
@@ -1,11 +0,0 @@
|
||||
--- pristine-linux-2.6.18/include/asm-i386/elf.h 2006-09-20 04:42:06.000000000 +0100
|
||||
+++ linux-2.6.18-xen/include/asm-i386/elf.h 2007-03-14 16:42:30.000000000 +0000
|
||||
@@ -36,7 +36,7 @@
|
||||
* This is used to ensure we don't load something for the wrong architecture.
|
||||
*/
|
||||
#define elf_check_arch(x) \
|
||||
- (((x)->e_machine == EM_386) || ((x)->e_machine == EM_486))
|
||||
+ (((x)->e_machine == EM_386) || ((x)->e_machine == EM_486) || ((x)->e_machine == EM_X86_64))
|
||||
|
||||
/*
|
||||
* These are used to set parameters in the core dumps.
|
||||
@@ -19,4 +19,5 @@ x86-elfnote-as-preprocessor-macro.patch
|
||||
fixaddr-top.patch
|
||||
git-c06cb8b1c4d25e5b4d7a2d7c2462619de1e0dbc4.patch
|
||||
softlockup-no-idle-hz.patch
|
||||
crash-kernel-32-on-64.patch
|
||||
allow-i386-crash-kernels-to-handle-x86_64-dumps.patch
|
||||
allow-i386-crash-kernels-to-handle-x86_64-dumps-fix.patch
|
||||
@@ -23,6 +23,11 @@ LDFLAGS += $(shell getconf LFS_LDFLAGS)
|
||||
CFLAGS-$(CONFIG_X86_32) += $(call cc-option,$(CC),-mno-tls-direct-seg-refs)
|
||||
CFLAGS += $(CFLAGS-y)
|
||||
|
||||
# Require GCC v3.4+ (to avoid issues with alignment constraints in Xen headers)
|
||||
ifeq ($(CONFIG_X86)$(call cc-ver,$(CC),0x030400),yn)
|
||||
$(error Xen tools require at least gcc-3.4)
|
||||
endif
|
||||
|
||||
%.opic: %.c
|
||||
$(CC) $(CPPFLAGS) -DPIC $(CFLAGS) -fPIC -c -o $@ $<
|
||||
|
||||
|
||||
@@ -1057,6 +1057,7 @@ int tdqcow_queue_write(struct disk_driver *dd, uint64_t sector,
|
||||
index_in_cluster+n);
|
||||
if (!cluster_offset) {
|
||||
DPRINTF("Ooops, no write cluster offset!\n");
|
||||
aio_unlock(s, sector);
|
||||
return cb(dd, -EIO, sector, nb_sectors, id, private);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ SUBDIRS += hvmloader
|
||||
|
||||
.PHONY: all
|
||||
all:
|
||||
@set -e; if [ $$((`bcc -v 2>&1 | grep version | cut -d' ' -f 3 | awk -F. '{ printf "0x%02x%02x%02x", $$1, $$2, $$3}'`)) -lt $$((0x00100e)) ] ; then \
|
||||
@set -e; if [ $$((`( bcc -v 2>&1 | grep version || echo 0.0.0 ) | cut -d' ' -f 3 | awk -F. '{ printf "0x%02x%02x%02x", $$1, $$2, $$3}'`)) -lt $$((0x00100e)) ] ; then \
|
||||
echo "***********************************************************"; \
|
||||
echo "Require dev86 package version >= 0.16.14 to build firmware!"; \
|
||||
echo "(visit http://www.cix.co.uk/~mayday for more information)"; \
|
||||
|
||||
@@ -17,157 +17,129 @@
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <elf.h>
|
||||
#ifdef __sun__
|
||||
#include <sys/machelf.h>
|
||||
#endif
|
||||
|
||||
#include <xen/hvm/e820.h>
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "../rombios/32bit/32bitbios_flat.h"
|
||||
#include "../rombios/32bit/jumptable.h"
|
||||
|
||||
|
||||
/*
|
||||
* relocate ELF file of type ET_REL
|
||||
*/
|
||||
static int relocate_elf(unsigned char *elfarray) {
|
||||
/* Relocate ELF file of type ET_REL */
|
||||
static void relocate_elf(char *elfarray)
|
||||
{
|
||||
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray;
|
||||
Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff];
|
||||
int i;
|
||||
Elf32_Sym *syms, *sym;
|
||||
Elf32_Rel *rels;
|
||||
char *code;
|
||||
uint32_t *loc, fix;
|
||||
int i, j;
|
||||
|
||||
if (ehdr->e_type != ET_REL) {
|
||||
printf("Not a relocatable BIOS object file. Has type %d, need %d\n",
|
||||
ehdr->e_type, ET_REL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < ehdr->e_shnum; i++)
|
||||
for ( i = 0; i < ehdr->e_shnum; i++ )
|
||||
shdr[i].sh_addr = (Elf32_Addr)&elfarray[shdr[i].sh_offset];
|
||||
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
if (shdr[i].sh_type == SHT_REL) {
|
||||
Elf32_Shdr *targetsec = (Elf32_Shdr *)&(shdr[shdr[i].sh_info]);
|
||||
Elf32_Shdr *symtabsec = (Elf32_Shdr *)&(shdr[shdr[i].sh_link]);
|
||||
Elf32_Sym *syms = (Elf32_Sym *)symtabsec->sh_addr;
|
||||
Elf32_Rel *rels = (Elf32_Rel *)shdr[i].sh_addr;
|
||||
unsigned char *code = (unsigned char *)targetsec->sh_addr;
|
||||
int j;
|
||||
for ( i = 0; i < ehdr->e_shnum; i++ )
|
||||
{
|
||||
if ( shdr[i].sh_type == SHT_RELA )
|
||||
printf("Unsupported section type SHT_RELA\n");
|
||||
|
||||
/* must not have been stripped */
|
||||
if (shdr[i].sh_size == 0)
|
||||
return -6;
|
||||
if ( shdr[i].sh_type != SHT_REL )
|
||||
continue;
|
||||
|
||||
for (j = 0; j < shdr[i].sh_size / sizeof(Elf32_Rel); j++) {
|
||||
int idx = ELF32_R_SYM(rels[j].r_info);
|
||||
Elf32_Sym *symbol = &syms[idx];
|
||||
uint32_t *loc = (uint32_t *)&code[rels[j].r_offset];
|
||||
uint32_t fix = shdr[symbol->st_shndx].sh_addr +
|
||||
symbol->st_value;
|
||||
syms = (Elf32_Sym *)shdr[shdr[i].sh_link].sh_addr;
|
||||
rels = (Elf32_Rel *)shdr[i].sh_addr;
|
||||
code = (char *)shdr[shdr[i].sh_info].sh_addr;
|
||||
|
||||
switch (ELF32_R_TYPE(rels[j].r_info)) {
|
||||
case R_386_PC32:
|
||||
*loc += (fix - (uint32_t)loc);
|
||||
break;
|
||||
for ( j = 0; j < shdr[i].sh_size / sizeof(Elf32_Rel); j++ )
|
||||
{
|
||||
sym = &syms[ELF32_R_SYM(rels[j].r_info)];
|
||||
loc = (uint32_t *)&code[rels[j].r_offset];
|
||||
fix = shdr[sym->st_shndx].sh_addr + sym->st_value;
|
||||
|
||||
case R_386_32:
|
||||
*loc += fix;
|
||||
break;
|
||||
}
|
||||
switch ( ELF32_R_TYPE(rels[j].r_info) )
|
||||
{
|
||||
case R_386_PC32:
|
||||
*loc += fix - (uint32_t)loc;
|
||||
break;
|
||||
|
||||
case R_386_32:
|
||||
*loc += fix;
|
||||
break;
|
||||
}
|
||||
} else if (shdr[i].sh_type == SHT_RELA) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* scan the rombios for the destination of the jumptable */
|
||||
static char* get_jump_table_start(void)
|
||||
/* Scan the rombios for the destination of the jump table. */
|
||||
static char *get_jump_table_start(void)
|
||||
{
|
||||
char *bios_mem;
|
||||
|
||||
for ( bios_mem = (char *)ROMBIOS_BEGIN;
|
||||
bios_mem != (char *)ROMBIOS_END;
|
||||
bios_mem++ ) {
|
||||
if (strncmp(bios_mem, "___JMPT", 7) == 0)
|
||||
bios_mem++ )
|
||||
if ( !strncmp(bios_mem, "___JMPT", 7) )
|
||||
return bios_mem;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* copy relocated jumptable into the rombios */
|
||||
static int copy_jumptable(unsigned char *elfarray)
|
||||
/* Copy relocated jumptable into the rombios. */
|
||||
static void copy_jumptable(char *elfarray)
|
||||
{
|
||||
int rc = 0;
|
||||
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray;
|
||||
Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff];
|
||||
Elf32_Shdr *shdr_strings = (Elf32_Shdr *)&shdr[ehdr->e_shstrndx];
|
||||
char *secstrings = (char *)&elfarray[shdr_strings->sh_offset];
|
||||
uint32_t *rombiosjumptable = (uint32_t *)get_jump_table_start();
|
||||
uint32_t *biosjumptable = NULL;
|
||||
char *secstrings = &elfarray[shdr[ehdr->e_shstrndx].sh_offset];
|
||||
char *jump_table = get_jump_table_start();
|
||||
int i;
|
||||
|
||||
if (rombiosjumptable == NULL) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* find the section with the jump table and copy to lower BIOS memory */
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
if (!strcmp(JUMPTABLE_SECTION_NAME, secstrings + shdr[i].sh_name)) {
|
||||
uint32_t biosjumptableentries;
|
||||
biosjumptable = (uint32_t *)shdr[i].sh_addr;
|
||||
biosjumptableentries = shdr[i].sh_size / 4;
|
||||
for (int j = 0; j < biosjumptableentries; j++) {
|
||||
rombiosjumptable[j] = biosjumptable[j];
|
||||
if (biosjumptable[j] == 0 &&
|
||||
j < (biosjumptableentries - 1)) {
|
||||
printf("WARNING: jumptable entry %d is NULL!\n",j);
|
||||
}
|
||||
}
|
||||
/* Find the section with the jump table and copy to lower BIOS memory. */
|
||||
for ( i = 0; i < ehdr->e_shnum; i++ )
|
||||
if ( !strcmp(JUMPTABLE_SECTION_NAME, secstrings + shdr[i].sh_name) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (biosjumptable == NULL) {
|
||||
if ( i == ehdr->e_shnum )
|
||||
{
|
||||
printf("Could not find " JUMPTABLE_SECTION_NAME " section in file.\n");
|
||||
rc = -4;
|
||||
return;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if ( jump_table == NULL )
|
||||
{
|
||||
printf("Could not find jump table in file.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(jump_table, (char *)shdr[i].sh_addr, shdr[i].sh_size);
|
||||
}
|
||||
|
||||
static int relocate_32bitbios(unsigned char *elfarray, uint32_t elfarraysize)
|
||||
static void relocate_32bitbios(char *elfarray, uint32_t elfarraysize)
|
||||
{
|
||||
int rc = 0;
|
||||
uint32_t mask = (64 * 1024) - 1;
|
||||
uint32_t to_malloc = (elfarraysize + mask) & ~mask; /* round to 64kb */
|
||||
unsigned char *highbiosarea;
|
||||
char *highbiosarea;
|
||||
|
||||
highbiosarea = (unsigned char *)(long)
|
||||
e820_malloc((uint64_t)to_malloc,
|
||||
E820_RESERVED,
|
||||
(uint64_t)0xffffffff);
|
||||
|
||||
if (highbiosarea != 0) {
|
||||
memcpy(highbiosarea, elfarray, elfarraysize);
|
||||
rc = relocate_elf(highbiosarea);
|
||||
if (rc == 0) {
|
||||
rc = copy_jumptable(highbiosarea);
|
||||
}
|
||||
} else {
|
||||
rc = -5;
|
||||
highbiosarea = (char *)(long)
|
||||
e820_malloc((elfarraysize + mask) & ~mask, /* round to 64kb */
|
||||
E820_RESERVED,
|
||||
(uint64_t)0xffffffff);
|
||||
if ( highbiosarea == NULL )
|
||||
{
|
||||
printf("No available memory for BIOS high memory area\n");
|
||||
return;
|
||||
}
|
||||
|
||||
return rc;
|
||||
memcpy(highbiosarea, elfarray, elfarraysize);
|
||||
relocate_elf(highbiosarea);
|
||||
copy_jumptable(highbiosarea);
|
||||
}
|
||||
|
||||
int highbios_setup(void)
|
||||
void highbios_setup(void)
|
||||
{
|
||||
return relocate_32bitbios((unsigned char *)highbios_array,
|
||||
sizeof(highbios_array));
|
||||
relocate_32bitbios((char *)highbios_array, sizeof(highbios_array));
|
||||
}
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "ssdt_tpm.h"
|
||||
#include "../config.h"
|
||||
#include "../util.h"
|
||||
#include <xen/hvm/e820.h>
|
||||
|
||||
#define align16(sz) (((sz) + 15) & ~15)
|
||||
#define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "pci_regs.h"
|
||||
#include <xen/version.h>
|
||||
#include <xen/hvm/params.h>
|
||||
#include <xen/hvm/e820.h>
|
||||
|
||||
/* memory map */
|
||||
#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
|
||||
@@ -297,25 +296,57 @@ static void pci_setup(void)
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int must_load_nic(void)
|
||||
/*
|
||||
* If the network card is in the boot order, load the Etherboot option ROM.
|
||||
* Read the boot order bytes from CMOS and check if any of them are 0x4.
|
||||
*/
|
||||
static int must_load_nic(void)
|
||||
{
|
||||
/* If the network card is in the boot order, load the Etherboot
|
||||
* option ROM. Read the boot order bytes from CMOS and check
|
||||
* if any of them are 0x4. */
|
||||
uint8_t boot_order;
|
||||
|
||||
/* Read CMOS register 0x3d (boot choices 0 and 1) */
|
||||
outb(0x70, 0x3d);
|
||||
boot_order = inb(0x71);
|
||||
if ( (boot_order & 0xf) == 0x4 || (boot_order & 0xf0) == 0x40 )
|
||||
/* Read CMOS register 0x3d (boot choices 0 and 1). */
|
||||
boot_order = cmos_inb(0x3d);
|
||||
if ( ((boot_order & 0xf) == 0x4) || ((boot_order & 0xf0) == 0x40) )
|
||||
return 1;
|
||||
/* Read CMOS register 0x38 (boot choice 2 and FDD test flag) */
|
||||
outb(0x70, 0x38);
|
||||
boot_order = inb(0x71);
|
||||
if ( (boot_order & 0xf0) == 0x40 )
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
/* Read CMOS register 0x38 (boot choice 2 and FDD test flag). */
|
||||
boot_order = cmos_inb(0x38);
|
||||
return ((boot_order & 0xf0) == 0x40);
|
||||
}
|
||||
|
||||
/* Replace possibly erroneous memory-size CMOS fields with correct values. */
|
||||
static void cmos_write_memory_size(void)
|
||||
{
|
||||
struct e820entry *map = E820_MAP;
|
||||
int i, nr = *E820_MAP_NR;
|
||||
uint32_t base_mem = 640, ext_mem = 0, alt_mem = 0;
|
||||
|
||||
for ( i = 0; i < nr; i++ )
|
||||
if ( (map[i].addr >= 0x100000) && (map[i].type == E820_RAM) )
|
||||
break;
|
||||
|
||||
if ( i != nr )
|
||||
{
|
||||
alt_mem = ext_mem = map[i].addr + map[i].size;
|
||||
ext_mem = (ext_mem > 0x0100000) ? (ext_mem - 0x0100000) >> 10 : 0;
|
||||
if ( ext_mem > 0xffff )
|
||||
ext_mem = 0xffff;
|
||||
alt_mem = (alt_mem > 0x1000000) ? (alt_mem - 0x1000000) >> 16 : 0;
|
||||
}
|
||||
|
||||
/* All BIOSes: conventional memory (640kB). */
|
||||
cmos_outb(0x15, (uint8_t)(base_mem >> 0));
|
||||
cmos_outb(0x16, (uint8_t)(base_mem >> 8));
|
||||
|
||||
/* All BIOSes: extended memory (1kB chunks above 1MB). */
|
||||
cmos_outb(0x17, (uint8_t)( ext_mem >> 0));
|
||||
cmos_outb(0x18, (uint8_t)( ext_mem >> 8));
|
||||
cmos_outb(0x30, (uint8_t)( ext_mem >> 0));
|
||||
cmos_outb(0x31, (uint8_t)( ext_mem >> 8));
|
||||
|
||||
/* Some BIOSes: alternative extended memory (64kB chunks above 16MB). */
|
||||
cmos_outb(0x34, (uint8_t)( alt_mem >> 0));
|
||||
cmos_outb(0x35, (uint8_t)( alt_mem >> 8));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
@@ -366,6 +397,8 @@ int main(void)
|
||||
ASSERT((ACPI_PHYSICAL_ADDRESS + acpi_sz) <= 0xF0000);
|
||||
}
|
||||
|
||||
cmos_write_memory_size();
|
||||
|
||||
if ( !check_amd() )
|
||||
{
|
||||
printf("Loading VMXAssist ...\n");
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <xen/version.h>
|
||||
#include <xen/hvm/e820.h>
|
||||
#include "smbios.h"
|
||||
#include "smbios_types.h"
|
||||
#include "util.h"
|
||||
@@ -129,47 +128,32 @@ write_smbios_tables(void *start,
|
||||
return (size_t)((char *)p - (char *)start);
|
||||
}
|
||||
|
||||
/* This tries to figure out how much pseudo-physical memory (in MB)
|
||||
is allocated to the current domU.
|
||||
|
||||
It iterates through the e820 table, adding up the 'usable' and
|
||||
'reserved' entries and rounding up to the nearest MB.
|
||||
|
||||
The e820map is not at e820 in hvmloader, so this uses the
|
||||
E820_MAP_* constants from e820.h to pick it up where libxenguest
|
||||
left it.
|
||||
*/
|
||||
/* Calculate how much pseudo-physical memory (in MB) is allocated to us. */
|
||||
static uint64_t
|
||||
get_memsize(void)
|
||||
{
|
||||
struct e820entry *map = NULL;
|
||||
uint8_t num_entries = 0;
|
||||
struct e820entry *map = E820_MAP;
|
||||
uint8_t num_entries = *E820_MAP_NR;
|
||||
uint64_t memsize = 0;
|
||||
uint8_t i;
|
||||
|
||||
map = (struct e820entry *) (E820_MAP_PAGE + E820_MAP_OFFSET);
|
||||
num_entries = *((uint8_t *) (E820_MAP_PAGE + E820_MAP_NR_OFFSET));
|
||||
|
||||
/* walk through e820map, ignoring any entries that aren't marked
|
||||
as usable or reserved. */
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Walk through e820map, ignoring any entries that aren't marked
|
||||
* as usable or reserved.
|
||||
*/
|
||||
for ( i = 0; i < num_entries; i++ )
|
||||
{
|
||||
if (map->type == E820_RAM || map->type == E820_RESERVED)
|
||||
if ( (map->type == E820_RAM) || (map->type == E820_RESERVED) )
|
||||
memsize += map->size;
|
||||
map++;
|
||||
}
|
||||
|
||||
/* Round up to the nearest MB. The user specifies domU
|
||||
pseudo-physical memory in megabytes, so not doing this
|
||||
could easily lead to reporting one less MB than the user
|
||||
specified. */
|
||||
if ( memsize & ((1<<20)-1) )
|
||||
memsize = (memsize >> 20) + 1;
|
||||
else
|
||||
memsize = (memsize >> 20);
|
||||
|
||||
return memsize;
|
||||
/*
|
||||
* Round up to the nearest MB. The user specifies domU pseudo-physical
|
||||
* memory in megabytes, so not doing this could easily lead to reporting
|
||||
* one less MB than the user specified.
|
||||
*/
|
||||
return (memsize + (1 << 20) - 1) >> 20;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -27,17 +27,17 @@
|
||||
|
||||
void outb(uint16_t addr, uint8_t val)
|
||||
{
|
||||
__asm__ __volatile__ ( "outb %%al, %%dx" :: "d"(addr), "a"(val) );
|
||||
__asm__ __volatile__ ( "outb %%al, %%dx" : : "d" (addr), "a" (val) );
|
||||
}
|
||||
|
||||
void outw(uint16_t addr, uint16_t val)
|
||||
{
|
||||
__asm__ __volatile__ ( "outw %%ax, %%dx" :: "d"(addr), "a"(val) );
|
||||
__asm__ __volatile__ ( "outw %%ax, %%dx" : : "d" (addr), "a" (val) );
|
||||
}
|
||||
|
||||
void outl(uint16_t addr, uint32_t val)
|
||||
{
|
||||
__asm__ __volatile__ ( "outl %%eax, %%dx" :: "d"(addr), "a"(val) );
|
||||
__asm__ __volatile__ ( "outl %%eax, %%dx" : : "d" (addr), "a" (val) );
|
||||
}
|
||||
|
||||
uint8_t inb(uint16_t addr)
|
||||
@@ -61,6 +61,18 @@ uint32_t inl(uint16_t addr)
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t cmos_inb(uint8_t idx)
|
||||
{
|
||||
outb(0x70, idx);
|
||||
return inb(0x71);
|
||||
}
|
||||
|
||||
void cmos_outb(uint8_t idx, uint8_t val)
|
||||
{
|
||||
outb(0x70, idx);
|
||||
outb(0x71, val);
|
||||
}
|
||||
|
||||
char *itoa(char *a, unsigned int i)
|
||||
{
|
||||
unsigned int _i = i, x = 0;
|
||||
@@ -280,9 +292,6 @@ uuid_to_string(char *dest, uint8_t *uuid)
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
#include <xen/hvm/e820.h>
|
||||
#define E820_MAP_NR ((unsigned char *)E820_MAP_PAGE + E820_MAP_NR_OFFSET)
|
||||
#define E820_MAP ((struct e820entry *)(E820_MAP_PAGE + E820_MAP_OFFSET))
|
||||
uint64_t e820_malloc(uint64_t size, uint32_t type, uint64_t mask)
|
||||
{
|
||||
uint64_t addr = 0;
|
||||
|
||||
@@ -26,6 +26,10 @@ uint8_t inb(uint16_t addr);
|
||||
uint16_t inw(uint16_t addr);
|
||||
uint32_t inl(uint16_t addr);
|
||||
|
||||
/* CMOS access */
|
||||
uint8_t cmos_inb(uint8_t idx);
|
||||
void cmos_outb(uint8_t idx, uint8_t val);
|
||||
|
||||
/* APIC access */
|
||||
uint32_t ioapic_read(uint32_t reg);
|
||||
void ioapic_write(uint32_t reg, uint32_t val);
|
||||
@@ -78,9 +82,13 @@ int vprintf(const char *fmt, va_list ap);
|
||||
/* Allocate region of specified type in the e820 table. */
|
||||
uint64_t e820_malloc(uint64_t size, uint32_t type, uint64_t mask);
|
||||
|
||||
/* Prepare the 32bit BIOS */
|
||||
int highbios_setup(void);
|
||||
/* General e820 access. */
|
||||
#include <xen/hvm/e820.h>
|
||||
#define E820_MAP_NR ((unsigned char *)E820_MAP_PAGE + E820_MAP_NR_OFFSET)
|
||||
#define E820_MAP ((struct e820entry *)(E820_MAP_PAGE + E820_MAP_OFFSET))
|
||||
|
||||
/* Prepare the 32bit BIOS */
|
||||
void highbios_setup(void);
|
||||
|
||||
#define isdigit(c) ((c) >= '0' && (c) <= '9')
|
||||
|
||||
|
||||
@@ -4196,178 +4196,86 @@ ASM_END
|
||||
case 0xe8:
|
||||
switch(regs.u.r8.al)
|
||||
{
|
||||
case 0x20: // coded by osmaker aka K.J.
|
||||
if(regs.u.r32.edx == 0x534D4150) /* SMAP */
|
||||
{
|
||||
#ifdef HVMASSIST
|
||||
if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
|
||||
Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
|
||||
case 0x20: {
|
||||
Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
|
||||
|
||||
if (regs.u.r16.bx + 0x14 <= e820_table_size) {
|
||||
memcpyb(ES, regs.u.r16.di,
|
||||
0xe000, 0x10 + regs.u.r16.bx, 0x14);
|
||||
}
|
||||
regs.u.r32.ebx += 0x14;
|
||||
if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
|
||||
regs.u.r32.ebx = 0;
|
||||
regs.u.r32.eax = 0x534D4150;
|
||||
regs.u.r32.ecx = 0x14;
|
||||
CLEAR_CF();
|
||||
return;
|
||||
} else if (regs.u.r16.bx == 1) {
|
||||
extended_memory_size = inb_cmos(0x35);
|
||||
extended_memory_size <<= 8;
|
||||
extended_memory_size |= inb_cmos(0x34);
|
||||
extended_memory_size *= 64;
|
||||
if (extended_memory_size > 0x3bc000) // greater than EFF00000???
|
||||
{
|
||||
extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
|
||||
}
|
||||
extended_memory_size *= 1024;
|
||||
extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
|
||||
if (regs.u.r32.edx != 0x534D4150) /* SMAP */
|
||||
goto int15_unimplemented;
|
||||
|
||||
if (extended_memory_size <= 15728640)
|
||||
{
|
||||
extended_memory_size = inb_cmos(0x31);
|
||||
extended_memory_size <<= 8;
|
||||
extended_memory_size |= inb_cmos(0x30);
|
||||
extended_memory_size *= 1024;
|
||||
}
|
||||
|
||||
write_word(ES, regs.u.r16.di, 0x0000);
|
||||
write_word(ES, regs.u.r16.di+2, 0x0010);
|
||||
write_word(ES, regs.u.r16.di+4, 0x0000);
|
||||
write_word(ES, regs.u.r16.di+6, 0x0000);
|
||||
|
||||
write_word(ES, regs.u.r16.di+8, extended_memory_size);
|
||||
extended_memory_size >>= 16;
|
||||
write_word(ES, regs.u.r16.di+10, extended_memory_size);
|
||||
extended_memory_size >>= 16;
|
||||
write_word(ES, regs.u.r16.di+12, extended_memory_size);
|
||||
extended_memory_size >>= 16;
|
||||
write_word(ES, regs.u.r16.di+14, extended_memory_size);
|
||||
|
||||
write_word(ES, regs.u.r16.di+16, 0x1);
|
||||
write_word(ES, regs.u.r16.di+18, 0x0);
|
||||
|
||||
regs.u.r32.ebx = 0;
|
||||
regs.u.r32.eax = 0x534D4150;
|
||||
regs.u.r32.ecx = 0x14;
|
||||
CLEAR_CF();
|
||||
return;
|
||||
} else { /* AX=E820, DX=534D4150, BX unrecognized */
|
||||
goto int15_unimplemented;
|
||||
}
|
||||
#else
|
||||
switch(regs.u.r16.bx)
|
||||
{
|
||||
case 0:
|
||||
write_word(ES, regs.u.r16.di, 0x00);
|
||||
write_word(ES, regs.u.r16.di+2, 0x00);
|
||||
write_word(ES, regs.u.r16.di+4, 0x00);
|
||||
write_word(ES, regs.u.r16.di+6, 0x00);
|
||||
|
||||
write_word(ES, regs.u.r16.di+8, 0xFC00);
|
||||
write_word(ES, regs.u.r16.di+10, 0x0009);
|
||||
write_word(ES, regs.u.r16.di+12, 0x0000);
|
||||
write_word(ES, regs.u.r16.di+14, 0x0000);
|
||||
|
||||
write_word(ES, regs.u.r16.di+16, 0x1);
|
||||
write_word(ES, regs.u.r16.di+18, 0x0);
|
||||
|
||||
regs.u.r32.ebx = 1;
|
||||
|
||||
regs.u.r32.eax = 0x534D4150;
|
||||
regs.u.r32.ecx = 0x14;
|
||||
CLEAR_CF();
|
||||
return;
|
||||
break;
|
||||
case 1:
|
||||
extended_memory_size = inb_cmos(0x35);
|
||||
extended_memory_size <<= 8;
|
||||
extended_memory_size |= inb_cmos(0x34);
|
||||
extended_memory_size *= 64;
|
||||
if(extended_memory_size > 0x3bc000) // greater than EFF00000???
|
||||
{
|
||||
extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
|
||||
}
|
||||
extended_memory_size *= 1024;
|
||||
extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
|
||||
|
||||
if(extended_memory_size <= 15728640)
|
||||
{
|
||||
extended_memory_size = inb_cmos(0x31);
|
||||
extended_memory_size <<= 8;
|
||||
extended_memory_size |= inb_cmos(0x30);
|
||||
extended_memory_size *= 1024;
|
||||
}
|
||||
|
||||
write_word(ES, regs.u.r16.di, 0x0000);
|
||||
write_word(ES, regs.u.r16.di+2, 0x0010);
|
||||
write_word(ES, regs.u.r16.di+4, 0x0000);
|
||||
write_word(ES, regs.u.r16.di+6, 0x0000);
|
||||
|
||||
write_word(ES, regs.u.r16.di+8, extended_memory_size);
|
||||
extended_memory_size >>= 16;
|
||||
write_word(ES, regs.u.r16.di+10, extended_memory_size);
|
||||
extended_memory_size >>= 16;
|
||||
write_word(ES, regs.u.r16.di+12, extended_memory_size);
|
||||
extended_memory_size >>= 16;
|
||||
write_word(ES, regs.u.r16.di+14, extended_memory_size);
|
||||
|
||||
write_word(ES, regs.u.r16.di+16, 0x1);
|
||||
write_word(ES, regs.u.r16.di+18, 0x0);
|
||||
|
||||
regs.u.r32.ebx = 0;
|
||||
regs.u.r32.eax = 0x534D4150;
|
||||
regs.u.r32.ecx = 0x14;
|
||||
CLEAR_CF();
|
||||
return;
|
||||
break;
|
||||
default: /* AX=E820, DX=534D4150, BX unrecognized */
|
||||
goto int15_unimplemented;
|
||||
if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
|
||||
if (regs.u.r16.bx + 0x14 <= e820_table_size)
|
||||
memcpyb(ES, regs.u.r16.di,
|
||||
0xe000, 0x10 + regs.u.r16.bx, 0x14);
|
||||
regs.u.r32.ebx += 0x14;
|
||||
if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
|
||||
regs.u.r32.ebx = 0;
|
||||
} else if (regs.u.r16.bx == 1) {
|
||||
Bit32u base, type;
|
||||
Bit16u off;
|
||||
for (off = 0; off < e820_table_size; off += 0x14) {
|
||||
base = read_dword(0xe000, 0x10 + off);
|
||||
type = read_dword(0xe000, 0x20 + off);
|
||||
if ((base >= 0x100000) && (type == 1))
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// if DX != 0x534D4150)
|
||||
goto int15_unimplemented;
|
||||
}
|
||||
if (off == e820_table_size) {
|
||||
SET_CF();
|
||||
break;
|
||||
}
|
||||
memcpyb(ES, regs.u.r16.di, 0xe000, 0x10 + off, 0x14);
|
||||
regs.u.r32.ebx = 0;
|
||||
} else { /* AX=E820, DX=534D4150, BX unrecognized */
|
||||
goto int15_unimplemented;
|
||||
}
|
||||
|
||||
regs.u.r32.eax = 0x534D4150;
|
||||
regs.u.r32.ecx = 0x14;
|
||||
CLEAR_CF();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x01:
|
||||
// do we have any reason to fail here ?
|
||||
CLEAR_CF();
|
||||
case 0x01: {
|
||||
Bit16u off, e820_table_size = read_word(0xe000, 0x8) * 0x14;
|
||||
Bit32u base, type, size;
|
||||
|
||||
// my real system sets ax and bx to 0
|
||||
// this is confirmed by Ralph Brown list
|
||||
// but syslinux v1.48 is known to behave
|
||||
// strangely if ax is set to 0
|
||||
// regs.u.r16.ax = 0;
|
||||
// regs.u.r16.bx = 0;
|
||||
// do we have any reason to fail here ?
|
||||
CLEAR_CF();
|
||||
|
||||
// Get the amount of extended memory (above 1M)
|
||||
regs.u.r8.cl = inb_cmos(0x30);
|
||||
regs.u.r8.ch = inb_cmos(0x31);
|
||||
// Get the amount of extended memory (above 1M)
|
||||
regs.u.r8.cl = inb_cmos(0x30);
|
||||
regs.u.r8.ch = inb_cmos(0x31);
|
||||
|
||||
// limit to 15M
|
||||
if(regs.u.r16.cx > 0x3c00)
|
||||
{
|
||||
regs.u.r16.cx = 0x3c00;
|
||||
}
|
||||
// limit to 15M
|
||||
if (regs.u.r16.cx > (15*1024))
|
||||
regs.u.r16.cx = 15*1024;
|
||||
|
||||
// Get the amount of extended memory above 16M in 64k blocs
|
||||
regs.u.r8.dl = inb_cmos(0x34);
|
||||
regs.u.r8.dh = inb_cmos(0x35);
|
||||
// Find first RAM E820 entry >= 1MB.
|
||||
for (off = 0; off < e820_table_size; off += 0x14) {
|
||||
base = read_dword(0xe000, 0x10 + off);
|
||||
type = read_dword(0xe000, 0x20 + off);
|
||||
if ((base >= 0x100000) && (type == 1))
|
||||
break;
|
||||
}
|
||||
|
||||
// Set configured memory equal to extended memory
|
||||
regs.u.r16.ax = regs.u.r16.cx;
|
||||
regs.u.r16.bx = regs.u.r16.dx;
|
||||
break;
|
||||
// If there is RAM above 16MB, return amount in 64kB chunks.
|
||||
regs.u.r16.dx = 0;
|
||||
if (off != e820_table_size) {
|
||||
size = base + read_dword(0xe000, 0x18 + off);
|
||||
if (size > 0x1000000) {
|
||||
size -= 0x1000000;
|
||||
regs.u.r16.dx = (Bit16u)(size >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
// Set configured memory equal to extended memory
|
||||
regs.u.r16.ax = regs.u.r16.cx;
|
||||
regs.u.r16.bx = regs.u.r16.dx;
|
||||
break;
|
||||
}
|
||||
default: /* AH=0xE8?? but not implemented */
|
||||
goto int15_unimplemented;
|
||||
}
|
||||
break;
|
||||
goto int15_unimplemented;
|
||||
}
|
||||
break;
|
||||
int15_unimplemented:
|
||||
// fall into the default
|
||||
default:
|
||||
|
||||
@@ -450,6 +450,9 @@ static inline int paddr_is_ram(target_phys_addr_t addr)
|
||||
#define phys_ram_addr(x) (phys_ram_base + (x))
|
||||
#endif
|
||||
|
||||
extern unsigned long *logdirty_bitmap;
|
||||
extern unsigned long logdirty_bitmap_size;
|
||||
|
||||
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
|
||||
int len, int is_write)
|
||||
{
|
||||
@@ -485,9 +488,20 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
|
||||
l = 1;
|
||||
}
|
||||
} else if (paddr_is_ram(addr)) {
|
||||
/* Reading from RAM */
|
||||
/* Writing to RAM */
|
||||
ptr = phys_ram_addr(addr);
|
||||
memcpy(ptr, buf, l);
|
||||
if (logdirty_bitmap != NULL) {
|
||||
/* Record that we have dirtied this frame */
|
||||
unsigned long pfn = addr >> TARGET_PAGE_BITS;
|
||||
if (pfn / 8 >= logdirty_bitmap_size) {
|
||||
fprintf(logfile, "dirtying pfn %x >= bitmap size %x\n",
|
||||
pfn, logdirty_bitmap_size * 8);
|
||||
} else {
|
||||
logdirty_bitmap[pfn / HOST_LONG_BITS]
|
||||
|= 1UL << pfn % HOST_LONG_BITS;
|
||||
}
|
||||
}
|
||||
#ifdef __ia64__
|
||||
sync_icache(ptr, l);
|
||||
#endif
|
||||
|
||||
@@ -439,6 +439,18 @@ void cpu_ioreq_xor(CPUState *env, ioreq_t *req)
|
||||
req->data = tmp1;
|
||||
}
|
||||
|
||||
void cpu_ioreq_xchg(CPUState *env, ioreq_t *req)
|
||||
{
|
||||
unsigned long tmp1;
|
||||
|
||||
if (req->data_is_ptr != 0)
|
||||
hw_error("expected scalar value");
|
||||
|
||||
read_physical(req->addr, req->size, &tmp1);
|
||||
write_physical(req->addr, req->size, &req->data);
|
||||
req->data = tmp1;
|
||||
}
|
||||
|
||||
void __handle_ioreq(CPUState *env, ioreq_t *req)
|
||||
{
|
||||
if (!req->data_is_ptr && req->dir == IOREQ_WRITE && req->size != 4)
|
||||
@@ -463,6 +475,9 @@ void __handle_ioreq(CPUState *env, ioreq_t *req)
|
||||
case IOREQ_TYPE_XOR:
|
||||
cpu_ioreq_xor(env, req);
|
||||
break;
|
||||
case IOREQ_TYPE_XCHG:
|
||||
cpu_ioreq_xchg(env, req);
|
||||
break;
|
||||
default:
|
||||
hw_error("Invalid ioreq type 0x%x\n", req->type);
|
||||
}
|
||||
|
||||
+148
-31
@@ -11,9 +11,14 @@
|
||||
#include "vl.h"
|
||||
#include "block_int.h"
|
||||
#include <unistd.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static struct xs_handle *xsh = NULL;
|
||||
static char *hd_filename[MAX_DISKS];
|
||||
static char *media_filename[MAX_DISKS];
|
||||
static QEMUTimer *insert_timer = NULL;
|
||||
|
||||
#define UWAIT_MAX (30*1000000) /* thirty seconds */
|
||||
@@ -40,10 +45,10 @@ static void insert_media(void *opaque)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_DISKS; i++) {
|
||||
if (hd_filename[i]) {
|
||||
do_change(bs_table[i]->device_name, hd_filename[i]);
|
||||
free(hd_filename[i]);
|
||||
hd_filename[i] = NULL;
|
||||
if (media_filename[i] && bs_table[i]) {
|
||||
do_change(bs_table[i]->device_name, media_filename[i]);
|
||||
free(media_filename[i]);
|
||||
media_filename[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,7 +87,7 @@ void xenstore_parse_domain_config(int domid)
|
||||
unsigned int len, num, hd_index;
|
||||
|
||||
for(i = 0; i < MAX_DISKS; i++)
|
||||
hd_filename[i] = NULL;
|
||||
media_filename[i] = NULL;
|
||||
|
||||
xsh = xs_daemon_open();
|
||||
if (xsh == NULL) {
|
||||
@@ -128,19 +133,12 @@ void xenstore_parse_domain_config(int domid)
|
||||
continue;
|
||||
free(type);
|
||||
type = xs_read(xsh, XBT_NULL, buf, &len);
|
||||
/* read params to get the patch of the image -- read it last
|
||||
* so that we have its path in buf when setting up the
|
||||
* watch */
|
||||
if (pasprintf(&buf, "%s/params", bpath) == -1)
|
||||
continue;
|
||||
free(params);
|
||||
params = xs_read(xsh, XBT_NULL, buf, &len);
|
||||
if (params == NULL)
|
||||
continue;
|
||||
if (params[0]) {
|
||||
hd_filename[hd_index] = params; /* strdup() */
|
||||
params = NULL; /* don't free params on re-use */
|
||||
}
|
||||
/*
|
||||
* check if device has a phantom vbd; the phantom is hooked
|
||||
* to the frontend device (for ease of cleanup), so lookup
|
||||
@@ -151,38 +149,42 @@ void xenstore_parse_domain_config(int domid)
|
||||
continue;
|
||||
free(fpath);
|
||||
fpath = xs_read(xsh, XBT_NULL, buf, &len);
|
||||
if (fpath != NULL) {
|
||||
if (fpath) {
|
||||
if (pasprintf(&buf, "%s/dev", fpath) == -1)
|
||||
continue;
|
||||
free(params);
|
||||
params = xs_read(xsh, XBT_NULL, buf , &len);
|
||||
if (params != NULL) {
|
||||
free(hd_filename[hd_index]);
|
||||
hd_filename[hd_index] = params;
|
||||
params = NULL; /* don't free params on re-use */
|
||||
if (params) {
|
||||
/*
|
||||
* wait for device, on timeout silently fail because we will
|
||||
* fail to open below
|
||||
*/
|
||||
waitForDevice(hd_filename[hd_index]);
|
||||
waitForDevice(params);
|
||||
}
|
||||
}
|
||||
|
||||
bs_table[hd_index] = bdrv_new(dev);
|
||||
/* re-establish buf */
|
||||
if (pasprintf(&buf, "%s/params", bpath) == -1)
|
||||
continue;
|
||||
/* check if it is a cdrom */
|
||||
if (type && !strcmp(type, "cdrom")) {
|
||||
bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM);
|
||||
xs_watch(xsh, buf, dev);
|
||||
if (pasprintf(&buf, "%s/params", bpath) != -1)
|
||||
xs_watch(xsh, buf, dev);
|
||||
}
|
||||
if (hd_filename[hd_index]) {
|
||||
if (bdrv_open(bs_table[hd_index], hd_filename[hd_index],
|
||||
0 /* snapshot */) < 0)
|
||||
/* open device now if media present */
|
||||
if (params[0]) {
|
||||
if (bdrv_open(bs_table[hd_index], params, 0 /* snapshot */) < 0)
|
||||
fprintf(stderr, "qemu: could not open hard disk image '%s'\n",
|
||||
hd_filename[hd_index]);
|
||||
params);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set a watch for log-dirty requests from the migration tools */
|
||||
if (pasprintf(&buf, "%s/logdirty/next-active", path) != -1) {
|
||||
xs_watch(xsh, buf, "logdirty");
|
||||
fprintf(logfile, "Watching %s\n", buf);
|
||||
}
|
||||
|
||||
|
||||
out:
|
||||
free(type);
|
||||
free(params);
|
||||
@@ -201,6 +203,116 @@ int xenstore_fd(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned long *logdirty_bitmap = NULL;
|
||||
unsigned long logdirty_bitmap_size;
|
||||
extern int vga_ram_size, bios_size;
|
||||
|
||||
void xenstore_process_logdirty_event(void)
|
||||
{
|
||||
char *act;
|
||||
static char *active_path = NULL;
|
||||
static char *next_active_path = NULL;
|
||||
static char *seg = NULL;
|
||||
unsigned int len;
|
||||
int i;
|
||||
|
||||
fprintf(logfile, "Triggered log-dirty buffer switch\n");
|
||||
|
||||
if (!seg) {
|
||||
char *path, *p, *key_ascii, key_terminated[17] = {0,};
|
||||
key_t key;
|
||||
int shmid;
|
||||
|
||||
/* Find and map the shared memory segment for log-dirty bitmaps */
|
||||
if (!(path = xs_get_domain_path(xsh, domid))) {
|
||||
fprintf(logfile, "Log-dirty: can't get domain path in store\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!(path = realloc(path, strlen(path)
|
||||
+ strlen("/logdirty/next-active") + 1))) {
|
||||
fprintf(logfile, "Log-dirty: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
strcat(path, "/logdirty/");
|
||||
p = path + strlen(path);
|
||||
strcpy(p, "key");
|
||||
|
||||
key_ascii = xs_read(xsh, XBT_NULL, path, &len);
|
||||
if (!key_ascii) {
|
||||
/* No key yet: wait for the next watch */
|
||||
free(path);
|
||||
return;
|
||||
}
|
||||
strncpy(key_terminated, key_ascii, 16);
|
||||
free(key_ascii);
|
||||
key = (key_t) strtoull(key_terminated, NULL, 16);
|
||||
|
||||
/* Figure out how bit the log-dirty bitmaps are */
|
||||
logdirty_bitmap_size = ((phys_ram_size + 0x20
|
||||
- (vga_ram_size + bios_size))
|
||||
>> (TARGET_PAGE_BITS)); /* nr of bits in map*/
|
||||
if (logdirty_bitmap_size > HVM_BELOW_4G_MMIO_START >> TARGET_PAGE_BITS)
|
||||
logdirty_bitmap_size +=
|
||||
HVM_BELOW_4G_MMIO_LENGTH >> TARGET_PAGE_BITS; /* still bits */
|
||||
logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1)
|
||||
/ HOST_LONG_BITS); /* longs */
|
||||
logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */
|
||||
|
||||
/* Map the shared-memory segment */
|
||||
if ((shmid = shmget(key,
|
||||
2 * logdirty_bitmap_size,
|
||||
S_IRUSR|S_IWUSR)) == -1
|
||||
|| (seg = shmat(shmid, NULL, 0)) == (void *)-1) {
|
||||
fprintf(logfile, "Log-dirty: can't map segment %16.16llx (%s)\n",
|
||||
(unsigned long long) key, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg);
|
||||
|
||||
/* Double-check that the bitmaps are the size we expect */
|
||||
if (logdirty_bitmap_size != *(uint32_t *)seg) {
|
||||
fprintf(logfile, "Log-dirty: got %lu, calc %lu\n",
|
||||
*(uint32_t *)seg, logdirty_bitmap_size);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remember the paths for the next-active and active entries */
|
||||
strcpy(p, "active");
|
||||
if (!(active_path = strdup(path))) {
|
||||
fprintf(logfile, "Log-dirty: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
strcpy(p, "next-active");
|
||||
if (!(next_active_path = strdup(path))) {
|
||||
fprintf(logfile, "Log-dirty: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
|
||||
/* Read the required active buffer from the store */
|
||||
act = xs_read(xsh, XBT_NULL, next_active_path, &len);
|
||||
if (!act) {
|
||||
fprintf(logfile, "Log-dirty: can't read next-active\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Switch buffers */
|
||||
i = act[0] - '0';
|
||||
if (i != 0 && i != 1) {
|
||||
fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
|
||||
exit(1);
|
||||
}
|
||||
logdirty_bitmap = seg + i * logdirty_bitmap_size;
|
||||
|
||||
/* Ack that we've switched */
|
||||
xs_write(xsh, XBT_NULL, active_path, act, len);
|
||||
free(act);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void xenstore_process_event(void *opaque)
|
||||
{
|
||||
char **vec, *image = NULL;
|
||||
@@ -210,6 +322,11 @@ void xenstore_process_event(void *opaque)
|
||||
if (!vec)
|
||||
return;
|
||||
|
||||
if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
|
||||
xenstore_process_logdirty_event();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
|
||||
strlen(vec[XS_WATCH_TOKEN]) != 3)
|
||||
goto out;
|
||||
@@ -220,13 +337,13 @@ void xenstore_process_event(void *opaque)
|
||||
|
||||
do_eject(0, vec[XS_WATCH_TOKEN]);
|
||||
bs_table[hd_index]->filename[0] = 0;
|
||||
if (hd_filename[hd_index]) {
|
||||
free(hd_filename[hd_index]);
|
||||
hd_filename[hd_index] = NULL;
|
||||
if (media_filename[hd_index]) {
|
||||
free(media_filename[hd_index]);
|
||||
media_filename[hd_index] = NULL;
|
||||
}
|
||||
|
||||
if (image[0]) {
|
||||
hd_filename[hd_index] = strdup(image);
|
||||
media_filename[hd_index] = strdup(image);
|
||||
xenstore_check_new_media_present(5000);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ GUEST_SRCS-$(CONFIG_IA64) += xc_dom_compat_linux.c
|
||||
|
||||
CFLAGS += -Werror -Wmissing-prototypes
|
||||
CFLAGS += -fno-strict-aliasing
|
||||
CFLAGS += $(INCLUDES) -I.
|
||||
CFLAGS += $(INCLUDES) -I. -I../xenstore
|
||||
|
||||
# Needed for posix_fadvise64() in xc_linux.c
|
||||
CFLAGS-$(CONFIG_Linux) += -D_GNU_SOURCE
|
||||
|
||||
@@ -349,11 +349,7 @@ xc_domain_dumpcore_via_callback(int xc_handle,
|
||||
/* Map the shared info frame */
|
||||
live_shinfo = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
|
||||
PROT_READ, info.shared_info_frame);
|
||||
if ( !live_shinfo
|
||||
#ifdef __ia64__
|
||||
&& !info.hvm
|
||||
#endif
|
||||
)
|
||||
if ( !live_shinfo && !info.hvm )
|
||||
{
|
||||
PERROR("Couldn't map live_shinfo");
|
||||
goto out;
|
||||
|
||||
+11
-13
@@ -21,12 +21,15 @@
|
||||
#include "xg_private.h"
|
||||
#include "xc_core.h"
|
||||
|
||||
static int max_gpfn(int xc_handle, domid_t domid)
|
||||
{
|
||||
return xc_memory_op(xc_handle, XENMEM_maximum_gpfn, &domid);
|
||||
}
|
||||
|
||||
int
|
||||
xc_core_arch_auto_translated_physmap(const xc_dominfo_t *info)
|
||||
{
|
||||
if ( info->hvm )
|
||||
return 1;
|
||||
return 0;
|
||||
return info->hvm;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -35,14 +38,14 @@ xc_core_arch_memory_map_get(int xc_handle, xc_dominfo_t *info,
|
||||
xc_core_memory_map_t **mapp,
|
||||
unsigned int *nr_entries)
|
||||
{
|
||||
unsigned long max_pfn = live_shinfo->arch.max_pfn;
|
||||
xc_core_memory_map_t *map = NULL;
|
||||
unsigned long max_pfn = max_gpfn(xc_handle, info->domid);
|
||||
xc_core_memory_map_t *map;
|
||||
|
||||
map = malloc(sizeof(*map));
|
||||
if ( !map )
|
||||
if ( map == NULL )
|
||||
{
|
||||
PERROR("Could not allocate memory");
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
map->addr = 0;
|
||||
@@ -51,11 +54,6 @@ xc_core_arch_memory_map_get(int xc_handle, xc_dominfo_t *info,
|
||||
*mapp = map;
|
||||
*nr_entries = 1;
|
||||
return 0;
|
||||
|
||||
out:
|
||||
if ( map )
|
||||
free(map);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -67,7 +65,7 @@ xc_core_arch_map_p2m(int xc_handle, xc_dominfo_t *info,
|
||||
xen_pfn_t *live_p2m_frame_list_list = NULL;
|
||||
xen_pfn_t *live_p2m_frame_list = NULL;
|
||||
uint32_t dom = info->domid;
|
||||
unsigned long max_pfn = live_shinfo->arch.max_pfn;
|
||||
unsigned long max_pfn = max_gpfn(xc_handle, info->domid);
|
||||
int ret = -1;
|
||||
int err;
|
||||
|
||||
|
||||
@@ -137,6 +137,12 @@ static void build_e820map(void *e820_page, unsigned long long mem_size)
|
||||
e820entry[nr_map].type = E820_RAM;
|
||||
nr_map++;
|
||||
|
||||
/* Explicitly reserve space for special pages (ioreq and xenstore). */
|
||||
e820entry[nr_map].addr = mem_size - PAGE_SIZE * 3;
|
||||
e820entry[nr_map].size = PAGE_SIZE * 3;
|
||||
e820entry[nr_map].type = E820_RESERVED;
|
||||
nr_map++;
|
||||
|
||||
if ( extra_mem_size )
|
||||
{
|
||||
e820entry[nr_map].addr = (1ULL << 32);
|
||||
@@ -280,7 +286,6 @@ static int setup_guest(int xc_handle,
|
||||
/* NB. evtchn_upcall_mask is unused: leave as zero. */
|
||||
memset(&shared_info->evtchn_mask[0], 0xff,
|
||||
sizeof(shared_info->evtchn_mask));
|
||||
shared_info->arch.max_pfn = page_array[nr_pages - 1];
|
||||
munmap(shared_info, PAGE_SIZE);
|
||||
|
||||
if ( v_end > HVM_BELOW_4G_RAM_END )
|
||||
|
||||
@@ -70,9 +70,6 @@ int xc_hvm_restore(int xc_handle, int io_fd,
|
||||
{
|
||||
DECLARE_DOMCTL;
|
||||
|
||||
/* The new domain's shared-info frame number. */
|
||||
unsigned long shared_info_frame;
|
||||
|
||||
/* A copy of the CPU context of the guest. */
|
||||
vcpu_guest_context_t ctxt;
|
||||
|
||||
@@ -86,8 +83,6 @@ int xc_hvm_restore(int xc_handle, int io_fd,
|
||||
uint8_t *hvm_buf = NULL;
|
||||
unsigned long long v_end, memsize;
|
||||
unsigned long shared_page_nr;
|
||||
shared_info_t *shared_info = NULL;
|
||||
xen_pfn_t arch_max_pfn;
|
||||
|
||||
unsigned long pfn;
|
||||
unsigned int prev_pc, this_pc;
|
||||
@@ -96,8 +91,6 @@ int xc_hvm_restore(int xc_handle, int io_fd,
|
||||
/* Types of the pfns in the current region */
|
||||
unsigned long region_pfn_type[MAX_BATCH_SIZE];
|
||||
|
||||
struct xen_add_to_physmap xatp;
|
||||
|
||||
/* Number of pages of memory the guest has. *Not* the same as max_pfn. */
|
||||
unsigned long nr_pages;
|
||||
|
||||
@@ -146,7 +139,6 @@ int xc_hvm_restore(int xc_handle, int io_fd,
|
||||
pfns[i] = i;
|
||||
for ( i = HVM_BELOW_4G_RAM_END >> PAGE_SHIFT; i < pfn_array_size; i++ )
|
||||
pfns[i] += HVM_BELOW_4G_MMIO_LENGTH >> PAGE_SHIFT;
|
||||
arch_max_pfn = pfns[max_pfn];/* used later */
|
||||
|
||||
/* Allocate memory for HVM guest, skipping VGA hole 0xA0000-0xC0000. */
|
||||
rc = xc_domain_memory_populate_physmap(
|
||||
@@ -350,29 +342,6 @@ int xc_hvm_restore(int xc_handle, int io_fd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Shared-info pfn */
|
||||
if (!read_exact(io_fd, &(shared_info_frame), sizeof(uint32_t)) ) {
|
||||
ERROR("reading the shared-info pfn failed!\n");
|
||||
goto out;
|
||||
}
|
||||
/* Map the shared-info frame where it was before */
|
||||
xatp.domid = dom;
|
||||
xatp.space = XENMAPSPACE_shared_info;
|
||||
xatp.idx = 0;
|
||||
xatp.gpfn = shared_info_frame;
|
||||
if ( (rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp)) != 0 ) {
|
||||
ERROR("setting the shared-info pfn failed!\n");
|
||||
goto out;
|
||||
}
|
||||
if ( (xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp) != 0) ||
|
||||
((shared_info = xc_map_foreign_range(
|
||||
xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE,
|
||||
shared_info_frame)) == NULL) )
|
||||
goto out;
|
||||
/* shared_info.arch.max_pfn is used by dump-core */
|
||||
shared_info->arch.max_pfn = arch_max_pfn;
|
||||
munmap(shared_info, PAGE_SIZE);
|
||||
|
||||
rc = 0;
|
||||
goto out;
|
||||
|
||||
|
||||
+35
-34
@@ -54,6 +54,11 @@ static unsigned long hvirt_start;
|
||||
/* #levels of page tables used by the current guest */
|
||||
static unsigned int pt_levels;
|
||||
|
||||
/* Shared-memory bitmaps for getting log-dirty bits from qemu */
|
||||
static unsigned long *qemu_bitmaps[2];
|
||||
static int qemu_active;
|
||||
static int qemu_non_active;
|
||||
|
||||
int xc_hvm_drain_io(int handle, domid_t dom)
|
||||
{
|
||||
DECLARE_HYPERCALL;
|
||||
@@ -77,7 +82,8 @@ int xc_hvm_drain_io(int handle, domid_t dom)
|
||||
*/
|
||||
|
||||
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
||||
#define BITMAP_SIZE ((pfn_array_size + BITS_PER_LONG - 1) / 8)
|
||||
#define BITS_TO_LONGS(bits) (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
|
||||
#define BITMAP_SIZE (BITS_TO_LONGS(pfn_array_size) * sizeof(unsigned long))
|
||||
|
||||
#define BITMAP_ENTRY(_nr,_bmap) \
|
||||
((unsigned long *)(_bmap))[(_nr)/BITS_PER_LONG]
|
||||
@@ -124,6 +130,7 @@ static inline int permute( int i, int nr, int order_nr )
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static uint64_t tv_to_us(struct timeval *new)
|
||||
{
|
||||
return (new->tv_sec * 1000000) + new->tv_usec;
|
||||
@@ -277,7 +284,9 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd,
|
||||
}
|
||||
|
||||
int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
uint32_t max_factor, uint32_t flags, int (*suspend)(int))
|
||||
uint32_t max_factor, uint32_t flags, int (*suspend)(int),
|
||||
void *(*init_qemu_maps)(int, unsigned),
|
||||
void (*qemu_flip_buffer)(int, int))
|
||||
{
|
||||
xc_dominfo_t info;
|
||||
|
||||
@@ -293,9 +302,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
/* The size of an array big enough to contain all guest pfns */
|
||||
unsigned long pfn_array_size;
|
||||
|
||||
/* The new domain's shared-info frame number. */
|
||||
unsigned long shared_info_frame;
|
||||
|
||||
/* Other magic frames: ioreqs and xenstore comms */
|
||||
unsigned long ioreq_pfn, bufioreq_pfn, store_pfn;
|
||||
|
||||
@@ -309,9 +315,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
uint32_t hvm_buf_size;
|
||||
uint8_t *hvm_buf = NULL;
|
||||
|
||||
/* Live mapping of shared info structure */
|
||||
shared_info_t *live_shinfo = NULL;
|
||||
|
||||
/* base of the region in which domain memory is mapped */
|
||||
unsigned char *region_base = NULL;
|
||||
|
||||
@@ -363,7 +366,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
ERROR("HVM:Could not get vcpu context");
|
||||
goto out;
|
||||
}
|
||||
shared_info_frame = info.shared_info_frame;
|
||||
|
||||
/* cheesy sanity check */
|
||||
if ((info.max_memkb >> (PAGE_SHIFT - 10)) > max_mfn) {
|
||||
@@ -372,13 +374,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Map the shared info frame */
|
||||
if(!(live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ, shared_info_frame))) {
|
||||
ERROR("HVM:Couldn't map live_shinfo");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( xc_get_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, &store_pfn)
|
||||
|| xc_get_hvm_param(xc_handle, dom, HVM_PARAM_IOREQ_PFN, &ioreq_pfn)
|
||||
|| xc_get_hvm_param(xc_handle, dom,
|
||||
@@ -392,8 +387,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
"nr_pages=0x%lx\n", info.max_memkb, max_mfn, info.nr_pages);
|
||||
|
||||
if (live) {
|
||||
ERROR("hvm domain doesn't support live migration now.\n");
|
||||
goto out;
|
||||
|
||||
if (xc_shadow_control(xc_handle, dom,
|
||||
XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY,
|
||||
@@ -453,6 +446,15 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
to_skip = malloc(BITMAP_SIZE);
|
||||
|
||||
|
||||
if (live) {
|
||||
/* Get qemu-dm logging dirty pages too */
|
||||
void *seg = init_qemu_maps(dom, BITMAP_SIZE);
|
||||
qemu_bitmaps[0] = seg;
|
||||
qemu_bitmaps[1] = seg + BITMAP_SIZE;
|
||||
qemu_active = 0;
|
||||
qemu_non_active = 1;
|
||||
}
|
||||
|
||||
hvm_buf_size = xc_domain_hvm_getcontext(xc_handle, dom, 0, 0);
|
||||
if ( hvm_buf_size == -1 )
|
||||
{
|
||||
@@ -509,13 +511,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
|
||||
DPRINTF("Saving HVM domain memory pages: iter %d 0%%", iter);
|
||||
|
||||
if (last_iter && (max_pfn != live_shinfo->arch.max_pfn)) {
|
||||
DPRINTF("calculated max_pfn as %#lx, shinfo says %#lx\n",
|
||||
max_pfn, live_shinfo->arch.max_pfn);
|
||||
ERROR("Max pfn doesn't match shared info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
while( N < pfn_array_size ){
|
||||
|
||||
unsigned int this_pc = (N * 100) / pfn_array_size;
|
||||
@@ -663,8 +658,7 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
goto out;
|
||||
}
|
||||
|
||||
DPRINTF("SUSPEND shinfo %08lx eip %08lx edx %08lx\n",
|
||||
info.shared_info_frame,
|
||||
DPRINTF("SUSPEND eip %08lx edx %08lx\n",
|
||||
(unsigned long)ctxt.user_regs.eip,
|
||||
(unsigned long)ctxt.user_regs.edx);
|
||||
}
|
||||
@@ -677,10 +671,23 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Pull in the dirty bits from qemu too */
|
||||
if (!last_iter) {
|
||||
qemu_active = qemu_non_active;
|
||||
qemu_non_active = qemu_active ? 0 : 1;
|
||||
qemu_flip_buffer(dom, qemu_active);
|
||||
for (j = 0; j < BITMAP_SIZE / sizeof(unsigned long); j++) {
|
||||
to_send[j] |= qemu_bitmaps[qemu_non_active][j];
|
||||
qemu_bitmaps[qemu_non_active][j] = 0;
|
||||
}
|
||||
} else {
|
||||
for (j = 0; j < BITMAP_SIZE / sizeof(unsigned long); j++)
|
||||
to_send[j] |= qemu_bitmaps[qemu_active][j];
|
||||
}
|
||||
|
||||
sent_last_iter = sent_this_iter;
|
||||
|
||||
print_stats(xc_handle, dom, sent_this_iter, &stats, 1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -739,12 +746,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
ERROR("write HVM info failed!\n");
|
||||
}
|
||||
|
||||
/* Shared-info pfn */
|
||||
if (!write_exact(io_fd, &(shared_info_frame), sizeof(uint32_t)) ) {
|
||||
ERROR("write shared-info pfn failed!\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Success! */
|
||||
rc = 0;
|
||||
|
||||
|
||||
@@ -263,6 +263,15 @@ int xc_memory_op(int xc_handle,
|
||||
goto out1;
|
||||
}
|
||||
break;
|
||||
case XENMEM_current_reservation:
|
||||
case XENMEM_maximum_reservation:
|
||||
case XENMEM_maximum_gpfn:
|
||||
if ( lock_pages(arg, sizeof(domid_t)) )
|
||||
{
|
||||
PERROR("Could not lock");
|
||||
goto out1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ret = do_xen_hypercall(xc_handle, &hypercall);
|
||||
@@ -287,6 +296,11 @@ int xc_memory_op(int xc_handle,
|
||||
case XENMEM_add_to_physmap:
|
||||
unlock_pages(arg, sizeof(struct xen_add_to_physmap));
|
||||
break;
|
||||
case XENMEM_current_reservation:
|
||||
case XENMEM_maximum_reservation:
|
||||
case XENMEM_maximum_gpfn:
|
||||
unlock_pages(arg, sizeof(domid_t));
|
||||
break;
|
||||
}
|
||||
|
||||
out1:
|
||||
|
||||
@@ -32,8 +32,10 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
uint32_t max_factor, uint32_t flags /* XCFLAGS_xxx */,
|
||||
int (*suspend)(int domid));
|
||||
uint32_t max_factor, uint32_t flags /* XCFLAGS_xxx */,
|
||||
int (*suspend)(int domid),
|
||||
void *(*init_qemu_maps)(int, unsigned),
|
||||
void (*qemu_flip_buffer)(int, int));
|
||||
|
||||
/**
|
||||
* This function will restore a saved domain running Linux.
|
||||
|
||||
@@ -201,7 +201,9 @@ __attribute__((weak))
|
||||
__attribute__((weak))
|
||||
int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
uint32_t max_factor, uint32_t flags,
|
||||
int (*suspend)(int domid))
|
||||
int (*suspend)(int domid),
|
||||
void *(*init_qemu_maps)(int, unsigned),
|
||||
void (*qemu_flip_buffer)(int, int))
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
|
||||
@@ -72,7 +72,6 @@ typedef struct xen_vbd_record
|
||||
struct xen_vm_record_opt *vm;
|
||||
struct xen_vdi_record_opt *vdi;
|
||||
char *device;
|
||||
char *image;
|
||||
bool bootable;
|
||||
enum xen_vbd_mode mode;
|
||||
enum xen_vbd_type type;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, XenSource Inc.
|
||||
* Copyright (c) 2006-2007, XenSource Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "xen_common.h"
|
||||
#include "xen_crashdump_decl.h"
|
||||
#include "xen_sr_decl.h"
|
||||
#include "xen_string_string_map.h"
|
||||
#include "xen_vbd_decl.h"
|
||||
#include "xen_vdi_decl.h"
|
||||
#include "xen_vdi_type.h"
|
||||
@@ -73,11 +74,10 @@ typedef struct xen_vdi_record
|
||||
struct xen_crashdump_record_opt_set *crash_dumps;
|
||||
int64_t virtual_size;
|
||||
int64_t physical_utilisation;
|
||||
int64_t sector_size;
|
||||
char *location;
|
||||
enum xen_vdi_type type;
|
||||
bool sharable;
|
||||
bool read_only;
|
||||
xen_string_string_map *other_config;
|
||||
} xen_vdi_record;
|
||||
|
||||
/**
|
||||
@@ -250,13 +250,6 @@ extern bool
|
||||
xen_vdi_get_physical_utilisation(xen_session *session, int64_t *result, xen_vdi vdi);
|
||||
|
||||
|
||||
/**
|
||||
* Get the sector_size field of the given VDI.
|
||||
*/
|
||||
extern bool
|
||||
xen_vdi_get_sector_size(xen_session *session, int64_t *result, xen_vdi vdi);
|
||||
|
||||
|
||||
/**
|
||||
* Get the type field of the given VDI.
|
||||
*/
|
||||
@@ -278,6 +271,13 @@ extern bool
|
||||
xen_vdi_get_read_only(xen_session *session, bool *result, xen_vdi vdi);
|
||||
|
||||
|
||||
/**
|
||||
* Get the other_config field of the given VDI.
|
||||
*/
|
||||
extern bool
|
||||
xen_vdi_get_other_config(xen_session *session, xen_string_string_map **result, xen_vdi vdi);
|
||||
|
||||
|
||||
/**
|
||||
* Set the name/label field of the given VDI.
|
||||
*/
|
||||
@@ -313,6 +313,30 @@ extern bool
|
||||
xen_vdi_set_read_only(xen_session *session, xen_vdi vdi, bool read_only);
|
||||
|
||||
|
||||
/**
|
||||
* Set the other_config field of the given VDI.
|
||||
*/
|
||||
extern bool
|
||||
xen_vdi_set_other_config(xen_session *session, xen_vdi vdi, xen_string_string_map *other_config);
|
||||
|
||||
|
||||
/**
|
||||
* Add the given key-value pair to the other_config field of the given
|
||||
* VDI.
|
||||
*/
|
||||
extern bool
|
||||
xen_vdi_add_to_other_config(xen_session *session, xen_vdi vdi, char *key, char *value);
|
||||
|
||||
|
||||
/**
|
||||
* Remove the given key and its corresponding value from the
|
||||
* other_config field of the given VDI. If the key is not in that Map, then
|
||||
* do nothing.
|
||||
*/
|
||||
extern bool
|
||||
xen_vdi_remove_from_other_config(xen_session *session, xen_vdi vdi, char *key);
|
||||
|
||||
|
||||
/**
|
||||
* Take an exact copy of the VDI; the snapshot lives in the same
|
||||
* Storage Repository as its parent.
|
||||
|
||||
@@ -54,9 +54,6 @@ static const struct_member xen_vbd_record_struct_members[] =
|
||||
{ .key = "device",
|
||||
.type = &abstract_type_string,
|
||||
.offset = offsetof(xen_vbd_record, device) },
|
||||
{ .key = "image",
|
||||
.type = &abstract_type_string,
|
||||
.offset = offsetof(xen_vbd_record, image) },
|
||||
{ .key = "bootable",
|
||||
.type = &abstract_type_bool,
|
||||
.offset = offsetof(xen_vbd_record, bootable) },
|
||||
|
||||
+74
-24
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, XenSource Inc.
|
||||
* Copyright (c) 2006-2007, XenSource Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "xen_crashdump.h"
|
||||
#include "xen_internal.h"
|
||||
#include "xen_sr.h"
|
||||
#include "xen_string_string_map.h"
|
||||
#include "xen_vbd.h"
|
||||
#include "xen_vdi.h"
|
||||
#include "xen_vdi_type_internal.h"
|
||||
@@ -64,12 +65,6 @@ static const struct_member xen_vdi_record_struct_members[] =
|
||||
{ .key = "physical_utilisation",
|
||||
.type = &abstract_type_int,
|
||||
.offset = offsetof(xen_vdi_record, physical_utilisation) },
|
||||
{ .key = "sector_size",
|
||||
.type = &abstract_type_int,
|
||||
.offset = offsetof(xen_vdi_record, sector_size) },
|
||||
{ .key = "location",
|
||||
.type = &abstract_type_string,
|
||||
.offset = offsetof(xen_vdi_record, location) },
|
||||
{ .key = "type",
|
||||
.type = &xen_vdi_type_abstract_type_,
|
||||
.offset = offsetof(xen_vdi_record, type) },
|
||||
@@ -78,7 +73,10 @@ static const struct_member xen_vdi_record_struct_members[] =
|
||||
.offset = offsetof(xen_vdi_record, sharable) },
|
||||
{ .key = "read_only",
|
||||
.type = &abstract_type_bool,
|
||||
.offset = offsetof(xen_vdi_record, read_only) }
|
||||
.offset = offsetof(xen_vdi_record, read_only) },
|
||||
{ .key = "other_config",
|
||||
.type = &abstract_type_string_string_map,
|
||||
.offset = offsetof(xen_vdi_record, other_config) }
|
||||
};
|
||||
|
||||
const abstract_type xen_vdi_record_abstract_type_ =
|
||||
@@ -105,6 +103,7 @@ xen_vdi_record_free(xen_vdi_record *record)
|
||||
xen_sr_record_opt_free(record->sr);
|
||||
xen_vbd_record_opt_set_free(record->vbds);
|
||||
xen_crashdump_record_opt_set_free(record->crash_dumps);
|
||||
xen_string_string_map_free(record->other_config);
|
||||
free(record);
|
||||
}
|
||||
|
||||
@@ -314,22 +313,6 @@ xen_vdi_get_physical_utilisation(xen_session *session, int64_t *result, xen_vdi
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
xen_vdi_get_sector_size(xen_session *session, int64_t *result, xen_vdi vdi)
|
||||
{
|
||||
abstract_value param_values[] =
|
||||
{
|
||||
{ .type = &abstract_type_string,
|
||||
.u.string_val = vdi }
|
||||
};
|
||||
|
||||
abstract_type result_type = abstract_type_int;
|
||||
|
||||
XEN_CALL_("VDI.get_sector_size");
|
||||
return session->ok;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
xen_vdi_get_type(xen_session *session, enum xen_vdi_type *result, xen_vdi vdi)
|
||||
{
|
||||
@@ -377,6 +360,23 @@ xen_vdi_get_read_only(xen_session *session, bool *result, xen_vdi vdi)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
xen_vdi_get_other_config(xen_session *session, xen_string_string_map **result, xen_vdi vdi)
|
||||
{
|
||||
abstract_value param_values[] =
|
||||
{
|
||||
{ .type = &abstract_type_string,
|
||||
.u.string_val = vdi }
|
||||
};
|
||||
|
||||
abstract_type result_type = abstract_type_string_string_map;
|
||||
|
||||
*result = NULL;
|
||||
XEN_CALL_("VDI.get_other_config");
|
||||
return session->ok;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
xen_vdi_set_name_label(xen_session *session, xen_vdi vdi, char *label)
|
||||
{
|
||||
@@ -457,6 +457,56 @@ xen_vdi_set_read_only(xen_session *session, xen_vdi vdi, bool read_only)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
xen_vdi_set_other_config(xen_session *session, xen_vdi vdi, xen_string_string_map *other_config)
|
||||
{
|
||||
abstract_value param_values[] =
|
||||
{
|
||||
{ .type = &abstract_type_string,
|
||||
.u.string_val = vdi },
|
||||
{ .type = &abstract_type_string_string_map,
|
||||
.u.set_val = (arbitrary_set *)other_config }
|
||||
};
|
||||
|
||||
xen_call_(session, "VDI.set_other_config", param_values, 2, NULL, NULL);
|
||||
return session->ok;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
xen_vdi_add_to_other_config(xen_session *session, xen_vdi vdi, char *key, char *value)
|
||||
{
|
||||
abstract_value param_values[] =
|
||||
{
|
||||
{ .type = &abstract_type_string,
|
||||
.u.string_val = vdi },
|
||||
{ .type = &abstract_type_string,
|
||||
.u.string_val = key },
|
||||
{ .type = &abstract_type_string,
|
||||
.u.string_val = value }
|
||||
};
|
||||
|
||||
xen_call_(session, "VDI.add_to_other_config", param_values, 3, NULL, NULL);
|
||||
return session->ok;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
xen_vdi_remove_from_other_config(xen_session *session, xen_vdi vdi, char *key)
|
||||
{
|
||||
abstract_value param_values[] =
|
||||
{
|
||||
{ .type = &abstract_type_string,
|
||||
.u.string_val = vdi },
|
||||
{ .type = &abstract_type_string,
|
||||
.u.string_val = key }
|
||||
};
|
||||
|
||||
xen_call_(session, "VDI.remove_from_other_config", param_values, 2, NULL, NULL);
|
||||
return session->ok;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
xen_vdi_snapshot(xen_session *session, xen_vdi *result, xen_vdi vdi)
|
||||
{
|
||||
|
||||
@@ -421,8 +421,7 @@ static xen_vm create_new_vm(xen_session *session, bool hvm)
|
||||
.name_label = "MyRootFS",
|
||||
.name_description = "MyRootFS description",
|
||||
.sr = &sr_record,
|
||||
.virtual_size = (1 << 21), // 1GiB / 512 bytes/sector
|
||||
.sector_size = 512,
|
||||
.virtual_size = (INT64_C(1) << 30), // 1GiB
|
||||
.type = XEN_VDI_TYPE_SYSTEM,
|
||||
.sharable = false,
|
||||
.read_only = false
|
||||
|
||||
@@ -39,14 +39,13 @@ vm_cfg = {
|
||||
local_vdi_cfg = {
|
||||
'name_label': 'gentoo.hvm',
|
||||
'name_description': '',
|
||||
'location': 'file:/root/gentoo.amd64.hvm.img',
|
||||
'virtual_size': 0,
|
||||
'sector_size': 0,
|
||||
'type': 'system',
|
||||
'parent': '',
|
||||
'SR_name': 'Local',
|
||||
'sharable': False,
|
||||
'read_only': False,
|
||||
'other_config': {'location': 'file:/root/gentoo.amd64.hvm.img'},
|
||||
}
|
||||
|
||||
local_vbd_cfg = {
|
||||
|
||||
@@ -39,8 +39,7 @@ vm_cfg = {
|
||||
vdi_cfg = {
|
||||
'name_label': 'API_VDI',
|
||||
'name_description': '',
|
||||
'virtual_size': 100 * 1024 * 1024,
|
||||
'sector_size': 1024,
|
||||
'virtual_size': 100 * 1024 * 1024 * 1024,
|
||||
'type': 'system',
|
||||
'parent': '',
|
||||
'SR_name': 'QCoW',
|
||||
@@ -60,14 +59,13 @@ vbd_cfg = {
|
||||
local_vdi_cfg = {
|
||||
'name_label': 'gentoo.amd64.img',
|
||||
'name_description': '',
|
||||
'location': 'file:/root/gentoo.amd64.img',
|
||||
'virtual_size': 0,
|
||||
'sector_size': 0,
|
||||
'type': 'system',
|
||||
'parent': '',
|
||||
'SR_name': 'Local',
|
||||
'sharable': False,
|
||||
'read_only': False,
|
||||
'other_config': {'location': 'file:/root/gentoo.amd64.img'},
|
||||
}
|
||||
|
||||
local_vbd_cfg = {
|
||||
|
||||
@@ -40,8 +40,7 @@ VM_LIST_FORMAT = '%(name_label)-18s %(memory_actual)-5s %(VCPUs_number)-5s'\
|
||||
' %(power_state)-10s %(uuid)-36s'
|
||||
SR_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(physical_size)-10s' \
|
||||
'%(type)-10s'
|
||||
VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s '\
|
||||
'%(sector_size)-8s'
|
||||
VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s'
|
||||
VBD_LIST_FORMAT = '%(device)-6s %(uuid)-36s %(VDI)-8s'
|
||||
TASK_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(status)-8s %(progress)-4s'
|
||||
VIF_LIST_FORMAT = '%(name)-8s %(device)-7s %(uuid)-36s %(MAC)-10s'
|
||||
@@ -96,12 +95,9 @@ OPTIONS = {
|
||||
|
||||
'vdi-create': [(('--name-label',), {'help': 'Name for VDI'}),
|
||||
(('--name-description',), {'help': 'Description for VDI'}),
|
||||
(('--sector-size',), {'type': 'int',
|
||||
'help': 'Sector size',
|
||||
'default': 0}),
|
||||
(('--virtual-size',), {'type': 'int',
|
||||
'default': 0,
|
||||
'help': 'Size of VDI in sectors'}),
|
||||
'help': 'Size of VDI in bytes'}),
|
||||
(('--type',), {'choices': ['system', 'user', 'ephemeral'],
|
||||
'default': 'system',
|
||||
'help': 'VDI type'}),
|
||||
@@ -569,8 +565,7 @@ def xapi_vdi_list(args, async = False):
|
||||
if not is_long:
|
||||
print VDI_LIST_FORMAT % {'name_label': 'VDI Label',
|
||||
'uuid' : 'UUID',
|
||||
'virtual_size': 'Bytes',
|
||||
'sector_size': 'Sector Size'}
|
||||
'virtual_size': 'Bytes'}
|
||||
|
||||
for vdi in vdis:
|
||||
vdi_struct = execute(server, 'VDI.get_record', (session, vdi))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
name_label = 'VDI 1'
|
||||
name_description = ''
|
||||
virtual_size = 10 * 1024 * 1024
|
||||
sector_size = 1024
|
||||
virtual_size = 10 * 1024 * 1024 * 1024
|
||||
type = 'system'
|
||||
sharable = False
|
||||
read_only = False
|
||||
@@ -50,17 +50,21 @@ static PyObject *pyxc_error_to_exception(void)
|
||||
const xc_error *err = xc_get_last_error();
|
||||
const char *desc = xc_error_code_to_desc(err->code);
|
||||
|
||||
if (err->code == XC_ERROR_NONE)
|
||||
if ( err->code == XC_ERROR_NONE )
|
||||
return PyErr_SetFromErrno(xc_error_obj);
|
||||
|
||||
if (err->message[0] != '\0')
|
||||
if ( err->message[0] != '\0' )
|
||||
pyerr = Py_BuildValue("(iss)", err->code, desc, err->message);
|
||||
else
|
||||
pyerr = Py_BuildValue("(is)", err->code, desc);
|
||||
|
||||
xc_clear_last_error();
|
||||
|
||||
PyErr_SetObject(xc_error_obj, pyerr);
|
||||
if ( pyerr != NULL )
|
||||
{
|
||||
PyErr_SetObject(xc_error_obj, pyerr);
|
||||
Py_DECREF(pyerr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -70,13 +74,13 @@ static PyObject *pyxc_domain_dumpcore(XcObject *self, PyObject *args)
|
||||
uint32_t dom;
|
||||
char *corefile;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "is", &dom, &corefile))
|
||||
if ( !PyArg_ParseTuple(args, "is", &dom, &corefile) )
|
||||
return NULL;
|
||||
|
||||
if ( (corefile == NULL) || (corefile[0] == '\0') )
|
||||
return NULL;
|
||||
|
||||
if (xc_domain_dumpcore(self->xc_handle, dom, corefile) != 0)
|
||||
if ( xc_domain_dumpcore(self->xc_handle, dom, corefile) != 0 )
|
||||
return pyxc_error_to_exception();
|
||||
|
||||
Py_INCREF(zero);
|
||||
@@ -168,10 +172,10 @@ static PyObject *pyxc_domain_shutdown(XcObject *self, PyObject *args)
|
||||
{
|
||||
uint32_t dom, reason;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ii", &dom, &reason))
|
||||
if ( !PyArg_ParseTuple(args, "ii", &dom, &reason) )
|
||||
return NULL;
|
||||
|
||||
if (xc_domain_shutdown(self->xc_handle, dom, reason) != 0)
|
||||
if ( xc_domain_shutdown(self->xc_handle, dom, reason) != 0 )
|
||||
return pyxc_error_to_exception();
|
||||
|
||||
Py_INCREF(zero);
|
||||
@@ -183,10 +187,10 @@ static PyObject *pyxc_domain_resume(XcObject *self, PyObject *args)
|
||||
uint32_t dom;
|
||||
int fast;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ii", &dom, &fast))
|
||||
if ( !PyArg_ParseTuple(args, "ii", &dom, &fast) )
|
||||
return NULL;
|
||||
|
||||
if (xc_domain_resume(self->xc_handle, dom, fast) != 0)
|
||||
if ( xc_domain_resume(self->xc_handle, dom, fast) != 0 )
|
||||
return pyxc_error_to_exception();
|
||||
|
||||
Py_INCREF(zero);
|
||||
@@ -282,7 +286,7 @@ static PyObject *pyxc_domain_getinfo(XcObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
PyObject *list, *info_dict;
|
||||
PyObject *list, *info_dict, *pyhandle;
|
||||
|
||||
uint32_t first_dom = 0;
|
||||
int max_doms = 1024, nr_doms, i, j;
|
||||
@@ -308,26 +312,34 @@ static PyObject *pyxc_domain_getinfo(XcObject *self,
|
||||
list = PyList_New(nr_doms);
|
||||
for ( i = 0 ; i < nr_doms; i++ )
|
||||
{
|
||||
PyObject *pyhandle = PyList_New(sizeof(xen_domain_handle_t));
|
||||
info_dict = Py_BuildValue(
|
||||
"{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
|
||||
",s:L,s:L,s:L,s:i,s:i}",
|
||||
"domid", (int)info[i].domid,
|
||||
"online_vcpus", info[i].nr_online_vcpus,
|
||||
"max_vcpu_id", info[i].max_vcpu_id,
|
||||
"hvm", info[i].hvm,
|
||||
"dying", info[i].dying,
|
||||
"crashed", info[i].crashed,
|
||||
"shutdown", info[i].shutdown,
|
||||
"paused", info[i].paused,
|
||||
"blocked", info[i].blocked,
|
||||
"running", info[i].running,
|
||||
"mem_kb", (long long)info[i].nr_pages*(XC_PAGE_SIZE/1024),
|
||||
"cpu_time", (long long)info[i].cpu_time,
|
||||
"maxmem_kb", (long long)info[i].max_memkb,
|
||||
"ssidref", (int)info[i].ssidref,
|
||||
"shutdown_reason", info[i].shutdown_reason);
|
||||
pyhandle = PyList_New(sizeof(xen_domain_handle_t));
|
||||
if ( (pyhandle == NULL) || (info_dict == NULL) )
|
||||
{
|
||||
Py_DECREF(list);
|
||||
if ( pyhandle != NULL ) { Py_DECREF(pyhandle); }
|
||||
if ( info_dict != NULL ) { Py_DECREF(info_dict); }
|
||||
return NULL;
|
||||
}
|
||||
for ( j = 0; j < sizeof(xen_domain_handle_t); j++ )
|
||||
PyList_SetItem(pyhandle, j, PyInt_FromLong(info[i].handle[j]));
|
||||
info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
|
||||
",s:l,s:L,s:l,s:i,s:i}",
|
||||
"domid", info[i].domid,
|
||||
"online_vcpus", info[i].nr_online_vcpus,
|
||||
"max_vcpu_id", info[i].max_vcpu_id,
|
||||
"hvm", info[i].hvm,
|
||||
"dying", info[i].dying,
|
||||
"crashed", info[i].crashed,
|
||||
"shutdown", info[i].shutdown,
|
||||
"paused", info[i].paused,
|
||||
"blocked", info[i].blocked,
|
||||
"running", info[i].running,
|
||||
"mem_kb", info[i].nr_pages*(XC_PAGE_SIZE/1024),
|
||||
"cpu_time", info[i].cpu_time,
|
||||
"maxmem_kb", info[i].max_memkb,
|
||||
"ssidref", info[i].ssidref,
|
||||
"shutdown_reason", info[i].shutdown_reason);
|
||||
PyDict_SetItemString(info_dict, "handle", pyhandle);
|
||||
Py_DECREF(pyhandle);
|
||||
PyList_SetItem(list, i, info_dict);
|
||||
|
||||
@@ -66,16 +66,23 @@ def blkdev_segment(name):
|
||||
'type' : 'Disk' }
|
||||
return val
|
||||
|
||||
def blkdev_uname_to_file(uname):
|
||||
"""Take a blkdev uname and return the corresponding filename."""
|
||||
fn = None
|
||||
def _parse_uname(uname):
|
||||
fn = taptype = None
|
||||
if uname.find(":") != -1:
|
||||
(typ, fn) = uname.split(":", 1)
|
||||
if typ == "phy" and not fn.startswith("/"):
|
||||
fn = "/dev/%s" %(fn,)
|
||||
if typ == "tap":
|
||||
(typ, fn) = fn.split(":", 1)
|
||||
return fn
|
||||
(taptype, fn) = fn.split(":", 1)
|
||||
return (fn, taptype)
|
||||
|
||||
def blkdev_uname_to_file(uname):
|
||||
"""Take a blkdev uname and return the corresponding filename."""
|
||||
return _parse_uname(uname)[0]
|
||||
|
||||
def blkdev_uname_to_taptype(uname):
|
||||
"""Take a blkdev uname and return the blktap type."""
|
||||
return _parse_uname(uname)[1]
|
||||
|
||||
def mount_mode(name):
|
||||
mode = None
|
||||
|
||||
@@ -227,24 +227,30 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
|
||||
response = xmlrpclib.dumps(response,
|
||||
methodresponse=1,
|
||||
allow_none=1)
|
||||
except xmlrpclib.Fault, fault:
|
||||
response = xmlrpclib.dumps(fault)
|
||||
except Exception, exn:
|
||||
if self.xenapi:
|
||||
if _is_not_supported(exn):
|
||||
errdesc = ['MESSAGE_METHOD_UNKNOWN', method]
|
||||
try:
|
||||
if self.xenapi:
|
||||
if _is_not_supported(exn):
|
||||
errdesc = ['MESSAGE_METHOD_UNKNOWN', method]
|
||||
else:
|
||||
log.exception('Internal error handling %s', method)
|
||||
errdesc = ['INTERNAL_ERROR', str(exn)]
|
||||
|
||||
response = xmlrpclib.dumps(
|
||||
({ "Status": "Failure",
|
||||
"ErrorDescription": errdesc },),
|
||||
methodresponse = 1)
|
||||
else:
|
||||
log.exception('Internal error handling %s', method)
|
||||
errdesc = ['INTERNAL_ERROR', str(exn)]
|
||||
response = xmlrpclib.dumps(
|
||||
({ "Status": "Failure",
|
||||
"ErrorDescription": errdesc },),
|
||||
methodresponse = 1)
|
||||
else:
|
||||
log.exception('Internal error handling %s', method)
|
||||
import xen.xend.XendClient
|
||||
response = xmlrpclib.dumps(
|
||||
xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))
|
||||
import xen.xend.XendClient
|
||||
if isinstance(exn, xmlrpclib.Fault):
|
||||
response = xmlrpclib.dumps(exn)
|
||||
else:
|
||||
log.exception('Internal error handling %s', method)
|
||||
response = xmlrpclib.dumps(
|
||||
xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))
|
||||
except:
|
||||
log.exception('Internal error handling error')
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@@ -253,7 +259,7 @@ def _is_not_supported(exn):
|
||||
try:
|
||||
m = notSupportedRE.search(exn[0])
|
||||
return m is not None
|
||||
except TypeError, e:
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,9 @@ from xen.xend.XendVMMetrics import XendVMMetrics
|
||||
from xen.xend.XendAPIConstants import *
|
||||
from xen.util.xmlrpclib2 import stringify
|
||||
|
||||
from xen.util.blkif import blkdev_name_to_number
|
||||
|
||||
|
||||
AUTH_NONE = 'none'
|
||||
AUTH_PAM = 'pam'
|
||||
|
||||
@@ -662,7 +665,8 @@ class XendAPI(object):
|
||||
('add_to_other_config', None),
|
||||
('remove_from_other_config', None),
|
||||
('dmesg', 'String'),
|
||||
('get_log', 'String')]
|
||||
('get_log', 'String'),
|
||||
('send_debug_keys', None)]
|
||||
|
||||
host_funcs = [('get_by_name_label', 'Set(host)')]
|
||||
|
||||
@@ -749,6 +753,11 @@ class XendAPI(object):
|
||||
log_buffer = log_file.read()
|
||||
return xen_api_success(log_buffer)
|
||||
|
||||
def host_send_debug_keys(self, _, host_ref, keys):
|
||||
node = XendNode.instance()
|
||||
node.send_debug_keys(keys)
|
||||
return xen_api_success_void()
|
||||
|
||||
def host_get_record(self, session, host_ref):
|
||||
node = XendNode.instance()
|
||||
dom = XendDomain.instance()
|
||||
@@ -1070,6 +1079,7 @@ class XendAPI(object):
|
||||
('hard_reboot', None),
|
||||
('suspend', None),
|
||||
('resume', None),
|
||||
('send_sysrq', None),
|
||||
('add_to_HVM_boot_params', None),
|
||||
('remove_from_HVM_boot_params', None),
|
||||
('add_to_VCPUs_params', None),
|
||||
@@ -1077,7 +1087,8 @@ class XendAPI(object):
|
||||
('add_to_platform', None),
|
||||
('remove_from_platform', None),
|
||||
('add_to_other_config', None),
|
||||
('remove_from_other_config', None)]
|
||||
('remove_from_other_config', None),
|
||||
('send_trigger', None)]
|
||||
|
||||
VM_funcs = [('create', 'VM'),
|
||||
('get_by_name_label', 'Set(VM)')]
|
||||
@@ -1513,6 +1524,24 @@ class XendAPI(object):
|
||||
return XendTask.log_progress(0, 100, do_vm_func,
|
||||
"domain_unpause", vm_ref)
|
||||
|
||||
def VM_send_sysrq(self, _, vm_ref, req):
|
||||
xeninfo = XendDomain.instance().get_vm_by_uuid(vm_ref)
|
||||
if xeninfo.state != XEN_API_VM_POWER_STATE_RUNNING:
|
||||
return xen_api_error(
|
||||
['VM_BAD_POWER_STATE', vm_ref,
|
||||
XendDomain.POWER_STATE_NAMES[XEN_API_VM_POWER_STATE_RUNNING],
|
||||
XendDomain.POWER_STATE_NAMES[xeninfo.state]])
|
||||
xeninfo.send_sysrq(req)
|
||||
return xen_api_success_void()
|
||||
|
||||
|
||||
def VM_send_trigger(self, _, vm_ref, trigger, vcpu):
|
||||
xendom = XendDomain.instance()
|
||||
xeninfo = xendom.get_vm_by_uuid(vm_ref)
|
||||
xendom.domain_send_trigger(xeninfo.getDomid(), trigger, vcpu)
|
||||
return xen_api_success_void()
|
||||
|
||||
|
||||
# Xen API: Class VM_metrics
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
@@ -1538,12 +1567,13 @@ class XendAPI(object):
|
||||
return xen_api_success(self._VM_metrics_get(ref).get_vcpus_number())
|
||||
|
||||
def VM_metrics_get_vcpus_utilisation(self, _, ref):
|
||||
return xen_api_success(self._VM_metrics_get(ref).get_metrics_get_vcpus_utilisation())
|
||||
return xen_api_success(self._VM_metrics_get(ref).get_vcpus_utilisation())
|
||||
|
||||
# Xen API: Class VBD
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
VBD_attr_ro = ['metrics']
|
||||
VBD_attr_ro = ['metrics',
|
||||
'runtime_properties']
|
||||
VBD_attr_rw = ['VM',
|
||||
'VDI',
|
||||
'device',
|
||||
@@ -1584,23 +1614,28 @@ class XendAPI(object):
|
||||
# class methods
|
||||
def VBD_create(self, session, vbd_struct):
|
||||
xendom = XendDomain.instance()
|
||||
xennode = XendNode.instance()
|
||||
|
||||
if not xendom.is_valid_vm(vbd_struct['VM']):
|
||||
return xen_api_error(['HANDLE_INVALID', 'VM', vbd_struct['VM']])
|
||||
|
||||
dom = xendom.get_vm_by_uuid(vbd_struct['VM'])
|
||||
vbd_ref = ''
|
||||
vdi = xennode.get_vdi_by_uuid(vbd_struct['VDI'])
|
||||
if not vdi:
|
||||
return xen_api_error(['HANDLE_INVALID', 'VDI', vdi_ref])
|
||||
|
||||
# new VBD via VDI/SR
|
||||
vdi_image = vdi.get_location()
|
||||
|
||||
try:
|
||||
# new VBD via VDI/SR
|
||||
vdi_ref = vbd_struct.get('VDI')
|
||||
vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref)
|
||||
if not vdi:
|
||||
return xen_api_error(['HANDLE_INVALID', 'VDI', vdi_ref])
|
||||
vdi_image = vdi.get_location()
|
||||
vbd_ref = XendTask.log_progress(0, 100,
|
||||
dom.create_vbd,
|
||||
vbd_struct, vdi_image)
|
||||
except XendError:
|
||||
return xen_api_todo()
|
||||
except XendError, e:
|
||||
log.exception("Error in VBD_create")
|
||||
return xen_api_error(['INTERNAL_ERROR', str(e)])
|
||||
|
||||
vdi.addVBD(vbd_ref)
|
||||
|
||||
xendom.managed_config_save(dom)
|
||||
return xen_api_success(vbd_ref)
|
||||
@@ -1612,7 +1647,14 @@ class XendAPI(object):
|
||||
if not vm:
|
||||
return xen_api_error(['HANDLE_INVALID', 'VBD', vbd_ref])
|
||||
|
||||
vdi_ref = XendDomain.instance()\
|
||||
.get_dev_property_by_uuid('vbd', vbd_ref, "VDI")
|
||||
vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref)
|
||||
|
||||
XendTask.log_progress(0, 100, vm.destroy_vbd, vbd_ref)
|
||||
|
||||
vdi.removeVBD(vbd_ref)
|
||||
|
||||
return xen_api_success_void()
|
||||
|
||||
def _VBD_get(self, vbd_ref, prop):
|
||||
@@ -1624,6 +1666,24 @@ class XendAPI(object):
|
||||
def VBD_get_metrics(self, _, vbd_ref):
|
||||
return xen_api_success(vbd_ref)
|
||||
|
||||
def VBD_get_runtime_properties(self, _, vbd_ref):
|
||||
xendom = XendDomain.instance()
|
||||
dominfo = xendom.get_vm_with_dev_uuid('vbd', vbd_ref)
|
||||
device = dominfo.get_dev_config_by_uuid('vbd', vbd_ref)
|
||||
|
||||
try:
|
||||
devid = int(device['id'])
|
||||
device_sxps = dominfo.getDeviceSxprs('vbd')
|
||||
device_dicts = [dict(device_sxp[1][1:]) for device_sxp in device_sxps]
|
||||
device_dict = [device_dict
|
||||
for device_dict in device_dicts
|
||||
if int(device_dict['virtual-device']) == devid][0]
|
||||
|
||||
return xen_api_success(device_dict)
|
||||
except Exception, exn:
|
||||
log.exception(exn)
|
||||
return xen_api_success({})
|
||||
|
||||
# attributes (rw)
|
||||
def VBD_get_VM(self, session, vbd_ref):
|
||||
return self._VBD_get(vbd_ref, 'VM')
|
||||
@@ -1684,7 +1744,8 @@ class XendAPI(object):
|
||||
# Xen API: Class VIF
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
VIF_attr_ro = ['metrics']
|
||||
VIF_attr_ro = ['metrics',
|
||||
'runtime_properties']
|
||||
VIF_attr_rw = ['device',
|
||||
'network',
|
||||
'VM',
|
||||
@@ -1721,18 +1782,17 @@ class XendAPI(object):
|
||||
# class methods
|
||||
def VIF_create(self, session, vif_struct):
|
||||
xendom = XendDomain.instance()
|
||||
if xendom.is_valid_vm(vif_struct['VM']):
|
||||
dom = xendom.get_vm_by_uuid(vif_struct['VM'])
|
||||
try:
|
||||
vif_ref = dom.create_vif(vif_struct)
|
||||
xendom.managed_config_save(dom)
|
||||
return xen_api_success(vif_ref)
|
||||
except XendError:
|
||||
return xen_api_error(XEND_ERROR_TODO)
|
||||
else:
|
||||
if not xendom.is_valid_vm(vif_struct['VM']):
|
||||
return xen_api_error(['HANDLE_INVALID', 'VM', vif_struct['VM']])
|
||||
|
||||
|
||||
dom = xendom.get_vm_by_uuid(vif_struct['VM'])
|
||||
try:
|
||||
vif_ref = dom.create_vif(vif_struct)
|
||||
xendom.managed_config_save(dom)
|
||||
return xen_api_success(vif_ref)
|
||||
except XendError:
|
||||
return xen_api_error(XEND_ERROR_TODO)
|
||||
|
||||
def VIF_destroy(self, session, vif_ref):
|
||||
xendom = XendDomain.instance()
|
||||
vm = xendom.get_vm_with_dev_uuid('vif', vif_ref)
|
||||
@@ -1770,6 +1830,27 @@ class XendAPI(object):
|
||||
vifs = reduce(lambda x, y: x + y, vifs)
|
||||
return xen_api_success(vifs)
|
||||
|
||||
def VIF_get_runtime_properties(self, _, vif_ref):
|
||||
xendom = XendDomain.instance()
|
||||
dominfo = xendom.get_vm_with_dev_uuid('vif', vif_ref)
|
||||
device = dominfo.get_dev_config_by_uuid('vif', vif_ref)
|
||||
|
||||
try:
|
||||
devid = int(device['id'])
|
||||
|
||||
device_sxps = dominfo.getDeviceSxprs('vif')
|
||||
device_dicts = [dict(device_sxp[1][1:])
|
||||
for device_sxp in device_sxps]
|
||||
|
||||
device_dict = [device_dict
|
||||
for device_dict in device_dicts
|
||||
if int(device_dict['handle']) == devid][0]
|
||||
|
||||
return xen_api_success(device_dict)
|
||||
|
||||
except Exception, exn:
|
||||
log.exception(exn)
|
||||
return xen_api_success({})
|
||||
|
||||
# Xen API: Class VIF_metrics
|
||||
# ----------------------------------------------------------------
|
||||
@@ -1799,13 +1880,13 @@ class XendAPI(object):
|
||||
VDI_attr_ro = ['SR',
|
||||
'VBDs',
|
||||
'physical_utilisation',
|
||||
'sector_size',
|
||||
'type']
|
||||
VDI_attr_rw = ['name_label',
|
||||
'name_description',
|
||||
'virtual_size',
|
||||
'sharable',
|
||||
'read_only']
|
||||
'read_only',
|
||||
'other_config']
|
||||
VDI_attr_inst = VDI_attr_ro + VDI_attr_rw
|
||||
|
||||
VDI_methods = [('snapshot', 'VDI')]
|
||||
@@ -1816,14 +1897,12 @@ class XendAPI(object):
|
||||
return XendNode.instance().get_vdi_by_uuid(ref)
|
||||
|
||||
def VDI_get_VBDs(self, session, vdi_ref):
|
||||
return xen_api_todo()
|
||||
vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref)
|
||||
return xen_api_success(vdi.getVBDs())
|
||||
|
||||
def VDI_get_physical_utilisation(self, session, vdi_ref):
|
||||
return xen_api_success(self._get_VDI(vdi_ref).
|
||||
get_physical_utilisation())
|
||||
|
||||
def VDI_get_sector_size(self, session, vdi_ref):
|
||||
return xen_api_success(self._get_VDI(vdi_ref).sector_size)
|
||||
get_physical_utilisation())
|
||||
|
||||
def VDI_get_type(self, session, vdi_ref):
|
||||
return xen_api_success(self._get_VDI(vdi_ref).type)
|
||||
@@ -1865,6 +1944,14 @@ class XendAPI(object):
|
||||
self._get_VDI(vdi_ref).read_only = bool(value)
|
||||
return xen_api_success_void()
|
||||
|
||||
def VDI_get_other_config(self, session, vdi_ref):
|
||||
return xen_api_success(
|
||||
self._get_VDI(vdi_ref).other_config)
|
||||
|
||||
def VDI_set_other_config(self, session, vdi_ref, other_config):
|
||||
self._get_VDI(vdi_ref).other_config = other_config
|
||||
return xen_api_success_void()
|
||||
|
||||
# Object Methods
|
||||
def VDI_snapshot(self, session, vdi_ref):
|
||||
return xen_api_todo()
|
||||
@@ -1881,13 +1968,13 @@ class XendAPI(object):
|
||||
'name_label': image.name_label,
|
||||
'name_description': image.name_description,
|
||||
'SR': image.sr_uuid,
|
||||
'VBDs': [], # TODO
|
||||
'VBDs': image.getVBDs(),
|
||||
'virtual_size': image.virtual_size,
|
||||
'physical_utilisation': image.physical_utilisation,
|
||||
'sector_size': image.sector_size,
|
||||
'type': image.type,
|
||||
'sharable': image.sharable,
|
||||
'read_only': image.read_only,
|
||||
'other_config': image.other_config
|
||||
})
|
||||
|
||||
# Class Functions
|
||||
|
||||
@@ -193,8 +193,8 @@ def restore(xd, fd, dominfo = None, paused = False):
|
||||
is_hvm = dominfo.info.is_hvm()
|
||||
if is_hvm:
|
||||
hvm = dominfo.info['memory_static_min']
|
||||
apic = dominfo.info['platform'].get('apic', 0)
|
||||
pae = dominfo.info['platform'].get('pae', 0)
|
||||
apic = int(dominfo.info['platform'].get('apic', 0))
|
||||
pae = int(dominfo.info['platform'].get('pae', 0))
|
||||
log.info("restore hvm domain %d, mem=%d, apic=%d, pae=%d",
|
||||
dominfo.domid, hvm, apic, pae)
|
||||
else:
|
||||
|
||||
@@ -28,7 +28,7 @@ from xen.xend.PrettyPrint import prettyprintstring
|
||||
from xen.xend.XendConstants import DOM_STATE_HALTED
|
||||
|
||||
log = logging.getLogger("xend.XendConfig")
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.setLevel(logging.WARN)
|
||||
|
||||
|
||||
"""
|
||||
@@ -105,8 +105,6 @@ XENAPI_CFG_TO_LEGACY_CFG = {
|
||||
'uuid': 'uuid',
|
||||
'vcpus_number': 'vcpus',
|
||||
'cpus': 'cpus',
|
||||
'memory_static_min': 'memory',
|
||||
'memory_static_max': 'maxmem',
|
||||
'name_label': 'name',
|
||||
'actions_after_shutdown': 'on_poweroff',
|
||||
'actions_after_reboot': 'on_reboot',
|
||||
@@ -136,11 +134,10 @@ XENAPI_CFG_TYPES = {
|
||||
'user_version': str,
|
||||
'is_a_template': bool0,
|
||||
'resident_on': str,
|
||||
'memory_static_min': int,
|
||||
'memory_static_min': int, # note these are stored in bytes, not KB!
|
||||
'memory_static_max': int,
|
||||
'memory_dynamic_min': int,
|
||||
'memory_dynamic_max': int,
|
||||
'memory_actual': int,
|
||||
'cpus': list,
|
||||
'vcpus_policy': str,
|
||||
'vcpus_params': dict,
|
||||
@@ -314,7 +311,6 @@ class XendConfig(dict):
|
||||
'shadow_memory': 0,
|
||||
'memory_static_max': 0,
|
||||
'memory_dynamic_max': 0,
|
||||
'memory_actual': 0,
|
||||
'devices': {},
|
||||
'security': None,
|
||||
'on_xend_start': 'ignore',
|
||||
@@ -334,20 +330,39 @@ class XendConfig(dict):
|
||||
|
||||
return defaults
|
||||
|
||||
#
|
||||
# Here we assume these values exist in the dict.
|
||||
# If they don't we have a bigger problem, lets not
|
||||
# try and 'fix it up' but acutually fix the cause ;-)
|
||||
#
|
||||
def _memory_sanity_check(self):
|
||||
if self['memory_static_min'] == 0:
|
||||
self['memory_static_min'] = self['memory_dynamic_min']
|
||||
|
||||
# If the static max is not set, let's set it to dynamic max.
|
||||
# If the static max is smaller than static min, then fix it!
|
||||
self['memory_static_max'] = max(self['memory_static_max'],
|
||||
self['memory_dynamic_max'],
|
||||
self['memory_static_min'])
|
||||
|
||||
for mem_type in ('memory_static_min', 'memory_static_max'):
|
||||
if self[mem_type] <= 0:
|
||||
raise XendConfigError('Memory value too low for %s: %d' %
|
||||
(mem_type, self[mem_type]))
|
||||
log.debug("_memory_sanity_check memory_static_min: %s, "
|
||||
"memory_static_max: %i, "
|
||||
"memory_dynamic_min: %i, "
|
||||
"memory_dynamic_max: %i",
|
||||
self["memory_static_min"],
|
||||
self["memory_static_max"],
|
||||
self["memory_dynamic_min"],
|
||||
self["memory_dynamic_max"])
|
||||
|
||||
if not self["memory_static_min"] <= self["memory_static_max"]:
|
||||
raise XendConfigError("memory_static_min must be less " \
|
||||
"than or equal to memory_static_max")
|
||||
if not self["memory_dynamic_min"] <= self["memory_dynamic_max"]:
|
||||
raise XendConfigError("memory_dynamic_min must be less " \
|
||||
"than or equal to memory_dynamic_max")
|
||||
if not self["memory_static_min"] <= self["memory_dynamic_min"]:
|
||||
raise XendConfigError("memory_static_min must be less " \
|
||||
"than or equal to memory_dynamic_min")
|
||||
if not self["memory_dynamic_max"] <= self["memory_static_max"]:
|
||||
raise XendConfigError("memory_dynamic_max must be less " \
|
||||
"than or equal to memory_static_max")
|
||||
if not self["memory_dynamic_max"] > 0:
|
||||
raise XendConfigError("memory_dynamic_max must be greater " \
|
||||
"than zero")
|
||||
if not self["memory_static_max"] > 0:
|
||||
raise XendConfigError("memory_static_max must be greater " \
|
||||
"than zero")
|
||||
|
||||
def _actions_sanity_check(self):
|
||||
for event in ['shutdown', 'reboot', 'crash']:
|
||||
@@ -392,8 +407,12 @@ class XendConfig(dict):
|
||||
self['domid'] = dominfo['domid']
|
||||
self['online_vcpus'] = dominfo['online_vcpus']
|
||||
self['vcpus_number'] = dominfo['max_vcpu_id'] + 1
|
||||
self['memory_dynamic_min'] = (dominfo['mem_kb'] + 1023)/1024
|
||||
self['memory_dynamic_max'] = (dominfo['maxmem_kb'] + 1023)/1024
|
||||
|
||||
self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024
|
||||
self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024
|
||||
self['memory_static_min'] = 0
|
||||
self['memory_static_max'] = dominfo['maxmem_kb'] * 1024
|
||||
|
||||
self['cpu_time'] = dominfo['cpu_time']/1e9
|
||||
# TODO: i don't know what the security stuff expects here
|
||||
if dominfo.get('ssidref'):
|
||||
@@ -447,6 +466,13 @@ class XendConfig(dict):
|
||||
log.warn('Ignoring unrecognised value for deprecated option:'
|
||||
'restart = \'%s\'', restart)
|
||||
|
||||
# Handle memory, passed in as MiB
|
||||
|
||||
if sxp.child_value(sxp_cfg, "memory") != None:
|
||||
cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory"))
|
||||
if sxp.child_value(sxp_cfg, "maxmem") != None:
|
||||
cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem"))
|
||||
|
||||
# Only extract options we know about.
|
||||
extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG
|
||||
extract_keys += XENAPI_CFG_TO_LEGACY_CFG.values()
|
||||
@@ -616,6 +642,21 @@ class XendConfig(dict):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# Lets try and handle memory correctly
|
||||
|
||||
MiB = 1024 * 1024
|
||||
|
||||
if "memory" in cfg:
|
||||
self["memory_static_min"] = 0
|
||||
self["memory_static_max"] = int(cfg["memory"]) * MiB
|
||||
self["memory_dynamic_min"] = int(cfg["memory"]) * MiB
|
||||
self["memory_dynamic_max"] = int(cfg["memory"]) * MiB
|
||||
|
||||
if "maxmem" in cfg:
|
||||
self["memory_static_max"] = int(cfg["maxmem"]) * MiB
|
||||
|
||||
self._memory_sanity_check()
|
||||
|
||||
def update_with(n, o):
|
||||
if not self.get(n):
|
||||
self[n] = cfg.get(o, '')
|
||||
@@ -632,13 +673,6 @@ class XendConfig(dict):
|
||||
if key in cfg:
|
||||
self['platform'][key] = cfg[key]
|
||||
|
||||
# make sure a sane maximum is set
|
||||
if self['memory_static_max'] <= 0:
|
||||
self['memory_static_max'] = self['memory_static_min']
|
||||
|
||||
self['memory_dynamic_max'] = self['memory_static_max']
|
||||
self['memory_dynamic_min'] = self['memory_static_min']
|
||||
|
||||
# set device references in the configuration
|
||||
self['devices'] = cfg.get('devices', {})
|
||||
self['console_refs'] = cfg.get('console_refs', [])
|
||||
@@ -812,6 +846,21 @@ class XendConfig(dict):
|
||||
else:
|
||||
sxpr.append([legacy, self[xenapi]])
|
||||
|
||||
MiB = 1024*1024
|
||||
|
||||
sxpr.append(["maxmem", int(self["memory_static_max"])/MiB])
|
||||
sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB])
|
||||
|
||||
if not legacy_only:
|
||||
sxpr.append(['memory_dynamic_min',
|
||||
int(self.get('memory_dynamic_min'))])
|
||||
sxpr.append(['memory_dynamic_max',
|
||||
int(self.get('memory_dynamic_max'))])
|
||||
sxpr.append(['memory_static_max',
|
||||
int(self.get('memory_static_max'))])
|
||||
sxpr.append(['memory_static_min',
|
||||
int(self.get('memory_static_min'))])
|
||||
|
||||
for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
|
||||
if legacy in ('domid', 'uuid'): # skip these
|
||||
continue
|
||||
@@ -820,8 +869,6 @@ class XendConfig(dict):
|
||||
|
||||
sxpr.append(['image', self.image_sxpr()])
|
||||
sxpr.append(['status', domain.state])
|
||||
sxpr.append(['memory_dynamic_min', self.get('memory_dynamic_min')])
|
||||
sxpr.append(['memory_dynamic_max', self.get('memory_dynamic_max')])
|
||||
|
||||
if domain.getDomid() is not None:
|
||||
sxpr.append(['state', self._get_old_state_string()])
|
||||
|
||||
@@ -674,7 +674,7 @@ class XendDomain:
|
||||
else:
|
||||
return domid
|
||||
|
||||
raise XendInvalidDomain("Domain does not exist")
|
||||
raise XendInvalidDomain(vm_uuid)
|
||||
finally:
|
||||
self.domains_lock.release()
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ from types import StringTypes
|
||||
|
||||
import xen.lowlevel.xc
|
||||
from xen.util import asserts
|
||||
from xen.util.blkif import blkdev_uname_to_file
|
||||
from xen.util.blkif import blkdev_uname_to_file, blkdev_uname_to_taptype
|
||||
from xen.util import security
|
||||
|
||||
from xen.xend import balloon, sxp, uuid, image, arch, osdep
|
||||
@@ -576,12 +576,14 @@ class XendDomainInfo:
|
||||
if target <= 0:
|
||||
raise XendError('Invalid memory size')
|
||||
|
||||
self.info['memory_static_min'] = target
|
||||
MiB = 1024 * 1024
|
||||
self.info['memory_dynamic_min'] = target * MiB
|
||||
self.info['memory_dynamic_max'] = target * MiB
|
||||
|
||||
if self.domid >= 0:
|
||||
self.storeVm("memory", target)
|
||||
self.storeDom("memory/target", target << 10)
|
||||
else:
|
||||
self.info['memory_dynamic_min'] = target
|
||||
xen.xend.XendDomain.instance().managed_config_save(self)
|
||||
|
||||
def setMemoryMaximum(self, limit):
|
||||
@@ -664,6 +666,10 @@ class XendDomainInfo:
|
||||
if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG:
|
||||
xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg]
|
||||
self.info[xapiarg] = val
|
||||
elif arg == "memory":
|
||||
self.info["static_memory_min"] = val
|
||||
elif arg == "maxmem":
|
||||
self.info["static_memory_max"] = val
|
||||
else:
|
||||
self.info[arg] = val
|
||||
|
||||
@@ -780,7 +786,7 @@ class XendDomainInfo:
|
||||
'vm': self.vmpath,
|
||||
'name': self.info['name_label'],
|
||||
'console/limit': str(xoptions.get_console_limit() * 1024),
|
||||
'memory/target': str(self.info['memory_static_min'] * 1024),
|
||||
'memory/target': str(self.info['memory_dynamic_max'] / 1024),
|
||||
}
|
||||
|
||||
def f(n, v):
|
||||
@@ -864,7 +870,15 @@ class XendDomainInfo:
|
||||
xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg]
|
||||
if val != None and val != self.info[xapiarg]:
|
||||
self.info[xapiarg] = val
|
||||
changed= True
|
||||
changed = True
|
||||
elif arg == "memory":
|
||||
if val != None and val != self.info["static_memory_min"]:
|
||||
self.info["static_memory_min"] = val
|
||||
changed = True
|
||||
elif arg == "maxmem":
|
||||
if val != None and val != self.info["static_memory_max"]:
|
||||
self.info["static_memory_max"] = val
|
||||
changed = True
|
||||
|
||||
# Check whether image definition has been updated
|
||||
image_sxp = self._readVm('image')
|
||||
@@ -969,11 +983,12 @@ class XendDomainInfo:
|
||||
|
||||
def getMemoryTarget(self):
|
||||
"""Get this domain's target memory size, in KB."""
|
||||
return self.info['memory_static_min'] * 1024
|
||||
return self.info['memory_dynamic_max'] / 1024
|
||||
|
||||
def getMemoryMaximum(self):
|
||||
"""Get this domain's maximum memory size, in KB."""
|
||||
return self.info['memory_static_max'] * 1024
|
||||
# remember, info now stores memory in bytes
|
||||
return self.info['memory_static_max'] / 1024
|
||||
|
||||
def getResume(self):
|
||||
return str(self._resume)
|
||||
@@ -1455,13 +1470,14 @@ class XendDomainInfo:
|
||||
# Use architecture- and image-specific calculations to determine
|
||||
# the various headrooms necessary, given the raw configured
|
||||
# values. maxmem, memory, and shadow are all in KiB.
|
||||
# but memory_static_max etc are all stored in bytes now.
|
||||
memory = self.image.getRequiredAvailableMemory(
|
||||
self.info['memory_static_min'] * 1024)
|
||||
self.info['memory_dynamic_max'] / 1024)
|
||||
maxmem = self.image.getRequiredAvailableMemory(
|
||||
self.info['memory_static_max'] * 1024)
|
||||
self.info['memory_static_max'] / 1024)
|
||||
shadow = self.image.getRequiredShadowMemory(
|
||||
self.info['shadow_memory'] * 1024,
|
||||
self.info['memory_static_max'] * 1024)
|
||||
self.info['shadow_memory'] / 1024,
|
||||
self.info['memory_static_max'] / 1024)
|
||||
|
||||
log.debug("_initDomain:shadow_memory=0x%x, memory_static_max=0x%x, memory_static_min=0x%x.", self.info['shadow_memory'], self.info['memory_static_max'], self.info['memory_static_min'],)
|
||||
# Round shadow up to a multiple of a MiB, as shadow_mem_control
|
||||
@@ -1650,7 +1666,18 @@ class XendDomainInfo:
|
||||
log.exception("XendDomainInfo.destroy: xc.domain_destroy failed.")
|
||||
|
||||
from xen.xend import XendDomain
|
||||
XendDomain.instance().remove_domain(self)
|
||||
|
||||
if "transient" in self.info["other_config"]\
|
||||
and bool(self.info["other_config"]["transient"]):
|
||||
xendDomainInstance = XendDomain.instance()
|
||||
|
||||
xendDomainInstance.domains_lock.acquire()
|
||||
xendDomainInstance._refresh(refresh_shutdown = False)
|
||||
xendDomainInstance.domains_lock.release()
|
||||
|
||||
xendDomainInstance.domain_delete(self.info["name_label"])
|
||||
else:
|
||||
XendDomain.instance().remove_domain(self)
|
||||
|
||||
self.cleanupDomain()
|
||||
self._cleanup_phantom_devs(paths)
|
||||
@@ -1759,7 +1786,8 @@ class XendDomainInfo:
|
||||
disk = devinfo[1]['uname']
|
||||
|
||||
fn = blkdev_uname_to_file(disk)
|
||||
mounted = devtype == 'tap' and not os.stat(fn).st_rdev
|
||||
taptype = blkdev_uname_to_taptype(disk)
|
||||
mounted = devtype == 'tap' and taptype != 'aio' and taptype != 'sync' and not os.stat(fn).st_rdev
|
||||
if mounted:
|
||||
# This is a file, not a device. pygrub can cope with a
|
||||
# file if it's raw, but if it's QCOW or other such formats
|
||||
@@ -1775,7 +1803,7 @@ class XendDomainInfo:
|
||||
|
||||
from xen.xend import XendDomain
|
||||
dom0 = XendDomain.instance().privilegedDomain()
|
||||
dom0._waitForDeviceUUID(dom0.create_vbd(vbd, fn))
|
||||
dom0._waitForDeviceUUID(dom0.create_vbd(vbd, disk))
|
||||
fn = BOOTLOADER_LOOPBACK_DEVICE
|
||||
|
||||
try:
|
||||
@@ -1833,7 +1861,7 @@ class XendDomainInfo:
|
||||
# 1MB per vcpu plus 4Kib/Mib of RAM. This is higher than
|
||||
# the minimum that Xen would allocate if no value were given.
|
||||
overhead_kb = self.info['vcpus_number'] * 1024 + \
|
||||
self.info['memory_static_max'] * 4
|
||||
(self.info['memory_static_max'] / 1024 / 1024) * 4
|
||||
overhead_kb = ((overhead_kb + 1023) / 1024) * 1024
|
||||
# The domain might already have some shadow memory
|
||||
overhead_kb -= xc.shadow_mem_control(self.domid) * 1024
|
||||
@@ -1899,6 +1927,11 @@ class XendDomainInfo:
|
||||
if self._infoIsSet(info_key):
|
||||
to_store[key] = str(self.info[info_key])
|
||||
|
||||
if self._infoIsSet("static_memory_min"):
|
||||
to_store["memory"] = str(self.info["static_memory_min"])
|
||||
if self._infoIsSet("static_memory_max"):
|
||||
to_store["maxmem"] = str(self.info["static_memory_max"])
|
||||
|
||||
image_sxpr = self.info.image_sxpr()
|
||||
if image_sxpr:
|
||||
to_store['image'] = sxp.to_string(image_sxpr)
|
||||
@@ -1988,7 +2021,11 @@ class XendDomainInfo:
|
||||
info = dom_get(self.domid)
|
||||
if not info:
|
||||
return
|
||||
|
||||
|
||||
if info["maxmem_kb"] < 0:
|
||||
info["maxmem_kb"] = XendNode.instance() \
|
||||
.physinfo_dict()['total_memory'] * 1024
|
||||
|
||||
#manually update ssidref / security fields
|
||||
if security.on() and info.has_key('ssidref'):
|
||||
if (info['ssidref'] != 0) and self.info.has_key('security'):
|
||||
@@ -2249,8 +2286,6 @@ class XendDomainInfo:
|
||||
@return: uuid of the device
|
||||
"""
|
||||
xenapi_vbd['image'] = vdi_image_path
|
||||
log.debug('create_vbd: %s' % xenapi_vbd)
|
||||
dev_uuid = ''
|
||||
if vdi_image_path.startswith('tap'):
|
||||
dev_uuid = self.info.device_add('tap', cfg_xenapi = xenapi_vbd)
|
||||
else:
|
||||
@@ -2260,16 +2295,25 @@ class XendDomainInfo:
|
||||
raise XendError('Failed to create device')
|
||||
|
||||
if self.state == XEN_API_VM_POWER_STATE_RUNNING:
|
||||
|
||||
_, config = self.info['devices'][dev_uuid]
|
||||
dev_control = None
|
||||
|
||||
if vdi_image_path.startswith('tap'):
|
||||
dev_control = self.getDeviceController('tap')
|
||||
dev_control = self.getDeviceController('tap')
|
||||
else:
|
||||
dev_control = self.getDeviceController('vbd')
|
||||
|
||||
config['devid'] = dev_control.createDevice(config)
|
||||
|
||||
try:
|
||||
devid = dev_control.createDevice(config)
|
||||
dev_control.waitForDevice(devid)
|
||||
self.info.device_update(dev_uuid,
|
||||
cfg_xenapi = {'devid': devid})
|
||||
except Exception, exn:
|
||||
log.exception(exn)
|
||||
del self.info['devices'][dev_uuid]
|
||||
self.info['vbd_refs'].remove(dev_uuid)
|
||||
raise
|
||||
|
||||
return dev_uuid
|
||||
|
||||
def create_phantom_vbd_with_vdi(self, xenapi_vbd, vdi_image_path):
|
||||
@@ -2303,9 +2347,21 @@ class XendDomainInfo:
|
||||
raise XendError('Failed to create device')
|
||||
|
||||
if self.state == XEN_API_VM_POWER_STATE_RUNNING:
|
||||
_, config = self.info['devices'][dev_uuid]
|
||||
config['devid'] = self.getDeviceController('vif').createDevice(config)
|
||||
|
||||
_, config = self.info['devices'][dev_uuid]
|
||||
dev_control = self.getDeviceController('vif')
|
||||
|
||||
try:
|
||||
devid = dev_control.createDevice(config)
|
||||
dev_control.waitForDevice(devid)
|
||||
self.info.device_update(dev_uuid,
|
||||
cfg_xenapi = {'devid': devid})
|
||||
except Exception, exn:
|
||||
log.exception(exn)
|
||||
del self.info['devices'][dev_uuid]
|
||||
self.info['vif_refs'].remove(dev_uuid)
|
||||
raise
|
||||
|
||||
return dev_uuid
|
||||
|
||||
def create_vtpm(self, xenapi_vtpm):
|
||||
@@ -2372,7 +2428,7 @@ class XendDomainInfo:
|
||||
def __str__(self):
|
||||
return '<domain id=%s name=%s memory=%s state=%s>' % \
|
||||
(str(self.domid), self.info['name_label'],
|
||||
str(self.info['memory_static_min']), DOM_STATES[self.state])
|
||||
str(self.info['memory_dynamic_max']), DOM_STATES[self.state])
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
@@ -59,6 +59,18 @@ if 'TRACE' not in logging.__dict__:
|
||||
return filename, frame[2]
|
||||
logging.Logger.findCaller = findCaller
|
||||
|
||||
# Work around a bug in Python's inspect module: findsource is supposed to
|
||||
# raise IOError if it fails, with other functions in that module coping
|
||||
# with that, but some people are seeing IndexError raised from there.
|
||||
if hasattr(inspect, 'findsource'):
|
||||
real_findsource = getattr(inspect, 'findsource')
|
||||
def findsource(*args, **kwargs):
|
||||
try:
|
||||
return real_findsource(*args, **kwargs)
|
||||
except IndexError, exn:
|
||||
raise IOError(exn)
|
||||
inspect.findsource = findsource
|
||||
|
||||
|
||||
log = logging.getLogger("xend")
|
||||
|
||||
|
||||
@@ -530,7 +530,8 @@ class XendNode:
|
||||
info['cores_per_socket'] *
|
||||
info['threads_per_core'])
|
||||
info['cpu_mhz'] = info['cpu_khz'] / 1000
|
||||
# physinfo is in KiB
|
||||
|
||||
# physinfo is in KiB, need it in MiB
|
||||
info['total_memory'] = info['total_memory'] / 1024
|
||||
info['free_memory'] = info['free_memory'] / 1024
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ class XendVDI(AutoSaveObject):
|
||||
|
||||
SAVED_CFG = ['name_label',
|
||||
'name_description',
|
||||
'sector_size',
|
||||
'virtual_size',
|
||||
'physical_utilisation',
|
||||
'sharable',
|
||||
@@ -67,13 +66,22 @@ class XendVDI(AutoSaveObject):
|
||||
self.sr_uuid = sr_uuid
|
||||
self.name_label = ""
|
||||
self.name_description = ""
|
||||
self.sector_size = 1024
|
||||
self.virtual_size = 0
|
||||
self.physical_utilisation = 0
|
||||
self.sharable = False
|
||||
self.read_only = False
|
||||
self.type = "system"
|
||||
self.location = ''
|
||||
self.other_config = {}
|
||||
self.vbds = []
|
||||
|
||||
def addVBD(self, vbd_ref):
|
||||
self.vbds.append(vbd_ref)
|
||||
|
||||
def removeVBD(self, vbd_ref):
|
||||
self.vbds.remove(vbd_ref)
|
||||
|
||||
def getVBDs(self):
|
||||
return self.vbds
|
||||
|
||||
def load_config_dict(self, cfg):
|
||||
"""Loads configuration into the object from a dict.
|
||||
@@ -144,11 +152,10 @@ class XendVDI(AutoSaveObject):
|
||||
'name_description': self.name_description,
|
||||
'virtual_size': self.virtual_size,
|
||||
'physical_utilisation': self.physical_utilisation,
|
||||
'sector_size': self.sector_size,
|
||||
'sharable': False,
|
||||
'readonly': False,
|
||||
'SR': self.sr_uuid,
|
||||
'location': self.get_location(),
|
||||
'other_config': self.other_config,
|
||||
'VBDs': []}
|
||||
|
||||
def get_location(self):
|
||||
@@ -163,12 +170,11 @@ class XendQCoWVDI(XendVDI):
|
||||
self.cfg_path = cfg_path
|
||||
self.physical_utilisation = psize
|
||||
self.virtual_size = vsize
|
||||
self.sector_size = 512
|
||||
self.auto_save = True
|
||||
self.location = 'tap:qcow:%s' % self.qcow_path
|
||||
self.other_config['location'] = 'tap:qcow:%s' % self.qcow_path
|
||||
|
||||
def get_location(self):
|
||||
return self.location
|
||||
return self.other_config['location']
|
||||
|
||||
class XendLocalVDI(XendVDI):
|
||||
def __init__(self, vdi_struct):
|
||||
@@ -182,11 +188,10 @@ class XendLocalVDI(XendVDI):
|
||||
self.name_description = vdi_struct.get('name_description', '')
|
||||
self.physical_utilisation = 0
|
||||
self.virtual_size = 0
|
||||
self.sector_size = 0
|
||||
self.type = vdi_struct.get('type', '')
|
||||
self.sharable = vdi_struct.get('sharable', False)
|
||||
self.read_only = vdi_struct.get('read_only', False)
|
||||
self.location = vdi_struct.get('location', 'file:/dev/null')
|
||||
self.other_config = vdi_struct.get('other_config', {})
|
||||
|
||||
def get_location(self):
|
||||
return self.location
|
||||
return self.other_config['location']
|
||||
@@ -0,0 +1,118 @@
|
||||
<!ENTITY % HTMLlat1 PUBLIC
|
||||
"-//W3C//ENTITIES Latin 1 for XHTML//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
|
||||
%HTMLlat1;
|
||||
<!ENTITY % HTMLsymbol PUBLIC
|
||||
"-//W3C//ENTITIES Symbols for XHTML//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent">
|
||||
%HTMLsymbol;
|
||||
<!ENTITY % HTMLspecial PUBLIC
|
||||
"-//W3C//ENTITIES Special for XHTML//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent">
|
||||
%HTMLspecial;
|
||||
<!-- a Uniform Resource Identifier, see [RFC2396] -->
|
||||
<!ENTITY % URI "CDATA">
|
||||
<!ENTITY % NAMEID "name ID #REQUIRED">
|
||||
<!ENTITY % CRASH_BEHAVIOUR "( destroy
|
||||
| coredump_and_destroy
|
||||
| restart
|
||||
| coredump_and_restart
|
||||
| preserve
|
||||
| rename_restart )">
|
||||
<!ENTITY % NORMAL_EXIT "( destroy | restart )">
|
||||
<!ENTITY % VDI_TYPE "( system
|
||||
| user
|
||||
| ephemeral
|
||||
| suspend
|
||||
| crashdump )">
|
||||
|
||||
<!ELEMENT xm (vm*,
|
||||
vdi*)>
|
||||
|
||||
<!ELEMENT version (#PCDATA)>
|
||||
|
||||
<!ELEMENT vm (name,
|
||||
version,
|
||||
(pv|hvm),
|
||||
memory,
|
||||
vbd*,
|
||||
vif*,
|
||||
vcpu_param*,
|
||||
other_config*)>
|
||||
<!ATTLIST vm is_a_template CDATA #REQUIRED
|
||||
auto_power_on CDATA #REQUIRED
|
||||
vcpus_max CDATA #REQUIRED
|
||||
vcpus_at_startup CDATA #REQUIRED
|
||||
actions_after_shutdown %NORMAL_EXIT; #REQUIRED
|
||||
actions_after_reboot %NORMAL_EXIT; #REQUIRED
|
||||
actions_after_crash %CRASH_BEHAVIOUR; #REQUIRED
|
||||
platform_std_VGA CDATA #REQUIRED
|
||||
platform_serial CDATA #REQUIRED
|
||||
platform_localtime CDATA #REQUIRED
|
||||
platform_clock_offet CDATA #REQUIRED
|
||||
platform_enable_audio CDATA #REQUIRED
|
||||
PCI_bus CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT memory EMPTY>
|
||||
<!ATTLIST memory static_min CDATA #REQUIRED
|
||||
static_max CDATA #REQUIRED
|
||||
dynamic_min CDATA #REQUIRED
|
||||
dynamic_max CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT vbd (qos_algorithm_param*)>
|
||||
<!ATTLIST vbd %NAMEID;
|
||||
mode (RO | RW) #REQUIRED
|
||||
vdi IDREF #REQUIRED
|
||||
device CDATA #REQUIRED
|
||||
bootable CDATA #REQUIRED
|
||||
type (CD | disk) #REQUIRED
|
||||
qos_algorithm_type CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT vif (qos_algorithm_param*)>
|
||||
<!ATTLIST vif %NAMEID;
|
||||
mac CDATA #REQUIRED
|
||||
mtu CDATA #REQUIRED
|
||||
device CDATA #REQUIRED
|
||||
qos_algorithm_type CDATA #REQUIRED
|
||||
bridge CDATA #IMPLIED
|
||||
network CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT pv EMPTY>
|
||||
<!ATTLIST pv kernel CDATA #REQUIRED
|
||||
bootloader CDATA #REQUIRED
|
||||
ramdisk CDATA #REQUIRED
|
||||
args CDATA #REQUIRED
|
||||
bootloader_args CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT hvm (boot_param*)>
|
||||
<!ATTLIST hvm boot_policy CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT boot_param EMPTY>
|
||||
<!ATTLIST boot_param key CDATA #REQUIRED
|
||||
value CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT vdi (name)>
|
||||
<!ATTLIST vdi %NAMEID;
|
||||
src %URI; #REQUIRED
|
||||
type %VDI_TYPE; #REQUIRED
|
||||
size CDATA #REQUIRED
|
||||
shareable CDATA #REQUIRED
|
||||
read_only CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT name (label,
|
||||
description)>
|
||||
|
||||
<!ELEMENT label (#PCDATA)>
|
||||
<!ELEMENT description (#PCDATA)>
|
||||
|
||||
<!ELEMENT vcpu_param EMPTY>
|
||||
<!ATTLIST vcpu_param key CDATA #REQUIRED
|
||||
value CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT other_config EMPTY>
|
||||
<!ATTLIST other_config key CDATA #REQUIRED
|
||||
value CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT qos_algorithm_param EMPTY>
|
||||
<!ATTLIST qos_algorithm_param key CDATA #REQUIRED
|
||||
value CDATA #REQUIRED>
|
||||
@@ -28,12 +28,13 @@ import time
|
||||
import xmlrpclib
|
||||
|
||||
from xen.xend import sxp
|
||||
from xen.xend import PrettyPrint
|
||||
from xen.xend import PrettyPrint as SXPPrettyPrint
|
||||
from xen.xend import osdep
|
||||
import xen.xend.XendClient
|
||||
from xen.xend.XendBootloader import bootloader
|
||||
from xen.util import blkif
|
||||
from xen.util import security
|
||||
from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm
|
||||
|
||||
from xen.xm.opts import *
|
||||
|
||||
@@ -98,6 +99,11 @@ gopts.opt('dryrun', short='n',
|
||||
use="Dry run - prints the resulting configuration in SXP but "
|
||||
"does not create the domain.")
|
||||
|
||||
gopts.opt('xmldryrun', short='x',
|
||||
fn=set_true, default=0,
|
||||
use="XML dry run - prints the resulting configuration in XML but "
|
||||
"does not create the domain.")
|
||||
|
||||
gopts.opt('paused', short='p',
|
||||
fn=set_true, default=0,
|
||||
use='Leave the domain paused after it is created.')
|
||||
@@ -1241,34 +1247,59 @@ def main(argv):
|
||||
except IOError, exn:
|
||||
raise OptionError("Cannot read file %s: %s" % (config, exn[1]))
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
from xen.xm.xenapi_create import sxp2xml
|
||||
sxp2xml_inst = sxp2xml()
|
||||
doc = sxp2xml_inst.convert_sxp_to_xml(config, transient=True)
|
||||
|
||||
if opts.vals.dryrun:
|
||||
PrettyPrint.prettyprint(config)
|
||||
SXPPrettyPrint.prettyprint(config)
|
||||
|
||||
if opts.vals.xmldryrun and serverType == SERVER_XEN_API:
|
||||
from xml.dom.ext import PrettyPrint as XMLPrettyPrint
|
||||
XMLPrettyPrint(doc)
|
||||
|
||||
if opts.vals.dryrun or opts.vals.xmldryrun:
|
||||
return
|
||||
|
||||
if opts.vals.console_autoconnect:
|
||||
do_console(sxp.child_value(config, 'name', -1))
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
from xen.xm.xenapi_create import xenapi_create
|
||||
xenapi_create_inst = xenapi_create()
|
||||
vm_refs = xenapi_create_inst.create(document = doc)
|
||||
|
||||
map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs)
|
||||
else:
|
||||
if not create_security_check(config):
|
||||
raise security.ACMError('Security Configuration prevents domain from starting')
|
||||
else:
|
||||
if opts.vals.console_autoconnect:
|
||||
cpid = os.fork()
|
||||
if cpid != 0:
|
||||
for i in range(10):
|
||||
# Catch failure of the create process
|
||||
time.sleep(1)
|
||||
(p, rv) = os.waitpid(cpid, os.WNOHANG)
|
||||
if os.WIFEXITED(rv):
|
||||
if os.WEXITSTATUS(rv) != 0:
|
||||
sys.exit(os.WEXITSTATUS(rv))
|
||||
try:
|
||||
# Acquire the console of the created dom
|
||||
name = sxp.child_value(config, 'name', -1)
|
||||
dom = server.xend.domain(name)
|
||||
domid = int(sxp.child_value(dom, 'domid', '-1'))
|
||||
console.execConsole(domid)
|
||||
except:
|
||||
pass
|
||||
print("Could not start console\n");
|
||||
sys.exit(0)
|
||||
dom = make_domain(opts, config)
|
||||
|
||||
raise security.ACMError(
|
||||
'Security Configuration prevents domain from starting')
|
||||
dom = make_domain(opts, config)
|
||||
|
||||
def do_console(domain_name):
|
||||
cpid = os.fork()
|
||||
if cpid != 0:
|
||||
for i in range(10):
|
||||
# Catch failure of the create process
|
||||
time.sleep(1)
|
||||
(p, rv) = os.waitpid(cpid, os.WNOHANG)
|
||||
if os.WIFEXITED(rv):
|
||||
if os.WEXITSTATUS(rv) != 0:
|
||||
sys.exit(os.WEXITSTATUS(rv))
|
||||
try:
|
||||
# Acquire the console of the created dom
|
||||
if serverType == SERVER_XEN_API:
|
||||
domid = server.xenapi.VM.get_domid(
|
||||
get_single_vm(domain_name))
|
||||
else:
|
||||
dom = server.xend.domain(domain_name)
|
||||
domid = int(sxp.child_value(dom, 'domid', '-1'))
|
||||
console.execConsole(domid)
|
||||
except:
|
||||
pass
|
||||
print("Could not start console\n");
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
||||
+298
-66
@@ -33,11 +33,11 @@ import getopt
|
||||
import socket
|
||||
import traceback
|
||||
import xmlrpclib
|
||||
import traceback
|
||||
import time
|
||||
import datetime
|
||||
from select import select
|
||||
import xml.dom.minidom
|
||||
from xen.util.blkif import blkdev_name_to_number
|
||||
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore', category=FutureWarning)
|
||||
@@ -49,18 +49,19 @@ from xen.xend.XendConstants import *
|
||||
|
||||
from xen.xm.opts import OptionError, Opts, wrap, set_true
|
||||
from xen.xm import console
|
||||
from xen.util import security
|
||||
from xen.util.xmlrpclib2 import ServerProxy
|
||||
|
||||
import XenAPI
|
||||
|
||||
|
||||
# getopt.gnu_getopt is better, but only exists in Python 2.3+. Use
|
||||
# getopt.getopt if gnu_getopt is not available. This will mean that options
|
||||
# may only be specified before positional arguments.
|
||||
if not hasattr(getopt, 'gnu_getopt'):
|
||||
getopt.gnu_getopt = getopt.getopt
|
||||
|
||||
XM_CONFIG_FILE = '/etc/xen/xm-config.xml'
|
||||
XM_CONFIG_FILE_ENVVAR = 'XM_CONFIG_FILE'
|
||||
XM_CONFIG_FILE_DEFAULT = '/etc/xen/xm-config.xml'
|
||||
|
||||
# Supported types of server
|
||||
SERVER_LEGACY_XMLRPC = 'LegacyXMLRPC'
|
||||
@@ -351,13 +352,14 @@ all_commands = (domain_commands + host_commands + scheduler_commands +
|
||||
# Configuration File Parsing
|
||||
##
|
||||
|
||||
xmConfigFile = os.getenv(XM_CONFIG_FILE_ENVVAR, XM_CONFIG_FILE_DEFAULT)
|
||||
config = None
|
||||
if os.path.isfile(XM_CONFIG_FILE):
|
||||
if os.path.isfile(xmConfigFile):
|
||||
try:
|
||||
config = xml.dom.minidom.parse(XM_CONFIG_FILE)
|
||||
config = xml.dom.minidom.parse(xmConfigFile)
|
||||
except:
|
||||
print >>sys.stderr, ('Ignoring invalid configuration file %s.' %
|
||||
XM_CONFIG_FILE)
|
||||
xmConfigFile)
|
||||
|
||||
def parseServer():
|
||||
if config:
|
||||
@@ -491,6 +493,18 @@ def usage(cmd = None):
|
||||
#
|
||||
####################################################################
|
||||
|
||||
def get_default_SR():
|
||||
return [sr_ref
|
||||
for sr_ref in server.xenapi.SR.get_all()
|
||||
if server.xenapi.SR.get_type(sr_ref) == "local"][0]
|
||||
|
||||
def get_default_Network():
|
||||
return [network_ref
|
||||
for network_ref in server.xenapi.network.get_all()][0]
|
||||
|
||||
def map2sxp(m):
|
||||
return [[k, m[k]] for k in m.keys()]
|
||||
|
||||
def arg_check(args, name, lo, hi = -1):
|
||||
n = len([i for i in args if i != '--'])
|
||||
|
||||
@@ -673,10 +687,41 @@ def xm_restore(args):
|
||||
|
||||
|
||||
def getDomains(domain_names, state, full = 0):
|
||||
if domain_names:
|
||||
return [server.xend.domain(dom, full) for dom in domain_names]
|
||||
if serverType == SERVER_XEN_API:
|
||||
doms_sxp = []
|
||||
doms_dict = []
|
||||
dom_refs = server.xenapi.VM.get_all()
|
||||
for dom_ref in dom_refs:
|
||||
dom_rec = server.xenapi.VM.get_record(dom_ref)
|
||||
dom_metrics_ref = server.xenapi.VM.get_metrics(dom_ref)
|
||||
dom_metrics = server.xenapi.VM_metrics.get_record(dom_metrics_ref)
|
||||
dom_rec.update({'name': dom_rec['name_label'],
|
||||
'memory_actual': int(dom_metrics['memory_actual'])/1024,
|
||||
'vcpus': dom_metrics['vcpus_number'],
|
||||
'state': '-----',
|
||||
'cpu_time': dom_metrics['vcpus_utilisation']})
|
||||
|
||||
doms_sxp.append(['domain'] + map2sxp(dom_rec))
|
||||
doms_dict.append(dom_rec)
|
||||
|
||||
if domain_names:
|
||||
doms = [['domain'] + map2sxp(dom) for dom in doms_dict
|
||||
if dom["name"] in domain_names]
|
||||
|
||||
if len(doms) > 0:
|
||||
return doms
|
||||
else:
|
||||
print "Error: no domain%s named %s" % \
|
||||
(len(domain_names) > 1 and 's' or '',
|
||||
', '.join(domain_names))
|
||||
sys.exit(-1)
|
||||
else:
|
||||
return doms_sxp
|
||||
else:
|
||||
return server.xend.domains_with_state(True, state, full)
|
||||
if domain_names:
|
||||
return [server.xend.domain(dom, full) for dom in domain_names]
|
||||
else:
|
||||
return server.xend.domains_with_state(True, state, full)
|
||||
|
||||
|
||||
def xm_list(args):
|
||||
@@ -735,20 +780,39 @@ def parse_doms_info(info):
|
||||
else:
|
||||
up_time = time.time() - start_time
|
||||
|
||||
return {
|
||||
parsed_info = {
|
||||
'domid' : get_info('domid', str, ''),
|
||||
'name' : get_info('name', str, '??'),
|
||||
'mem' : get_info('memory_dynamic_min', int, 0),
|
||||
'state' : get_info('state', str, ''),
|
||||
'cpu_time' : get_info('cpu_time', float, 0.0),
|
||||
|
||||
# VCPUs is the number online when the VM is up, or the number
|
||||
# configured otherwise.
|
||||
'vcpus' : get_info('online_vcpus', int,
|
||||
get_info('vcpus', int, 0)),
|
||||
'up_time' : up_time,
|
||||
'seclabel' : security.get_security_printlabel(info),
|
||||
'up_time' : up_time
|
||||
}
|
||||
|
||||
# We're not supporting security stuff just yet via XenAPI
|
||||
|
||||
if serverType != SERVER_XEN_API:
|
||||
from xen.util import security
|
||||
parsed_info['seclabel'] = security.get_security_printlabel(info)
|
||||
else:
|
||||
parsed_info['seclabel'] = ""
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
parsed_info['mem'] = get_info('memory_actual', int, 0) / 1024
|
||||
cpu_times = get_info('cpu_time', lambda x : (x), 0.0)
|
||||
if sum(cpu_times.values()) > 0:
|
||||
parsed_info['cpu_time'] = sum(cpu_times.values()) / float(len(cpu_times.values()))
|
||||
else:
|
||||
parsed_info['cpu_time'] = 0
|
||||
else:
|
||||
parsed_info['mem'] = get_info('memory', int,0)
|
||||
parsed_info['cpu_time'] = get_info('cpu_time', float, 0.0)
|
||||
|
||||
return parsed_info
|
||||
|
||||
def check_sched_type(sched):
|
||||
if serverType == SERVER_XEN_API:
|
||||
current = server.xenapi.host.get_sched_policy(server.xenapi.session.get_this_host())
|
||||
@@ -797,17 +861,22 @@ def xm_label_list(doms):
|
||||
output = []
|
||||
format = '%(name)-32s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s ' \
|
||||
'%(cpu_time)8.1f %(seclabel)9s'
|
||||
|
||||
for dom in doms:
|
||||
d = parse_doms_info(dom)
|
||||
if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
|
||||
if not d['seclabel']:
|
||||
d['seclabel'] = 'ERROR'
|
||||
elif security.active_policy in ['DEFAULT']:
|
||||
d['seclabel'] = 'DEFAULT'
|
||||
else:
|
||||
d['seclabel'] = 'INACTIVE'
|
||||
output.append((format % d, d['seclabel']))
|
||||
|
||||
if serverType != SERVER_XEN_API:
|
||||
from xen.util import security
|
||||
|
||||
for dom in doms:
|
||||
d = parse_doms_info(dom)
|
||||
|
||||
if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
|
||||
if not d['seclabel']:
|
||||
d['seclabel'] = 'ERROR'
|
||||
elif security.active_policy in ['DEFAULT']:
|
||||
d['seclabel'] = 'DEFAULT'
|
||||
else:
|
||||
d['seclabel'] = 'INACTIVE'
|
||||
|
||||
output.append((format % d, d['seclabel']))
|
||||
|
||||
#sort by labels
|
||||
output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower()))
|
||||
@@ -816,7 +885,6 @@ def xm_label_list(doms):
|
||||
|
||||
|
||||
def xm_vcpu_list(args):
|
||||
|
||||
if args:
|
||||
dominfo = map(server.xend.domain.getVCPUInfo, args)
|
||||
else:
|
||||
@@ -1112,7 +1180,7 @@ def xm_mem_set(args):
|
||||
dom = args[0]
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
mem_target = int_unit(args[1], 'k') * 1024
|
||||
mem_target = int_unit(args[1], 'm') * 1024 * 1024
|
||||
server.xenapi.VM.set_memory_dynamic_max(get_single_vm(dom), mem_target)
|
||||
server.xenapi.VM.set_memory_dynamic_min(get_single_vm(dom), mem_target)
|
||||
else:
|
||||
@@ -1464,7 +1532,10 @@ def xm_sysrq(args):
|
||||
arg_check(args, "sysrq", 2)
|
||||
dom = args[0]
|
||||
req = args[1]
|
||||
server.xend.domain.send_sysrq(dom, req)
|
||||
if serverType == SERVER_XEN_API:
|
||||
server.xenapi.VM.send_sysrq(get_single_vm(dom), req)
|
||||
else:
|
||||
server.xend.domain.send_sysrq(dom, req)
|
||||
|
||||
def xm_trigger(args):
|
||||
vcpu = 0
|
||||
@@ -1474,12 +1545,23 @@ def xm_trigger(args):
|
||||
trigger = args[1]
|
||||
if len(args) == 3:
|
||||
vcpu = int(args[2])
|
||||
|
||||
server.xend.domain.send_trigger(dom, trigger, vcpu)
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
server.xenapi.VM.send_trigger(get_single_vm(dom), trigger, vcpu)
|
||||
else:
|
||||
server.xend.domain.send_trigger(dom, trigger, vcpu)
|
||||
|
||||
def xm_debug_keys(args):
|
||||
arg_check(args, "debug-keys", 1)
|
||||
server.xend.node.send_debug_keys(str(args[0]))
|
||||
|
||||
keys = str(args[0])
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
server.xenapi.host.send_debug_keys(
|
||||
server.xenapi.session.get_this_host(),
|
||||
keys)
|
||||
else:
|
||||
server.xend.node.send_debug_keys(keys)
|
||||
|
||||
def xm_top(args):
|
||||
arg_check(args, "top", 0)
|
||||
@@ -1605,12 +1687,21 @@ def xm_network_list(args):
|
||||
(use_long, params) = arg_check_for_resource_list(args, "network-list")
|
||||
|
||||
dom = params[0]
|
||||
if use_long:
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom))
|
||||
vif_properties = \
|
||||
map(server.xenapi.VIF.get_runtime_properties, vif_refs)
|
||||
devs = map(lambda (handle, properties): [handle, map2sxp(properties)],
|
||||
zip(range(len(vif_properties)), vif_properties))
|
||||
else:
|
||||
devs = server.xend.domain.getDeviceSxprs(dom, 'vif')
|
||||
|
||||
if use_long:
|
||||
map(PrettyPrint.prettyprint, devs)
|
||||
else:
|
||||
hdr = 0
|
||||
for x in server.xend.domain.getDeviceSxprs(dom, 'vif'):
|
||||
for x in devs:
|
||||
if hdr == 0:
|
||||
print 'Idx BE MAC Addr. handle state evt-ch tx-/rx-ring-ref BE-path'
|
||||
hdr = 1
|
||||
@@ -1630,12 +1721,25 @@ def xm_block_list(args):
|
||||
(use_long, params) = arg_check_for_resource_list(args, "block-list")
|
||||
|
||||
dom = params[0]
|
||||
if use_long:
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
|
||||
vbd_properties = \
|
||||
map(server.xenapi.VBD.get_runtime_properties, vbd_refs)
|
||||
vbd_devs = \
|
||||
map(server.xenapi.VBD.get_device, vbd_refs)
|
||||
vbd_devids = \
|
||||
map(blkdev_name_to_number, vbd_devs)
|
||||
devs = map(lambda (devid, prop): [devid, map2sxp(prop)],
|
||||
zip(vbd_devids, vbd_properties))
|
||||
else:
|
||||
devs = server.xend.domain.getDeviceSxprs(dom, 'vbd')
|
||||
|
||||
if use_long:
|
||||
map(PrettyPrint.prettyprint, devs)
|
||||
else:
|
||||
hdr = 0
|
||||
for x in server.xend.domain.getDeviceSxprs(dom, 'vbd'):
|
||||
for x in devs:
|
||||
if hdr == 0:
|
||||
print 'Vdev BE handle state evt-ch ring-ref BE-path'
|
||||
hdr = 1
|
||||
@@ -1690,13 +1794,17 @@ def parse_block_configuration(args):
|
||||
if len(args) == 5:
|
||||
vbd.append(['backend', args[4]])
|
||||
|
||||
# verify that policy permits attaching this resource
|
||||
if security.on():
|
||||
dominfo = server.xend.domain(dom)
|
||||
label = security.get_security_printlabel(dominfo)
|
||||
else:
|
||||
label = None
|
||||
security.res_security_check(args[1], label)
|
||||
if serverType != SERVER_XEN_API:
|
||||
# verify that policy permits attaching this resource
|
||||
from xen.util import security
|
||||
|
||||
if security.on():
|
||||
dominfo = server.xend.domain(dom)
|
||||
label = security.get_security_printlabel(dominfo)
|
||||
else:
|
||||
label = None
|
||||
|
||||
security.res_security_check(args[1], label)
|
||||
|
||||
return (dom, vbd)
|
||||
|
||||
@@ -1704,8 +1812,45 @@ def parse_block_configuration(args):
|
||||
def xm_block_attach(args):
|
||||
arg_check(args, 'block-attach', 4, 5)
|
||||
|
||||
(dom, vbd) = parse_block_configuration(args)
|
||||
server.xend.domain.device_create(dom, vbd)
|
||||
if serverType == SERVER_XEN_API:
|
||||
dom = args[0]
|
||||
uname = args[1]
|
||||
dev = args[2]
|
||||
mode = args[3]
|
||||
|
||||
# First create new VDI
|
||||
vdi_record = {
|
||||
"name_label": "vdi" + str(uname.__hash__()),
|
||||
"name_description": "",
|
||||
"SR": get_default_SR(),
|
||||
"virtual_size": 0,
|
||||
"sector_size": 512,
|
||||
"type": "system",
|
||||
"sharable": False,
|
||||
"read_only": mode!="w",
|
||||
"other_config": {"location": uname}
|
||||
}
|
||||
|
||||
vdi_ref = server.xenapi.VDI.create(vdi_record)
|
||||
|
||||
# Now create new VBD
|
||||
|
||||
vbd_record = {
|
||||
"VM": get_single_vm(dom),
|
||||
"VDI": vdi_ref,
|
||||
"device": dev,
|
||||
"bootable": True,
|
||||
"mode": mode=="w" and "RW" or "RO",
|
||||
"type": "Disk",
|
||||
"qos_algorithm_type": "",
|
||||
"qos_algorithm_params": {}
|
||||
}
|
||||
|
||||
server.xenapi.VBD.create(vbd_record)
|
||||
|
||||
else:
|
||||
(dom, vbd) = parse_block_configuration(args)
|
||||
server.xend.domain.device_create(dom, vbd)
|
||||
|
||||
|
||||
def xm_block_configure(args):
|
||||
@@ -1723,15 +1868,65 @@ def xm_network_attach(args):
|
||||
vif_params = ['type', 'mac', 'bridge', 'ip', 'script', \
|
||||
'backend', 'vifname', 'rate', 'model']
|
||||
|
||||
for a in args[1:]:
|
||||
vif_param = a.split("=")
|
||||
if len(vif_param) != 2 or vif_param[1] == '' or \
|
||||
vif_param[0] not in vif_params:
|
||||
err("Invalid argument: %s" % a)
|
||||
usage('network-attach')
|
||||
vif.append(vif_param)
|
||||
if serverType == SERVER_XEN_API:
|
||||
vif_record = {
|
||||
"device": "eth0",
|
||||
"network": get_default_Network(),
|
||||
"VM": get_single_vm(dom),
|
||||
"MAC": "",
|
||||
"MTU": "",
|
||||
"qos_algorithm_type": "",
|
||||
"qos_algorithm_params": {},
|
||||
"other_config": {}
|
||||
}
|
||||
|
||||
server.xend.domain.device_create(dom, vif)
|
||||
def set(keys, val):
|
||||
record = vif_record
|
||||
for key in keys[:-1]:
|
||||
record = record[key]
|
||||
record[keys[-1]] = val
|
||||
|
||||
vif_conv = {
|
||||
'type':
|
||||
lambda x: None,
|
||||
'mac':
|
||||
lambda x: set(['MAC'], x),
|
||||
'bridge':
|
||||
lambda x: set(['network'], get_net_from_bridge(x)),
|
||||
'ip':
|
||||
lambda x: set(['other_config', 'ip'], x),
|
||||
'script':
|
||||
lambda x: set(['other_config', 'script'], x),
|
||||
'backend':
|
||||
lambda x: set(['other_config', 'backend'], x),
|
||||
'vifname':
|
||||
lambda x: set(['device'], x),
|
||||
'rate':
|
||||
lambda x: set(['qos_algorithm_params', 'rate'], x),
|
||||
'model':
|
||||
lambda x: None
|
||||
}
|
||||
|
||||
for a in args[1:]:
|
||||
vif_param = a.split("=")
|
||||
if len(vif_param) != 2 or vif_param[1] == '' or \
|
||||
vif_param[0] not in vif_params:
|
||||
err("Invalid argument: %s" % a)
|
||||
usage('network-attach')
|
||||
else:
|
||||
vif_conv[vif_param[0]](vif_param[1])
|
||||
|
||||
print str(vif_record)
|
||||
server.xenapi.VIF.create(vif_record)
|
||||
else:
|
||||
for a in args[1:]:
|
||||
vif_param = a.split("=")
|
||||
if len(vif_param) != 2 or vif_param[1] == '' or \
|
||||
vif_param[0] not in vif_params:
|
||||
err("Invalid argument: %s" % a)
|
||||
usage('network-attach')
|
||||
vif.append(vif_param)
|
||||
server.xend.domain.device_create(dom, vif)
|
||||
|
||||
|
||||
def detach(args, command, deviceClass):
|
||||
@@ -1751,16 +1946,49 @@ def detach(args, command, deviceClass):
|
||||
|
||||
|
||||
def xm_block_detach(args):
|
||||
try:
|
||||
detach(args, 'block-detach', 'vbd')
|
||||
return
|
||||
except:
|
||||
pass
|
||||
detach(args, 'block-detach', 'tap')
|
||||
if serverType == SERVER_XEN_API:
|
||||
arg_check(args, "xm_block_detach", 2, 3)
|
||||
dom = args[0]
|
||||
dev = args[1]
|
||||
vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
|
||||
vbd_refs = [vbd_ref for vbd_ref in vbd_refs
|
||||
if server.xenapi.VBD.get_device(vbd_ref) == dev]
|
||||
if len(vbd_refs) > 0:
|
||||
vbd_ref = vbd_refs[0]
|
||||
vdi_ref = server.xenapi.VBD.get_VDI(vbd_ref)
|
||||
|
||||
server.xenapi.VBD.destroy(vbd_ref)
|
||||
|
||||
if len(server.xenapi.VDI.get_VBDs(vdi_ref)) <= 0:
|
||||
server.xenapi.VDI.destroy(vdi_ref)
|
||||
else:
|
||||
raise OptionError("Cannot find device '%s' in domain '%s'"
|
||||
% (dev,dom))
|
||||
else:
|
||||
try:
|
||||
detach(args, 'block-detach', 'vbd')
|
||||
return
|
||||
except:
|
||||
pass
|
||||
detach(args, 'block-detach', 'tap')
|
||||
|
||||
def xm_network_detach(args):
|
||||
detach(args, 'network-detach', 'vif')
|
||||
if serverType == SERVER_XEN_API:
|
||||
arg_check(args, "xm_block_detach", 2, 3)
|
||||
dom = args[0]
|
||||
devid = args[1]
|
||||
vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom))
|
||||
vif_refs = [vif_ref for vif_ref in vif_refs
|
||||
if server.xenapi.VIF.\
|
||||
get_runtime_properties(vif_ref)["handle"] == devid]
|
||||
if len(vif_refs) > 0:
|
||||
vif_ref = vif_refs[0]
|
||||
|
||||
server.xenapi.VIF.destroy(vif_ref)
|
||||
else:
|
||||
print "Cannot find device '%s' in domain '%s'" % (devid,dom)
|
||||
else:
|
||||
detach(args, 'network-detach', 'vif')
|
||||
|
||||
|
||||
def xm_vnet_list(args):
|
||||
@@ -2001,13 +2229,17 @@ def _run_cmd(cmd, cmd_name, args):
|
||||
err(str(e))
|
||||
_usage(cmd_name)
|
||||
print e.usage
|
||||
except security.ACMError, e:
|
||||
err(str(e))
|
||||
except:
|
||||
print "Unexpected error:", sys.exc_info()[0]
|
||||
print
|
||||
print "Please report to xen-devel@lists.xensource.com"
|
||||
raise
|
||||
except Exception, e:
|
||||
if serverType != SERVER_XEN_API:
|
||||
from xen.util import security
|
||||
if isinstance(e, security.ACMError):
|
||||
err(str(e))
|
||||
return False, 1
|
||||
else:
|
||||
print "Unexpected error:", sys.exc_info()[0]
|
||||
print
|
||||
print "Please report to xen-devel@lists.xensource.com"
|
||||
raise
|
||||
|
||||
return False, 1
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ from xen.xend import PrettyPrint
|
||||
from xen.xend import sxp
|
||||
from xen.xend import XendClient
|
||||
|
||||
from xen.xm.main import serverType, SERVER_XEN_API
|
||||
from xen.xm.xenapi_create import *
|
||||
|
||||
from opts import *
|
||||
from create import *
|
||||
|
||||
@@ -65,7 +68,15 @@ def main(argv):
|
||||
|
||||
if opts.vals.dryrun:
|
||||
PrettyPrint.prettyprint(config)
|
||||
else:
|
||||
return
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
sxp2xml_inst = sxp2xml()
|
||||
doc = sxp2xml_inst.convert_sxp_to_xml(config)
|
||||
|
||||
xenapi_create_inst = xenapi_create()
|
||||
vm_refs = xenapi_create_inst.create(document = doc)
|
||||
else:
|
||||
make_unstarted_domain(opts, config)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -51,7 +51,7 @@ gopts.opt('reboot', short='R',
|
||||
|
||||
def wait_reboot(opts, doms, rcs):
|
||||
if serverType == SERVER_XEN_API:
|
||||
opts.err("Cannot wait for reboot w/ XenAPI (yet)")
|
||||
opts.err("Cannot wait for reboot w/ XenAPI (yet)")
|
||||
|
||||
while doms:
|
||||
alive = server.xend.domains(0)
|
||||
@@ -73,7 +73,7 @@ def wait_reboot(opts, doms, rcs):
|
||||
def wait_shutdown(opts, doms):
|
||||
while doms:
|
||||
if serverType == SERVER_XEN_API:
|
||||
alive = [dom for dom in server.xenapi.VM.get_all()
|
||||
alive = [dom for dom in server.xenapi.VM.get_all()
|
||||
if server.xenapi.VM.get_power_state(dom) ==
|
||||
XEN_API_VM_POWER_STATE[XEN_API_VM_POWER_STATE_RUNNING]]
|
||||
else:
|
||||
@@ -91,16 +91,16 @@ def wait_shutdown(opts, doms):
|
||||
def shutdown(opts, doms, mode, wait):
|
||||
rcs = {}
|
||||
for d in doms:
|
||||
if serverType == SERVER_XEN_API:
|
||||
if mode == 'halt':
|
||||
server.xenapi.VM.clean_shutdown(d)
|
||||
if mode == 'reboot':
|
||||
server.xenapi.VM.clean_reboot(d)
|
||||
if mode == 'poweroff':
|
||||
server.xenapi.VM.clean_shutdown(d)
|
||||
else:
|
||||
rcs[d] = server.xend.domain.getRestartCount(d)
|
||||
server.xend.domain.shutdown(d, mode)
|
||||
if serverType == SERVER_XEN_API:
|
||||
if mode == 'halt':
|
||||
server.xenapi.VM.clean_shutdown(d)
|
||||
if mode == 'reboot':
|
||||
server.xenapi.VM.clean_reboot(d)
|
||||
if mode == 'poweroff':
|
||||
server.xenapi.VM.clean_shutdown(d)
|
||||
else:
|
||||
rcs[d] = server.xend.domain.getRestartCount(d)
|
||||
server.xend.domain.shutdown(d, mode)
|
||||
|
||||
if wait:
|
||||
if mode == 'reboot':
|
||||
@@ -135,7 +135,7 @@ def main_dom(opts, args):
|
||||
if len(args) > 1: opts.err('No multiple domain parameters allowed')
|
||||
dom = args[0]
|
||||
if serverType == SERVER_XEN_API:
|
||||
dom = get_single_vm(dom)
|
||||
dom = get_single_vm(dom)
|
||||
mode = shutdown_mode(opts)
|
||||
shutdown(opts, [ dom ], mode, opts.vals.wait)
|
||||
|
||||
|
||||
@@ -0,0 +1,636 @@
|
||||
#!/usr/bin/python
|
||||
#============================================================================
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2.1 of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#============================================================================
|
||||
# Copyright (C) 2007 Tom Wilkie <tom.wilkie@gmail.com>
|
||||
#============================================================================
|
||||
"""Domain creation using new XenAPI
|
||||
"""
|
||||
|
||||
from xen.xm.main import server, get_default_SR
|
||||
from xml.dom.minidom import parse, getDOMImplementation
|
||||
from xml.dom.ext import PrettyPrint
|
||||
from xml.parsers.xmlproc import xmlproc, xmlval, xmldtd
|
||||
from xen.xend import sxp
|
||||
from xen.xend.XendAPIConstants import XEN_API_ON_NORMAL_EXIT, \
|
||||
XEN_API_ON_CRASH_BEHAVIOUR
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
import traceback
|
||||
|
||||
def log(_, msg):
|
||||
#print "> " + msg
|
||||
pass
|
||||
|
||||
DEBUG = 0
|
||||
|
||||
def get_name_label(node):
|
||||
name_node = node.getElementsByTagName("name")[0]
|
||||
label_node = name_node.getElementsByTagName("label")[0]
|
||||
return " ".join([child.nodeValue for child in label_node.childNodes])
|
||||
|
||||
def get_name_description(node):
|
||||
name_node = node.getElementsByTagName("name")[0]
|
||||
description_node = name_node.getElementsByTagName("description")[0]
|
||||
return " ".join([child.nodeValue for child in description_node.childNodes])
|
||||
|
||||
def get_text_in_child_node(node, child):
|
||||
tag_node = node.getElementsByTagName(child)[0]
|
||||
return tag_node.nodeValue
|
||||
|
||||
def get_child_node_attribute(node, child, attribute):
|
||||
tag_node = node.getElementsByTagName(child)[0]
|
||||
return tag_node.attributes[attribute].value
|
||||
|
||||
def get_child_nodes_as_dict(node, child_name,
|
||||
key_attribute_name,
|
||||
value_attribute_name):
|
||||
return dict([(child.attributes[key_attribute_name].value,
|
||||
child.attributes[value_attribute_name].value)
|
||||
for child in node.getElementsByTagName(child_name)])
|
||||
|
||||
def try_quietly(fn, *args):
|
||||
try:
|
||||
return fn(*args)
|
||||
except:
|
||||
return None
|
||||
|
||||
class xenapi_create:
|
||||
|
||||
def __init__(self):
|
||||
self.DEFAULT_STORAGE_REPOSITORY = get_default_SR()
|
||||
|
||||
self.dtd = "/usr/lib/python/xen/xm/create.dtd"
|
||||
|
||||
def create(self, filename=None, document=None):
|
||||
"""
|
||||
Create a domain from an XML file or DOM tree
|
||||
"""
|
||||
if filename is not None:
|
||||
self.check_dtd(file)
|
||||
document = parse(file)
|
||||
elif document is not None:
|
||||
self.check_dom_against_dtd(document)
|
||||
|
||||
self.check_doc(document)
|
||||
|
||||
vdis = document.getElementsByTagName("vdi")
|
||||
vdi_refs_dict = self.create_vdis(vdis)
|
||||
|
||||
try:
|
||||
vms = document.getElementsByTagName("vm")
|
||||
return self.create_vms(vms, vdi_refs_dict)
|
||||
except Exception, exn:
|
||||
try_quietly(self.cleanup_vdis(vdi_refs_dict))
|
||||
raise exn
|
||||
|
||||
# Methods to check xml file
|
||||
# try to use dtd to check where possible
|
||||
def check_dtd(self, file):
|
||||
"""
|
||||
Check file against DTD.
|
||||
Use this if possible as it gives nice
|
||||
error messages
|
||||
"""
|
||||
dtd = xmldtd.load_dtd(self.dtd)
|
||||
parser = xmlproc.XMLProcessor()
|
||||
parser.set_application(xmlval.ValidatingApp(dtd, parser))
|
||||
parser.dtd = dtd
|
||||
parser.ent = dtd
|
||||
parser.parse_resource(file)
|
||||
|
||||
def check_dom_against_dtd(self, dom):
|
||||
"""
|
||||
Check DOM again DTD.
|
||||
Doesn't give as nice error messages.
|
||||
(no location info)
|
||||
"""
|
||||
dtd = xmldtd.load_dtd(self.dtd)
|
||||
app = xmlval.ValidatingApp(dtd, self)
|
||||
app.set_locator(self)
|
||||
self.dom2sax(dom, app)
|
||||
|
||||
# Get errors back from ValidatingApp
|
||||
def report_error(self, number, args=None):
|
||||
self.errors = xmlproc.errors.english
|
||||
try:
|
||||
msg = self.errors[number]
|
||||
if args != None:
|
||||
msg = msg % args
|
||||
except KeyError:
|
||||
msg = self.errors[4002] % number # Unknown err msg :-)
|
||||
print msg
|
||||
sys.exit(-1)
|
||||
|
||||
# Here for compatibility with ValidatingApp
|
||||
def get_line(self):
|
||||
return -1
|
||||
|
||||
def get_column(self):
|
||||
return -1
|
||||
|
||||
def dom2sax(self, dom, app):
|
||||
"""
|
||||
Take a dom tree and tarverse it,
|
||||
issuing SAX calls to app.
|
||||
"""
|
||||
for child in dom.childNodes:
|
||||
if child.nodeType == child.TEXT_NODE:
|
||||
data = child.nodeValue
|
||||
app.handle_data(data, 0, len(data))
|
||||
else:
|
||||
app.handle_start_tag(
|
||||
child.nodeName,
|
||||
self.attrs_to_dict(child.attributes))
|
||||
self.dom2sax(child, app)
|
||||
app.handle_end_tag(child.nodeName)
|
||||
|
||||
def attrs_to_dict(self, attrs):
|
||||
return dict(attrs.items())
|
||||
|
||||
#
|
||||
# Checks which cannot be done with dtd
|
||||
#
|
||||
def check_doc(self, doc):
|
||||
vms = doc.getElementsByTagName("vm")
|
||||
self.check_vms(vms)
|
||||
|
||||
def check_vms(self, vms):
|
||||
map(self.check_vm, vms)
|
||||
|
||||
def check_vm(self, vm):
|
||||
vifs = vm.getElementsByTagName("vif")
|
||||
self.check_vifs(vifs)
|
||||
|
||||
def check_vifs(self, vifs):
|
||||
map(self.check_vif, vifs)
|
||||
|
||||
def check_vif(self, vif):
|
||||
"""
|
||||
Check that the vif has
|
||||
either a bridge or network
|
||||
name but not both
|
||||
"""
|
||||
if "bridge" in vif.attributes.keys() \
|
||||
and "network" in vif.attributes.keys():
|
||||
raise "You cannot specify both a bridge and\
|
||||
a network name."
|
||||
|
||||
# Cleanup methods here
|
||||
def cleanup_vdis(self, vdi_refs_dict):
|
||||
map(self.cleanup_vdi, vdi_refs_dict.values())
|
||||
|
||||
def cleanup_vdi(self, vdi_ref):
|
||||
server.xenapi.VDI.destroy(vdi_ref)
|
||||
|
||||
def cleanup_vms(self, vm_refs):
|
||||
map(self.cleanup_vm, vm_refs)
|
||||
|
||||
def cleanup_vm(self, vm_ref):
|
||||
server.xenapi.VM.destroy(vm_ref)
|
||||
|
||||
# Create methods here
|
||||
def create_vdis(self, vdis):
|
||||
log(DEBUG, "create_vdis")
|
||||
return dict(map(self.create_vdi, vdis))
|
||||
|
||||
def create_vdi(self, vdi):
|
||||
log(DEBUG, "create_vdi")
|
||||
|
||||
vdi_record = {
|
||||
"name_label": get_name_label(vdi),
|
||||
"name_description": get_name_description(vdi),
|
||||
"SR": self.DEFAULT_STORAGE_REPOSITORY,
|
||||
"virtual_size": vdi.attributes["size"].value,
|
||||
"type": vdi.attributes["type"].value,
|
||||
"shareable": vdi.attributes["shareable"].value,
|
||||
"read_only": vdi.attributes["read_only"].value,
|
||||
"other_config": {"location":
|
||||
vdi.attributes["src"].value}
|
||||
}
|
||||
|
||||
key = vdi.attributes["name"].value
|
||||
value = server.xenapi.VDI.create(vdi_record)
|
||||
|
||||
return (key, value)
|
||||
|
||||
def create_vms(self, vms, vdis):
|
||||
log(DEBUG, "create_vms")
|
||||
return map(lambda vm: self.create_vm(vm, vdis), vms)
|
||||
|
||||
def create_vm(self, vm, vdis):
|
||||
log(DEBUG, "create_vm")
|
||||
|
||||
vm_record = {
|
||||
"name_label":
|
||||
get_name_label(vm),
|
||||
"name_description":
|
||||
get_name_description(vm),
|
||||
"user_version":
|
||||
get_text_in_child_node(vm, "version"),
|
||||
"is_a_template":
|
||||
vm.attributes["is_a_template"].value,
|
||||
"auto_power_on":
|
||||
vm.attributes["auto_power_on"].value,
|
||||
"memory_static_max":
|
||||
get_child_node_attribute(vm, "memory", "static_max"),
|
||||
"memory_static_min":
|
||||
get_child_node_attribute(vm, "memory", "static_min"),
|
||||
"memory_dynamic_max":
|
||||
get_child_node_attribute(vm, "memory", "dynamic_max"),
|
||||
"memory_dynamic_min":
|
||||
get_child_node_attribute(vm, "memory", "dynamic_min"),
|
||||
"vcpus_params":
|
||||
get_child_nodes_as_dict(vm, "vcpu_param", "key", "value"),
|
||||
"vcpus_max":
|
||||
vm.attributes["vcpus_max"].value,
|
||||
"vcpus_at_startup":
|
||||
vm.attributes["vcpus_at_startup"].value,
|
||||
"actions_after_shutdown":
|
||||
vm.attributes["actions_after_shutdown"].value,
|
||||
"actions_after_reboot":
|
||||
vm.attributes["actions_after_reboot"].value,
|
||||
"actions_after_crash":
|
||||
vm.attributes["actions_after_crash"].value,
|
||||
"platform_std_VGA":
|
||||
vm.attributes["platform_std_VGA"].value,
|
||||
"platform_serial":
|
||||
vm.attributes["platform_serial"].value,
|
||||
"platform_localtime":
|
||||
vm.attributes["platform_localtime"].value,
|
||||
"platform_clock_offet":
|
||||
vm.attributes["platform_clock_offet"].value,
|
||||
"platform_enable_audio":
|
||||
vm.attributes["platform_enable_audio"].value,
|
||||
"PCI_bus":
|
||||
vm.attributes["platform_enable_audio"].value,
|
||||
"other_config":
|
||||
get_child_nodes_as_dict(vm, "other_config", "key", "value")
|
||||
}
|
||||
|
||||
if len(vm.getElementsByTagName("pv")) > 0:
|
||||
vm_record.update({
|
||||
"PV_bootloader":
|
||||
get_child_node_attribute(vm, "pv", "bootloader"),
|
||||
"PV_kernel":
|
||||
get_child_node_attribute(vm, "pv", "kernel"),
|
||||
"PV_ramdisk":
|
||||
get_child_node_attribute(vm, "pv", "ramdisk"),
|
||||
"PV_args":
|
||||
get_child_node_attribute(vm, "pv", "args"),
|
||||
"PV_bootloader_args":
|
||||
get_child_node_attribute(vm, "pv", "bootloader_args")
|
||||
})
|
||||
else:
|
||||
hvm = vm.getElementsByTagName("hvm")[0]
|
||||
vm_record.update({
|
||||
"HVM_boot_policy":
|
||||
get_child_node_attribute(vm, "hvm", "boot_policy"),
|
||||
"HVM_boot_params":
|
||||
get_child_nodes_as_dict(hvm, "boot_params", "key", "value")
|
||||
})
|
||||
try:
|
||||
vm_ref = server.xenapi.VM.create(vm_record)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
sys.exit(-1)
|
||||
|
||||
# Now create vbds
|
||||
|
||||
vbds = vm.getElementsByTagName("vbd")
|
||||
|
||||
self.create_vbds(vm_ref, vbds, vdis)
|
||||
|
||||
# Now create vifs
|
||||
|
||||
vifs = vm.getElementsByTagName("vif")
|
||||
|
||||
self.create_vifs(vm_ref, vifs)
|
||||
|
||||
return vm_ref
|
||||
|
||||
def create_vbds(self, vm_ref, vbds, vdis):
|
||||
log(DEBUG, "create_vbds")
|
||||
return map(lambda vbd: self.create_vbd(vm_ref, vbd, vdis), vbds)
|
||||
|
||||
def create_vbd(self, vm_ref, vbd, vdis):
|
||||
log(DEBUG, "create_vbd")
|
||||
|
||||
vbd_record = {
|
||||
"VM":
|
||||
vm_ref,
|
||||
"VDI":
|
||||
vdis[vbd.attributes["vdi"].value],
|
||||
"device":
|
||||
vbd.attributes["device"].value,
|
||||
"bootable":
|
||||
vbd.attributes["bootable"].value,
|
||||
"mode":
|
||||
vbd.attributes["mode"].value,
|
||||
"type":
|
||||
vbd.attributes["type"].value,
|
||||
"qos_algorithm_type":
|
||||
vbd.attributes["qos_algorithm_type"].value,
|
||||
"qos_algorithm_params":
|
||||
get_child_nodes_as_dict(vbd,
|
||||
"qos_algorithm_param", "key", "value")
|
||||
}
|
||||
|
||||
return server.xenapi.VBD.create(vbd_record)
|
||||
|
||||
def create_vifs(self, vm_ref, vifs):
|
||||
log(DEBUG, "create_vifs")
|
||||
return map(lambda vif: self.create_vif(vm_ref, vif), vifs)
|
||||
|
||||
def create_vif(self, vm_ref, vif):
|
||||
log(DEBUG, "create_vif")
|
||||
|
||||
if "bridge" in vif.attributes.keys():
|
||||
raise "Not allowed to add by bridge just yet"
|
||||
elif "network" in vif.attributes.keys():
|
||||
network = [network_ref
|
||||
for network_ref in server.xenapi.network.get_all()
|
||||
if server.xenapi.network.get_name_label(network_ref)
|
||||
== vif.attributes["network"].value][0]
|
||||
else:
|
||||
network = self._get_network_ref()
|
||||
|
||||
vif_record = {
|
||||
"device":
|
||||
vif.attributes["device"].value,
|
||||
"network":
|
||||
network,
|
||||
"VM":
|
||||
vm_ref,
|
||||
"MAC":
|
||||
vif.attributes["mac"].value,
|
||||
"MTU":
|
||||
vif.attributes["mtu"].value,
|
||||
"qos_algorithm_type":
|
||||
vif.attributes["qos_algorithm_type"].value,
|
||||
"qos_algorithm_params":
|
||||
get_child_nodes_as_dict(vif,
|
||||
"qos_algorithm_param", "key", "value")
|
||||
}
|
||||
|
||||
return server.xenapi.VIF.create(vif_record)
|
||||
|
||||
_network_refs = []
|
||||
|
||||
def _get_network_ref(self):
|
||||
try:
|
||||
return self._network_refs.pop(0)
|
||||
except IndexError:
|
||||
self._network_refs = server.xenapi.network.get_all()
|
||||
return self._network_refs.pop(0)
|
||||
|
||||
def get_child_by_name(exp, childname, default = None):
|
||||
try:
|
||||
return [child for child in sxp.children(exp)
|
||||
if child[0] == childname][0][1]
|
||||
except:
|
||||
return default
|
||||
|
||||
# Convert old sxp into new xml
|
||||
|
||||
class sxp2xml:
|
||||
|
||||
def convert_sxp_to_xml(self, config, transient=False):
|
||||
|
||||
devices = [child for child in sxp.children(config)
|
||||
if len(child) > 0 and child[0] == "device"]
|
||||
|
||||
vbds_sxp = map(lambda x: x[1], [device for device in devices
|
||||
if device[1][0] == "vbd"])
|
||||
|
||||
vifs_sxp = map(lambda x: x[1], [device for device in devices
|
||||
if device[1][0] == "vif"])
|
||||
# Create XML Document
|
||||
|
||||
impl = getDOMImplementation()
|
||||
|
||||
document = impl.createDocument(None, "xm", None)
|
||||
|
||||
# Lets make the VM tag..
|
||||
|
||||
vm = document.createElement("vm")
|
||||
|
||||
# Some string compatibility
|
||||
|
||||
actions_after_shutdown \
|
||||
= get_child_by_name(config, "on_poweroff", "destroy")
|
||||
actions_after_reboot \
|
||||
= get_child_by_name(config, "on_reboot", "restart")
|
||||
actions_after_crash \
|
||||
= get_child_by_name(config, "on_crash", "restart")
|
||||
|
||||
def conv_chk(val, vals):
|
||||
val.replace("-", "_")
|
||||
if val not in vals:
|
||||
raise "Invalid value: " + val
|
||||
else:
|
||||
return val
|
||||
|
||||
actions_after_shutdown = conv_chk(actions_after_shutdown,\
|
||||
XEN_API_ON_NORMAL_EXIT)
|
||||
actions_after_reboot = conv_chk(actions_after_reboot, \
|
||||
XEN_API_ON_NORMAL_EXIT)
|
||||
actions_after_crash = conv_chk(actions_after_crash, \
|
||||
XEN_API_ON_CRASH_BEHAVIOUR)
|
||||
# Flesh out tag attributes
|
||||
|
||||
vm.attributes["is_a_template"] = "false"
|
||||
vm.attributes["auto_power_on"] = "false"
|
||||
vm.attributes["actions_after_shutdown"] \
|
||||
= actions_after_shutdown
|
||||
vm.attributes["actions_after_reboot"] \
|
||||
= actions_after_reboot
|
||||
vm.attributes["actions_after_crash"] \
|
||||
= actions_after_crash
|
||||
vm.attributes["platform_std_VGA"] = "false"
|
||||
vm.attributes["platform_serial"] = ""
|
||||
vm.attributes["platform_localtime"] = ""
|
||||
vm.attributes["platform_clock_offet"] = ""
|
||||
vm.attributes["platform_enable_audio"] = ""
|
||||
vm.attributes["PCI_bus"] = ""
|
||||
|
||||
vm.attributes["vcpus_max"] \
|
||||
= str(get_child_by_name(config, "vcpus", 1))
|
||||
vm.attributes["vcpus_at_startup"] \
|
||||
= str(get_child_by_name(config, "vcpus", 1))
|
||||
|
||||
# Make the name tag
|
||||
|
||||
vm.appendChild(self.make_name_tag(
|
||||
get_child_by_name(config, "name"), document))
|
||||
|
||||
# Make version tag
|
||||
|
||||
version = document.createElement("version")
|
||||
version.appendChild(document.createTextNode("1.0"))
|
||||
vm.appendChild(version)
|
||||
|
||||
# Make pv or hvm tag
|
||||
|
||||
image = get_child_by_name(config, "image")
|
||||
|
||||
if image[0] == "linux":
|
||||
pv = document.createElement("pv")
|
||||
pv.attributes["kernel"] \
|
||||
= get_child_by_name(image, "kernel", "")
|
||||
pv.attributes["bootloader"] = ""
|
||||
pv.attributes["ramdisk"] \
|
||||
= get_child_by_name(image, "ramdisk", "")
|
||||
pv.attributes["args"] \
|
||||
= "root=" + get_child_by_name(image, "root", "") \
|
||||
+ " " + get_child_by_name(image, "args", "")
|
||||
pv.attributes["bootloader_args"] = ""
|
||||
|
||||
vm.appendChild(pv)
|
||||
elif image[0] == "hvm":
|
||||
hvm = document.createElement("hvm")
|
||||
hvm.attributes["boot_policy"] = ""
|
||||
|
||||
vm.appendChild(hvm)
|
||||
|
||||
# Make memory tag
|
||||
|
||||
memory = document.createElement("memory")
|
||||
|
||||
memory_str = str(int(
|
||||
get_child_by_name(config, "memory"))*1024*1024)
|
||||
|
||||
memory.attributes["static_min"] = str(0)
|
||||
memory.attributes["static_max"] = memory_str
|
||||
memory.attributes["dynamic_min"] = memory_str
|
||||
memory.attributes["dynamic_max"] = memory_str
|
||||
|
||||
if get_child_by_name(config, "maxmem"):
|
||||
memory.attributes["static_max"] = \
|
||||
str(int(get_child_by_name(config, "maxmem")*1024*1024))
|
||||
|
||||
vm.appendChild(memory)
|
||||
|
||||
# And now the vbds
|
||||
|
||||
vbds = map(lambda vbd: self.extract_vbd(vbd, document), vbds_sxp)
|
||||
|
||||
map(vm.appendChild, vbds)
|
||||
|
||||
# And now the vifs
|
||||
|
||||
vifs = map(lambda vif: self.extract_vif(vif, document), vifs_sxp)
|
||||
|
||||
map(vm.appendChild, vifs)
|
||||
|
||||
# transient?
|
||||
|
||||
if transient:
|
||||
other_config = document.createElement("other_config")
|
||||
other_config.attributes["key"] = "transient"
|
||||
other_config.attributes["value"] = "True"
|
||||
vm.appendChild(other_config)
|
||||
|
||||
# Add it to doc_root
|
||||
|
||||
document.documentElement.appendChild(vm)
|
||||
|
||||
# We want to pull out vdis
|
||||
|
||||
vdis = map(lambda vdb: self.extract_vdi(vdb, document), vbds_sxp)
|
||||
|
||||
map(document.documentElement.appendChild, vdis)
|
||||
|
||||
return document
|
||||
|
||||
def make_name_tag(self, label_text, document):
|
||||
name = document.createElement("name")
|
||||
|
||||
label = document.createElement("label")
|
||||
label.appendChild(document.createTextNode(str(label_text)))
|
||||
name.appendChild(label)
|
||||
|
||||
description = document.createElement("description")
|
||||
description.appendChild(document.createTextNode(" "))
|
||||
name.appendChild(description)
|
||||
|
||||
return name
|
||||
|
||||
def extract_vbd(self, vbd_sxp, document):
|
||||
src = get_child_by_name(vbd_sxp, "uname")
|
||||
name = str(src.__hash__())
|
||||
|
||||
vbd = document.createElement("vbd")
|
||||
|
||||
vbd.attributes["name"] = "vdb" + name
|
||||
vbd.attributes["vdi"] = "vdi" + name
|
||||
vbd.attributes["mode"] \
|
||||
= get_child_by_name(vbd_sxp, "mode") != "w" \
|
||||
and "RO" or "RW"
|
||||
vbd.attributes["device"] \
|
||||
= get_child_by_name(vbd_sxp, "dev")
|
||||
vbd.attributes["bootable"] = "1"
|
||||
vbd.attributes["type"] = "disk"
|
||||
vbd.attributes["qos_algorithm_type"] = ""
|
||||
|
||||
return vbd
|
||||
|
||||
def extract_vdi(self, vbd_sxp, document):
|
||||
src = get_child_by_name(vbd_sxp, "uname")
|
||||
name = "vdi" + str(src.__hash__())
|
||||
path = src[src.find(":")+1:]
|
||||
|
||||
vdi = document.createElement("vdi")
|
||||
|
||||
vdi.attributes["src"] = src
|
||||
vdi.attributes["read_only"] \
|
||||
= (get_child_by_name(vbd_sxp, "mode") != "w") \
|
||||
and "true" or "false"
|
||||
vdi.attributes["size"] \
|
||||
= str(os.path.getsize(path))
|
||||
vdi.attributes["type"] = "system"
|
||||
vdi.attributes["shareable"] = "false"
|
||||
vdi.attributes["name"] = name
|
||||
|
||||
vdi.appendChild(self.make_name_tag(name, document))
|
||||
|
||||
return vdi
|
||||
|
||||
def extract_vif(self, vif_sxp, document):
|
||||
|
||||
vif = document.createElement("vif")
|
||||
|
||||
dev = get_child_by_name(vif_sxp, "vifname", "eth0")
|
||||
|
||||
vif.attributes["name"] \
|
||||
= "vif" + str(dev.__hash__())
|
||||
vif.attributes["mac"] \
|
||||
= get_child_by_name(vif_sxp, "mac", "")
|
||||
vif.attributes["mtu"] \
|
||||
= get_child_by_name(vif_sxp, "mtu", "")
|
||||
vif.attributes["device"] = dev
|
||||
vif.attributes["qos_algorithm_type"] = ""
|
||||
|
||||
if get_child_by_name(vif_sxp, "bridge") is not None:
|
||||
vif.attributes["bridge"] \
|
||||
= get_child_by_name(vif_sxp, "bridge")
|
||||
|
||||
return vif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
PROGRAMS_INSTALL_DIR = /usr/$(LIBDIR)/xen/bin
|
||||
|
||||
INCLUDES += -I $(XEN_LIBXC)
|
||||
INCLUDES += -I $(XEN_LIBXC) -I $(XEN_XENSTORE)
|
||||
|
||||
CFLAGS += -Werror -fno-strict-aliasing
|
||||
CFLAGS += $(INCLUDES)
|
||||
@@ -22,9 +22,9 @@ CFLAGS += $(INCLUDES)
|
||||
CFLAGS += -Wp,-MD,.$(@F).d
|
||||
PROG_DEP = .*.d
|
||||
|
||||
PROGRAMS = xc_restore xc_save readnotes
|
||||
PROGRAMS = xc_restore xc_save readnotes
|
||||
|
||||
LDLIBS = -L$(XEN_LIBXC) -lxenguest -lxenctrl
|
||||
LDLIBS = -L$(XEN_LIBXC) -L$(XEN_XENSTORE) -lxenguest -lxenctrl -lxenstore
|
||||
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
+127
-2
@@ -12,7 +12,13 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <xs.h>
|
||||
#include <xenctrl.h>
|
||||
#include <xenguest.h>
|
||||
|
||||
@@ -31,6 +37,123 @@ static int suspend(int domid)
|
||||
!strncmp(ans, "done\n", 5));
|
||||
}
|
||||
|
||||
/* For HVM guests, there are two sources of dirty pages: the Xen shadow
|
||||
* log-dirty bitmap, which we get with a hypercall, and qemu's version.
|
||||
* The protocol for getting page-dirtying data from qemu uses a
|
||||
* double-buffered shared memory interface directly between xc_save and
|
||||
* qemu-dm.
|
||||
*
|
||||
* xc_save calculates the size of the bitmaps and notifies qemu-dm
|
||||
* through the store that it wants to share the bitmaps. qemu-dm then
|
||||
* starts filling in the 'active' buffer.
|
||||
*
|
||||
* To change the buffers over, xc_save writes the other buffer number to
|
||||
* the store and waits for qemu to acknowledge that it is now writing to
|
||||
* the new active buffer. xc_save can then process and clear the old
|
||||
* active buffer. */
|
||||
|
||||
static char *qemu_active_path;
|
||||
static char *qemu_next_active_path;
|
||||
static struct xs_handle *xs;
|
||||
|
||||
/* Get qemu to change buffers. */
|
||||
static void qemu_flip_buffer(int domid, int next_active)
|
||||
{
|
||||
char digit = '0' + next_active;
|
||||
unsigned int len;
|
||||
char *active_str, **watch;
|
||||
struct timeval tv;
|
||||
fd_set fdset;
|
||||
|
||||
/* Tell qemu that we want it to start writing log-dirty bits to the
|
||||
* other buffer */
|
||||
if (!xs_write(xs, XBT_NULL, qemu_next_active_path, &digit, 1)) {
|
||||
errx(1, "can't write next-active to store path (%s)\n",
|
||||
qemu_next_active_path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Wait a while for qemu to signal that it has switched to the new
|
||||
* active buffer */
|
||||
read_again:
|
||||
tv.tv_sec = 5;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(xs_fileno(xs), &fdset);
|
||||
if ((select(xs_fileno(xs) + 1, &fdset, NULL, NULL, &tv)) != 1) {
|
||||
errx(1, "timed out waiting for qemu to switch buffers\n");
|
||||
exit(1);
|
||||
}
|
||||
watch = xs_read_watch(xs, &len);
|
||||
free(watch);
|
||||
|
||||
active_str = xs_read(xs, XBT_NULL, qemu_active_path, &len);
|
||||
if (active_str == NULL || active_str[0] - '0' != next_active)
|
||||
/* Watch fired but value is not yet right */
|
||||
goto read_again;
|
||||
}
|
||||
|
||||
static void * init_qemu_maps(int domid, unsigned int bitmap_size)
|
||||
{
|
||||
key_t key;
|
||||
char key_ascii[17] = {0,};
|
||||
int shmid = -1;
|
||||
void *seg;
|
||||
char *path, *p;
|
||||
|
||||
/* Make a shared-memory segment */
|
||||
while (shmid == -1)
|
||||
{
|
||||
key = rand(); /* No security, just a sequence of numbers */
|
||||
shmid = shmget(key, 2 * bitmap_size,
|
||||
IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
|
||||
if (shmid == -1 && errno != EEXIST)
|
||||
errx(1, "can't get shmem to talk to qemu-dm");
|
||||
}
|
||||
|
||||
/* Map it into our address space */
|
||||
seg = shmat(shmid, NULL, 0);
|
||||
if (seg == (void *) -1)
|
||||
errx(1, "can't map shmem to talk to qemu-dm");
|
||||
memset(seg, 0, 2 * bitmap_size);
|
||||
|
||||
/* Write the size of it into the first 32 bits */
|
||||
*(uint32_t *)seg = bitmap_size;
|
||||
|
||||
/* Tell qemu about it */
|
||||
if ((xs = xs_daemon_open()) == NULL)
|
||||
errx(1, "Couldn't contact xenstore");
|
||||
if (!(path = xs_get_domain_path(xs, domid)))
|
||||
errx(1, "can't get domain path in store");
|
||||
if (!(path = realloc(path, strlen(path)
|
||||
+ strlen("/logdirty/next-active") + 1)))
|
||||
errx(1, "no memory for constructing xenstore path");
|
||||
strcat(path, "/logdirty/");
|
||||
p = path + strlen(path);
|
||||
|
||||
strcpy(p, "key");
|
||||
snprintf(key_ascii, 17, "%16.16llx", (unsigned long long) key);
|
||||
if (!xs_write(xs, XBT_NULL, path, key_ascii, 16))
|
||||
errx(1, "can't write key (%s) to store path (%s)\n", key_ascii, path);
|
||||
|
||||
/* Watch for qemu's indication of the active buffer, and request it
|
||||
* to start writing to buffer 0 */
|
||||
strcpy(p, "active");
|
||||
if (!xs_watch(xs, path, "qemu-active-buffer"))
|
||||
errx(1, "can't set watch in store (%s)\n", path);
|
||||
if (!(qemu_active_path = strdup(path)))
|
||||
errx(1, "no memory for copying xenstore path");
|
||||
|
||||
strcpy(p, "next-active");
|
||||
if (!(qemu_next_active_path = strdup(path)))
|
||||
errx(1, "no memory for copying xenstore path");
|
||||
|
||||
qemu_flip_buffer(domid, 0);
|
||||
|
||||
free(path);
|
||||
return seg;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
@@ -52,9 +175,11 @@ main(int argc, char **argv)
|
||||
flags = atoi(argv[5]);
|
||||
|
||||
if (flags & XCFLAGS_HVM)
|
||||
ret = xc_hvm_save(xc_fd, io_fd, domid, maxit, max_f, flags, &suspend);
|
||||
ret = xc_hvm_save(xc_fd, io_fd, domid, maxit, max_f, flags,
|
||||
&suspend, &init_qemu_maps, &qemu_flip_buffer);
|
||||
else
|
||||
ret = xc_linux_save(xc_fd, io_fd, domid, maxit, max_f, flags, &suspend);
|
||||
ret = xc_linux_save(xc_fd, io_fd, domid, maxit, max_f, flags,
|
||||
&suspend);
|
||||
|
||||
xc_interface_close(xc_fd);
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@ except ConsoleError, e:
|
||||
|
||||
status, output = traceCommand("xm block-attach %s phy:NOT-EXIST xvda1 w" % domain.getName())
|
||||
eyecatcher = "Error"
|
||||
where = output.find(eyecatcher)
|
||||
where = re.compile(eyecatcher, re.IGNORECASE).search(output)
|
||||
if status == 0:
|
||||
FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status )
|
||||
elif where == -1:
|
||||
elif where is None:
|
||||
FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output )
|
||||
|
||||
try:
|
||||
|
||||
@@ -31,10 +31,10 @@ except ConsoleError, e:
|
||||
|
||||
status, output = traceCommand("xm block-attach %s file:/dev/NOT-EXIST xvda1 w" % domain.getName())
|
||||
eyecatcher = "Error"
|
||||
where = output.find(eyecatcher)
|
||||
where = re.compile(eyecatcher, re.IGNORECASE).search(output)
|
||||
if status == 0:
|
||||
FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status )
|
||||
elif where == -1:
|
||||
elif where is None:
|
||||
FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output )
|
||||
|
||||
try:
|
||||
|
||||
@@ -12,6 +12,18 @@ def count_eth(console):
|
||||
FAIL(str(e))
|
||||
return len(run['output'].splitlines())
|
||||
|
||||
def get_state(domain_name, number):
|
||||
s, o = traceCommand("xm network-list %s | awk '/^%d/ {print $5}'" %
|
||||
(domain_name, number))
|
||||
print o
|
||||
|
||||
if s != 0:
|
||||
FAIL("network-list failed")
|
||||
if o == "":
|
||||
return 0
|
||||
else:
|
||||
return int(o)
|
||||
|
||||
def network_attach(domain_name, console):
|
||||
eths_before = count_eth(console)
|
||||
status, output = traceCommand("xm network-attach %s" % domain_name)
|
||||
@@ -30,6 +42,13 @@ def network_detach(domain_name, console, num=0):
|
||||
if status != 0:
|
||||
return -1, "xm network-detach returned invalid %i != 0" % status
|
||||
|
||||
for i in range(10):
|
||||
if get_state(domain_name, num) == 0:
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
FAIL("network-detach failed: device did not disappear")
|
||||
|
||||
eths_after = count_eth(console)
|
||||
if eths_after != (eths_before-1):
|
||||
return -2, "Network device was not actually disconnected from domU"
|
||||
|
||||
@@ -167,7 +167,8 @@ EXPORT_SYMBOL(notify_remote_via_irq);
|
||||
irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
unsigned int l1i, port;
|
||||
int cpu = smp_processor_id();
|
||||
/* XXX: All events are bound to vcpu0 but irq may be redirected. */
|
||||
int cpu = 0; /*smp_processor_id();*/
|
||||
irqreturn_t(*handler) (int, void *, struct pt_regs *);
|
||||
shared_info_t *s = shared_info_area;
|
||||
vcpu_info_t *v = &s->vcpu_info[cpu];
|
||||
|
||||
+3
-15
@@ -58,19 +58,7 @@ HDRS += $(wildcard $(BASEDIR)/include/asm-x86/hvm/*.h)
|
||||
HDRS += $(wildcard $(BASEDIR)/include/asm-x86/hvm/svm/*.h)
|
||||
HDRS += $(wildcard $(BASEDIR)/include/asm-x86/hvm/vmx/*.h)
|
||||
|
||||
# Test for at least GCC v3.2.x.
|
||||
gcc-ver = $(shell $(CC) -dumpversion | sed -e 's/^\(.\)\.\(.\)\.\(.\)/\$(1)/')
|
||||
ifeq ($(call gcc-ver,1),1)
|
||||
$(error gcc-1.x.x unsupported - upgrade to at least gcc-3.2.x)
|
||||
endif
|
||||
ifeq ($(call gcc-ver,1),2)
|
||||
$(error gcc-2.x.x unsupported - upgrade to at least gcc-3.2.x)
|
||||
endif
|
||||
ifeq ($(call gcc-ver,1),3)
|
||||
ifeq ($(call gcc-ver,2),0)
|
||||
$(error gcc-3.0.x unsupported - upgrade to at least gcc-3.2.x)
|
||||
endif
|
||||
ifeq ($(call gcc-ver,2),1)
|
||||
$(error gcc-3.1.x unsupported - upgrade to at least gcc-3.2.x)
|
||||
endif
|
||||
# Require GCC v3.4+ (to avoid issues with alignment constraints in Xen headers)
|
||||
ifneq ($(call cc-ver,$(CC),0x030400),y)
|
||||
$(error Xen requires at least gcc-3.4)
|
||||
endif
|
||||
+15
-9
@@ -29,6 +29,10 @@
|
||||
#define S_TO_NS 1000000000ULL /* 1s = 10^9 ns */
|
||||
#define S_TO_FS 1000000000000000ULL /* 1s = 10^15 fs */
|
||||
|
||||
/* Frequency_of_TSC / frequency_of_HPET = 32 */
|
||||
#define TSC_PER_HPET_TICK 32
|
||||
#define guest_time_hpet(v) (hvm_get_guest_time(v) / TSC_PER_HPET_TICK)
|
||||
|
||||
#define HPET_ID 0x000
|
||||
#define HPET_PERIOD 0x004
|
||||
#define HPET_CFG 0x010
|
||||
@@ -67,7 +71,9 @@
|
||||
#define HPET_TN_INT_ROUTE_CAP_MASK (0xffffffffULL \
|
||||
<< HPET_TN_INT_ROUTE_CAP_SHIFT)
|
||||
|
||||
#define hpet_tick_to_ns(h, tick) ((s_time_t)(tick)*S_TO_NS/h->tsc_freq)
|
||||
#define hpet_tick_to_ns(h, tick) ((s_time_t)(tick)* \
|
||||
(S_TO_NS*TSC_PER_HPET_TICK)/h->tsc_freq)
|
||||
|
||||
#define timer_config(h, n) (h->hpet.timers[n].config)
|
||||
#define timer_enabled(h, n) (timer_config(h, n) & HPET_TN_ENABLE)
|
||||
#define timer_is_periodic(h, n) (timer_config(h, n) & HPET_TN_PERIODIC)
|
||||
@@ -108,7 +114,7 @@ static inline int hpet_check_access_length(
|
||||
static inline uint64_t hpet_read_maincounter(HPETState *h)
|
||||
{
|
||||
if ( hpet_enabled(h) )
|
||||
return hvm_get_guest_time(h->vcpu) + h->mc_offset;
|
||||
return guest_time_hpet(h->vcpu) + h->mc_offset;
|
||||
else
|
||||
return h->hpet.mc64;
|
||||
}
|
||||
@@ -144,7 +150,7 @@ static void hpet_stop_timer(HPETState *h, unsigned int tn)
|
||||
|
||||
/* the number of HPET tick that stands for
|
||||
* 1/(2^10) second, namely, 0.9765625 milliseconds */
|
||||
#define HPET_TINY_TIME_SPAN (h->tsc_freq >> 10)
|
||||
#define HPET_TINY_TIME_SPAN ((h->tsc_freq >> 10) / TSC_PER_HPET_TICK)
|
||||
|
||||
static void hpet_set_timer(HPETState *h, unsigned int tn)
|
||||
{
|
||||
@@ -225,14 +231,14 @@ static void hpet_write(
|
||||
if ( !(old_val & HPET_CFG_ENABLE) && (new_val & HPET_CFG_ENABLE) )
|
||||
{
|
||||
/* Enable main counter and interrupt generation. */
|
||||
h->mc_offset = h->hpet.mc64 - hvm_get_guest_time(h->vcpu);
|
||||
h->mc_offset = h->hpet.mc64 - guest_time_hpet(h->vcpu);
|
||||
for ( i = 0; i < HPET_TIMER_NUM; i++ )
|
||||
hpet_set_timer(h, i);
|
||||
}
|
||||
else if ( (old_val & HPET_CFG_ENABLE) && !(new_val & HPET_CFG_ENABLE) )
|
||||
{
|
||||
/* Halt main counter and disable interrupt generation. */
|
||||
h->hpet.mc64 = h->mc_offset + hvm_get_guest_time(h->vcpu);
|
||||
h->hpet.mc64 = h->mc_offset + guest_time_hpet(h->vcpu);
|
||||
for ( i = 0; i < HPET_TIMER_NUM; i++ )
|
||||
hpet_stop_timer(h, i);
|
||||
}
|
||||
@@ -384,7 +390,7 @@ static int hpet_save(struct domain *d, hvm_domain_context_t *h)
|
||||
HPETState *hp = &d->arch.hvm_domain.pl_time.vhpet;
|
||||
|
||||
/* Write the proper value into the main counter */
|
||||
hp->hpet.mc64 = hp->mc_offset + hvm_get_guest_time(hp->vcpu);
|
||||
hp->hpet.mc64 = hp->mc_offset + guest_time_hpet(hp->vcpu);
|
||||
|
||||
/* Save the HPET registers */
|
||||
return hvm_save_entry(HPET, 0, h, &hp->hpet);
|
||||
@@ -400,7 +406,7 @@ static int hpet_load(struct domain *d, hvm_domain_context_t *h)
|
||||
return -EINVAL;
|
||||
|
||||
/* Recalculate the offset between the main counter and guest time */
|
||||
hp->mc_offset = hp->hpet.mc64 - hvm_get_guest_time(hp->vcpu);
|
||||
hp->mc_offset = hp->hpet.mc64 - guest_time_hpet(hp->vcpu);
|
||||
|
||||
/* Restart the timers */
|
||||
for ( i = 0; i < HPET_TIMER_NUM; i++ )
|
||||
@@ -425,8 +431,8 @@ void hpet_init(struct vcpu *v)
|
||||
h->hpet.capability = 0x8086A201ULL;
|
||||
|
||||
/* This is the number of femptoseconds per HPET tick. */
|
||||
/* Here we define HPET's frequency to be the same as the TSC's. */
|
||||
h->hpet.capability |= ((S_TO_FS/h->tsc_freq) << 32);
|
||||
/* Here we define HPET's frequency to be 1/32 of the TSC's */
|
||||
h->hpet.capability |= ((S_TO_FS*TSC_PER_HPET_TICK/h->tsc_freq) << 32);
|
||||
|
||||
for ( i = 0; i < HPET_TIMER_NUM; i++ )
|
||||
{
|
||||
|
||||
@@ -415,6 +415,17 @@ static int mmio_decode(int address_bytes, unsigned char *opcode,
|
||||
GET_OP_SIZE_FOR_NONEBYTE(*op_size);
|
||||
return mem_reg(*op_size, opcode, mmio_op, rex);
|
||||
|
||||
case 0x08: /* or r8, m8 */
|
||||
mmio_op->instr = INSTR_OR;
|
||||
*op_size = BYTE;
|
||||
GET_OP_SIZE_FOR_BYTE(size_reg);
|
||||
return reg_mem(size_reg, opcode, mmio_op, rex);
|
||||
|
||||
case 0x09: /* or r32/16, m32/16 */
|
||||
mmio_op->instr = INSTR_OR;
|
||||
GET_OP_SIZE_FOR_NONEBYTE(*op_size);
|
||||
return reg_mem(*op_size, opcode, mmio_op, rex);
|
||||
|
||||
case 0x0A: /* or m8, r8 */
|
||||
mmio_op->instr = INSTR_OR;
|
||||
*op_size = BYTE;
|
||||
|
||||
+49
-51
@@ -449,6 +449,9 @@ int svm_vmcb_restore(struct vcpu *v, struct hvm_hw_cpu *c)
|
||||
vmcb->rflags = c->eflags;
|
||||
|
||||
v->arch.hvm_svm.cpu_shadow_cr0 = c->cr0;
|
||||
vmcb->cr0 = c->cr0 | X86_CR0_WP | X86_CR0_ET;
|
||||
if ( !paging_mode_hap(v->domain) )
|
||||
vmcb->cr0 |= X86_CR0_PG;
|
||||
|
||||
#ifdef HVM_DEBUG_SUSPEND
|
||||
printk("%s: cr3=0x%"PRIx64", cr0=0x%"PRIx64", cr4=0x%"PRIx64".\n",
|
||||
@@ -482,7 +485,6 @@ int svm_vmcb_restore(struct vcpu *v, struct hvm_hw_cpu *c)
|
||||
* first.
|
||||
*/
|
||||
HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR3 c->cr3 = %"PRIx64"", c->cr3);
|
||||
/* current!=vcpu as not called by arch_vmx_do_launch */
|
||||
mfn = gmfn_to_mfn(v->domain, c->cr3 >> PAGE_SHIFT);
|
||||
if( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain) )
|
||||
goto bad_cr3;
|
||||
@@ -566,7 +568,7 @@ void svm_save_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data)
|
||||
data->msr_star = vmcb->star;
|
||||
data->msr_cstar = vmcb->cstar;
|
||||
data->msr_syscall_mask = vmcb->sfmask;
|
||||
data->msr_efer = vmcb->efer;
|
||||
data->msr_efer = v->arch.hvm_svm.cpu_shadow_efer;
|
||||
|
||||
data->tsc = hvm_get_guest_time(v);
|
||||
}
|
||||
@@ -581,7 +583,12 @@ void svm_load_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data)
|
||||
vmcb->star = data->msr_star;
|
||||
vmcb->cstar = data->msr_cstar;
|
||||
vmcb->sfmask = data->msr_syscall_mask;
|
||||
vmcb->efer = data->msr_efer;
|
||||
v->arch.hvm_svm.cpu_shadow_efer = data->msr_efer;
|
||||
vmcb->efer = data->msr_efer | EFER_SVME;
|
||||
/* VMCB's EFER.LME isn't set unless we're actually in long mode
|
||||
* (see long_mode_do_msr_write()) */
|
||||
if ( !(vmcb->efer & EFER_LMA) )
|
||||
vmcb->efer &= ~EFER_LME;
|
||||
|
||||
hvm_set_guest_time(v, data->tsc);
|
||||
}
|
||||
@@ -741,6 +748,14 @@ static void svm_set_tsc_offset(struct vcpu *v, u64 offset)
|
||||
static void svm_init_ap_context(
|
||||
struct vcpu_guest_context *ctxt, int vcpuid, int trampoline_vector)
|
||||
{
|
||||
struct vcpu *v;
|
||||
cpu_user_regs_t *regs;
|
||||
u16 cs_sel;
|
||||
|
||||
/* We know this is safe because hvm_bringup_ap() does it */
|
||||
v = current->domain->vcpu[vcpuid];
|
||||
regs = &v->arch.guest_context.user_regs;
|
||||
|
||||
memset(ctxt, 0, sizeof(*ctxt));
|
||||
|
||||
/*
|
||||
@@ -748,8 +763,19 @@ static void svm_init_ap_context(
|
||||
* passed to us is page alligned and is the physicall frame number for
|
||||
* the code. We will execute this code in real mode.
|
||||
*/
|
||||
cs_sel = trampoline_vector << 8;
|
||||
ctxt->user_regs.eip = 0x0;
|
||||
ctxt->user_regs.cs = (trampoline_vector << 8);
|
||||
ctxt->user_regs.cs = cs_sel;
|
||||
|
||||
/*
|
||||
* This is the launch of an AP; set state so that we begin executing
|
||||
* the trampoline code in real-mode.
|
||||
*/
|
||||
svm_do_vmmcall_reset_to_realmode(v, regs);
|
||||
/* Adjust the vmcb's hidden register state. */
|
||||
v->arch.hvm_svm.vmcb->rip = 0;
|
||||
v->arch.hvm_svm.vmcb->cs.sel = cs_sel;
|
||||
v->arch.hvm_svm.vmcb->cs.base = (cs_sel << 4);
|
||||
}
|
||||
|
||||
static void svm_init_hypercall_page(struct domain *d, void *hypercall_page)
|
||||
@@ -894,32 +920,6 @@ static void svm_load_cpu_guest_regs(
|
||||
svm_load_cpu_user_regs(v, regs);
|
||||
}
|
||||
|
||||
static void arch_svm_do_launch(struct vcpu *v)
|
||||
{
|
||||
svm_do_launch(v);
|
||||
|
||||
if ( paging_mode_hap(v->domain) ) {
|
||||
v->arch.hvm_svm.vmcb->h_cr3 = pagetable_get_paddr(v->domain->arch.phys_table);
|
||||
}
|
||||
|
||||
if ( v->vcpu_id != 0 )
|
||||
{
|
||||
cpu_user_regs_t *regs = ¤t->arch.guest_context.user_regs;
|
||||
u16 cs_sel = regs->cs;
|
||||
/*
|
||||
* This is the launch of an AP; set state so that we begin executing
|
||||
* the trampoline code in real-mode.
|
||||
*/
|
||||
svm_do_vmmcall_reset_to_realmode(v, regs);
|
||||
/* Adjust the state to execute the trampoline code.*/
|
||||
v->arch.hvm_svm.vmcb->rip = 0;
|
||||
v->arch.hvm_svm.vmcb->cs.sel= cs_sel;
|
||||
v->arch.hvm_svm.vmcb->cs.base = (cs_sel << 4);
|
||||
}
|
||||
|
||||
reset_stack_and_jump(svm_asm_do_launch);
|
||||
}
|
||||
|
||||
static void svm_ctxt_switch_from(struct vcpu *v)
|
||||
{
|
||||
svm_save_dr(v);
|
||||
@@ -941,16 +941,30 @@ static void svm_ctxt_switch_to(struct vcpu *v)
|
||||
svm_restore_dr(v);
|
||||
}
|
||||
|
||||
static void arch_svm_do_resume(struct vcpu *v)
|
||||
{
|
||||
if ( v->arch.hvm_svm.launch_core != smp_processor_id() )
|
||||
{
|
||||
v->arch.hvm_svm.launch_core = smp_processor_id();
|
||||
hvm_migrate_timers(v);
|
||||
}
|
||||
|
||||
hvm_do_resume(v);
|
||||
reset_stack_and_jump(svm_asm_do_resume);
|
||||
}
|
||||
|
||||
static int svm_vcpu_initialise(struct vcpu *v)
|
||||
{
|
||||
int rc;
|
||||
|
||||
v->arch.schedule_tail = arch_svm_do_launch;
|
||||
v->arch.schedule_tail = arch_svm_do_resume;
|
||||
v->arch.ctxt_switch_from = svm_ctxt_switch_from;
|
||||
v->arch.ctxt_switch_to = svm_ctxt_switch_to;
|
||||
|
||||
v->arch.hvm_svm.saved_irq_vector = -1;
|
||||
|
||||
v->arch.hvm_svm.launch_core = -1;
|
||||
|
||||
if ( (rc = svm_create_vmcb(v)) != 0 )
|
||||
{
|
||||
dprintk(XENLOG_WARNING,
|
||||
@@ -1014,10 +1028,12 @@ void svm_npt_detect(void)
|
||||
|
||||
/* check CPUID for nested paging support */
|
||||
cpuid(0x8000000A, &eax, &ebx, &ecx, &edx);
|
||||
if ( edx & 0x01 ) { /* nested paging */
|
||||
if ( edx & 0x01 ) /* nested paging */
|
||||
{
|
||||
hap_capable_system = 1;
|
||||
}
|
||||
else if ( opt_hap_enabled ) {
|
||||
else if ( opt_hap_enabled )
|
||||
{
|
||||
printk(" nested paging is not supported by this CPU.\n");
|
||||
hap_capable_system = 0; /* no nested paging, we disable flag. */
|
||||
}
|
||||
@@ -1075,24 +1091,6 @@ int start_svm(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void arch_svm_do_resume(struct vcpu *v)
|
||||
{
|
||||
/* pinning VCPU to a different core? */
|
||||
if ( v->arch.hvm_svm.launch_core == smp_processor_id()) {
|
||||
hvm_do_resume( v );
|
||||
reset_stack_and_jump( svm_asm_do_resume );
|
||||
}
|
||||
else {
|
||||
if (svm_dbg_on)
|
||||
printk("VCPU core pinned: %d to %d\n",
|
||||
v->arch.hvm_svm.launch_core, smp_processor_id() );
|
||||
v->arch.hvm_svm.launch_core = smp_processor_id();
|
||||
hvm_migrate_timers( v );
|
||||
hvm_do_resume( v );
|
||||
reset_stack_and_jump( svm_asm_do_resume );
|
||||
}
|
||||
}
|
||||
|
||||
static int svm_do_nested_pgfault(paddr_t gpa, struct cpu_user_regs *regs)
|
||||
{
|
||||
if (mmio_space(gpa)) {
|
||||
|
||||
@@ -196,11 +196,13 @@ static int construct_vmcb(struct vcpu *v)
|
||||
|
||||
arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP;
|
||||
|
||||
if ( paging_mode_hap(v->domain) ) {
|
||||
if ( paging_mode_hap(v->domain) )
|
||||
{
|
||||
vmcb->cr0 = arch_svm->cpu_shadow_cr0;
|
||||
vmcb->np_enable = 1; /* enable nested paging */
|
||||
vmcb->g_pat = 0x0007040600070406ULL; /* guest PAT */
|
||||
vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_PG;
|
||||
vmcb->h_cr3 = pagetable_get_paddr(v->domain->arch.phys_table);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -247,16 +249,6 @@ void svm_destroy_vmcb(struct vcpu *v)
|
||||
arch_svm->vmcb = NULL;
|
||||
}
|
||||
|
||||
void svm_do_launch(struct vcpu *v)
|
||||
{
|
||||
hvm_stts(v);
|
||||
|
||||
/* current core is the one we intend to perform the VMRUN on */
|
||||
v->arch.hvm_svm.launch_core = smp_processor_id();
|
||||
|
||||
v->arch.schedule_tail = arch_svm_do_resume;
|
||||
}
|
||||
|
||||
static void svm_dump_sel(char *name, svm_segment_register_t *s)
|
||||
{
|
||||
printk("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n",
|
||||
|
||||
@@ -80,15 +80,24 @@
|
||||
popl %eax; \
|
||||
addl $(NR_SKIPPED_REGS*4), %esp
|
||||
|
||||
ALIGN
|
||||
|
||||
#define VMRUN .byte 0x0F,0x01,0xD8
|
||||
#define VMLOAD .byte 0x0F,0x01,0xDA
|
||||
#define VMSAVE .byte 0x0F,0x01,0xDB
|
||||
#define STGI .byte 0x0F,0x01,0xDC
|
||||
#define CLGI .byte 0x0F,0x01,0xDD
|
||||
|
||||
ENTRY(svm_asm_do_launch)
|
||||
ENTRY(svm_asm_do_resume)
|
||||
GET_CURRENT(%ebx)
|
||||
xorl %ecx,%ecx
|
||||
notl %ecx
|
||||
cli # tests must not race interrupts
|
||||
movl VCPU_processor(%ebx),%eax
|
||||
shl $IRQSTAT_shift,%eax
|
||||
test %ecx,irq_stat(%eax,1)
|
||||
jnz svm_process_softirqs
|
||||
call svm_intr_assist
|
||||
call svm_load_cr2
|
||||
|
||||
CLGI
|
||||
sti
|
||||
GET_CURRENT(%ebx)
|
||||
@@ -134,31 +143,8 @@ svm_stgi_label:
|
||||
addl $4,%esp
|
||||
jmp svm_asm_do_resume
|
||||
|
||||
ALIGN
|
||||
|
||||
ENTRY(svm_asm_do_resume)
|
||||
svm_test_all_events:
|
||||
GET_CURRENT(%ebx)
|
||||
/*test_all_events:*/
|
||||
xorl %ecx,%ecx
|
||||
notl %ecx
|
||||
cli # tests must not race interrupts
|
||||
/*test_softirqs:*/
|
||||
movl VCPU_processor(%ebx),%eax
|
||||
shl $IRQSTAT_shift,%eax
|
||||
test %ecx,irq_stat(%eax,1)
|
||||
jnz svm_process_softirqs
|
||||
svm_restore_all_guest:
|
||||
call svm_intr_assist
|
||||
call svm_load_cr2
|
||||
/*
|
||||
* Check if we are going back to AMD-V based VM
|
||||
* By this time, all the setups in the VMCB must be complete.
|
||||
*/
|
||||
jmp svm_asm_do_launch
|
||||
|
||||
ALIGN
|
||||
svm_process_softirqs:
|
||||
sti
|
||||
call do_softirq
|
||||
jmp svm_test_all_events
|
||||
jmp svm_asm_do_resume
|
||||
@@ -98,7 +98,17 @@
|
||||
#define STGI .byte 0x0F,0x01,0xDC
|
||||
#define CLGI .byte 0x0F,0x01,0xDD
|
||||
|
||||
ENTRY(svm_asm_do_launch)
|
||||
ENTRY(svm_asm_do_resume)
|
||||
GET_CURRENT(%rbx)
|
||||
cli # tests must not race interrupts
|
||||
movl VCPU_processor(%rbx),%eax
|
||||
shl $IRQSTAT_shift, %rax
|
||||
leaq irq_stat(%rip), %rdx
|
||||
testl $~0, (%rdx, %rax, 1)
|
||||
jnz svm_process_softirqs
|
||||
call svm_intr_assist
|
||||
call svm_load_cr2
|
||||
|
||||
CLGI
|
||||
sti
|
||||
GET_CURRENT(%rbx)
|
||||
@@ -150,28 +160,8 @@ svm_stgi_label:
|
||||
call svm_vmexit_handler
|
||||
jmp svm_asm_do_resume
|
||||
|
||||
ENTRY(svm_asm_do_resume)
|
||||
svm_test_all_events:
|
||||
GET_CURRENT(%rbx)
|
||||
/*test_all_events:*/
|
||||
cli # tests must not race interrupts
|
||||
/*test_softirqs:*/
|
||||
movl VCPU_processor(%rbx),%eax
|
||||
shl $IRQSTAT_shift, %rax
|
||||
leaq irq_stat(%rip), %rdx
|
||||
testl $~0, (%rdx, %rax, 1)
|
||||
jnz svm_process_softirqs
|
||||
svm_restore_all_guest:
|
||||
call svm_intr_assist
|
||||
call svm_load_cr2
|
||||
/*
|
||||
* Check if we are going back to AMD-V based VM
|
||||
* By this time, all the setups in the VMCB must be complete.
|
||||
*/
|
||||
jmp svm_asm_do_launch
|
||||
|
||||
ALIGN
|
||||
svm_process_softirqs:
|
||||
sti
|
||||
call do_softirq
|
||||
jmp svm_test_all_events
|
||||
jmp svm_asm_do_resume
|
||||
@@ -54,8 +54,8 @@ static int vpic_get_priority(struct hvm_hw_vpic *vpic, uint8_t mask)
|
||||
if ( mask == 0 )
|
||||
return VPIC_PRIO_NONE;
|
||||
|
||||
/* prio = ffs(mask ROL vpic->priority_add); */
|
||||
asm ( "rol %%cl,%b1 ; bsf %1,%0"
|
||||
/* prio = ffs(mask ROR vpic->priority_add); */
|
||||
asm ( "ror %%cl,%b1 ; bsf %1,%0"
|
||||
: "=r" (prio) : "r" ((uint32_t)mask), "c" (vpic->priority_add) );
|
||||
return prio;
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@
|
||||
#include <asm/x86_emulate.h>
|
||||
#include <asm/e820.h>
|
||||
#include <asm/hypercall.h>
|
||||
#include <asm/shared.h>
|
||||
#include <public/memory.h>
|
||||
|
||||
#define MEM_LOG(_f, _a...) gdprintk(XENLOG_WARNING , _f "\n" , ## _a)
|
||||
@@ -246,6 +247,11 @@ int memory_is_conventional_ram(paddr_t p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long domain_get_maximum_gpfn(struct domain *d)
|
||||
{
|
||||
return is_hvm_domain(d) ? d->arch.p2m.max_mapped_pfn : arch_get_max_pfn(d);
|
||||
}
|
||||
|
||||
void share_xen_page_with_guest(
|
||||
struct page_info *page, struct domain *d, int readonly)
|
||||
{
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include <asm/current.h>
|
||||
#include <asm/flushtlb.h>
|
||||
#include <asm/shadow.h>
|
||||
#include <asm/shared.h>
|
||||
#include "private.h"
|
||||
|
||||
|
||||
@@ -2672,7 +2671,7 @@ sh_alloc_log_dirty_bitmap(struct domain *d)
|
||||
{
|
||||
ASSERT(d->arch.paging.shadow.dirty_bitmap == NULL);
|
||||
d->arch.paging.shadow.dirty_bitmap_size =
|
||||
(arch_get_max_pfn(d) + (BITS_PER_LONG - 1)) &
|
||||
(domain_get_maximum_gpfn(d) + (BITS_PER_LONG - 1)) &
|
||||
~(BITS_PER_LONG - 1);
|
||||
d->arch.paging.shadow.dirty_bitmap =
|
||||
xmalloc_array(unsigned long,
|
||||
@@ -2682,7 +2681,8 @@ sh_alloc_log_dirty_bitmap(struct domain *d)
|
||||
d->arch.paging.shadow.dirty_bitmap_size = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(d->arch.paging.shadow.dirty_bitmap, 0, d->arch.paging.shadow.dirty_bitmap_size/8);
|
||||
memset(d->arch.paging.shadow.dirty_bitmap, 0,
|
||||
d->arch.paging.shadow.dirty_bitmap_size/8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ void __dummy__(void)
|
||||
OFFSET(VCPU_domain, struct vcpu, domain);
|
||||
OFFSET(VCPU_vcpu_info, struct vcpu, vcpu_info);
|
||||
OFFSET(VCPU_trap_bounce, struct vcpu, arch.trap_bounce);
|
||||
OFFSET(VCPU_int80_bounce, struct vcpu, arch.int80_bounce);
|
||||
OFFSET(VCPU_thread_flags, struct vcpu, arch.flags);
|
||||
OFFSET(VCPU_event_addr, struct vcpu,
|
||||
arch.guest_context.event_callback_eip);
|
||||
|
||||
@@ -187,6 +187,10 @@ ENTRY(compat_post_handle_exception)
|
||||
call compat_create_bounce_frame
|
||||
jmp compat_test_all_events
|
||||
|
||||
ENTRY(compat_int80_direct_trap)
|
||||
call compat_create_bounce_frame
|
||||
jmp compat_restore_all_guest
|
||||
|
||||
/* CREATE A BASIC EXCEPTION FRAME ON GUEST OS (RING-1) STACK: */
|
||||
/* {[ERRCODE,] EIP, CS, EFLAGS, [ESP, SS]} */
|
||||
/* %rdx: trap_bounce, %rbx: struct vcpu */
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
#include <xen/event.h>
|
||||
#include <asm/regs.h>
|
||||
#include <compat/callback.h>
|
||||
#include <compat/arch-x86_32.h>
|
||||
|
||||
@@ -291,6 +292,9 @@ int compat_set_trap_table(XEN_GUEST_HANDLE(trap_info_compat_t) traps)
|
||||
|
||||
XLAT_trap_info(dst + cur.vector, &cur);
|
||||
|
||||
if ( cur.vector == 0x80 )
|
||||
init_int80_direct_trap(current);
|
||||
|
||||
guest_handle_add_offset(traps, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -222,6 +222,35 @@ bad_hypercall:
|
||||
movq $-ENOSYS,UREGS_rax(%rsp)
|
||||
jmp test_all_events
|
||||
|
||||
ENTRY(int80_direct_trap)
|
||||
pushq $0
|
||||
SAVE_ALL
|
||||
|
||||
GET_CURRENT(%rbx)
|
||||
|
||||
/* Check that the callback is non-null. */
|
||||
leaq VCPU_int80_bounce(%rbx),%rdx
|
||||
cmp $0, TRAPBOUNCE_flags(%rdx)
|
||||
jz int80_slow_path
|
||||
|
||||
movq VCPU_domain(%rbx),%rax
|
||||
btl $_DOMF_compat,DOMAIN_domain_flags(%rax)
|
||||
jc compat_int80_direct_trap
|
||||
|
||||
call create_bounce_frame
|
||||
jmp restore_all_guest
|
||||
|
||||
int80_slow_path:
|
||||
/*
|
||||
* Setup entry vector and error code as if this was a GPF caused by an
|
||||
* IDT entry with DPL==0.
|
||||
*/
|
||||
movl $((0x80 << 3) | 0x2),UREGS_error_code(%rsp)
|
||||
movl $TRAP_gp_fault,UREGS_entry_vector(%rsp)
|
||||
/* A GPF wouldn't have incremented the instruction pointer. */
|
||||
sub $2,UREGS_rip(%rsp)
|
||||
jmp handle_exception_saved
|
||||
|
||||
/* CREATE A BASIC EXCEPTION FRAME ON GUEST OS STACK: */
|
||||
/* { RCX, R11, [DS-GS,] [CR2,] [ERRCODE,] RIP, CS, RFLAGS, RSP, SS } */
|
||||
/* %rdx: trap_bounce, %rbx: struct vcpu */
|
||||
@@ -359,6 +388,7 @@ ENTRY(ret_from_intr)
|
||||
/* No special register assumptions. */
|
||||
ENTRY(handle_exception)
|
||||
SAVE_ALL
|
||||
handle_exception_saved:
|
||||
testb $X86_EFLAGS_IF>>8,UREGS_eflags+1(%rsp)
|
||||
jz exception_with_ints_disabled
|
||||
sti
|
||||
|
||||
@@ -247,6 +247,7 @@ unsigned long do_iret(void)
|
||||
|
||||
asmlinkage void syscall_enter(void);
|
||||
asmlinkage void compat_hypercall(void);
|
||||
asmlinkage void int80_direct_trap(void);
|
||||
void __init percpu_traps_init(void)
|
||||
{
|
||||
char *stack_bottom, *stack;
|
||||
@@ -262,6 +263,7 @@ void __init percpu_traps_init(void)
|
||||
#ifdef CONFIG_COMPAT
|
||||
/* The hypercall entry vector is only accessible from ring 1. */
|
||||
_set_gate(idt_table+HYPERCALL_VECTOR, 15, 1, &compat_hypercall);
|
||||
_set_gate(idt_table+0x80, 15, 3, &int80_direct_trap);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -346,6 +348,22 @@ void __init percpu_traps_init(void)
|
||||
wrmsr(MSR_SYSCALL_MASK, EF_VM|EF_RF|EF_NT|EF_DF|EF_IE|EF_TF, 0U);
|
||||
}
|
||||
|
||||
void init_int80_direct_trap(struct vcpu *v)
|
||||
{
|
||||
struct trap_info *ti = &v->arch.guest_context.trap_ctxt[0x80];
|
||||
struct trap_bounce *tb = &v->arch.int80_bounce;
|
||||
|
||||
if ( !guest_gate_selector_okay(v->domain, ti->cs) )
|
||||
return;
|
||||
|
||||
tb->flags = TBF_EXCEPTION;
|
||||
tb->cs = ti->cs;
|
||||
tb->eip = ti->address;
|
||||
|
||||
if ( null_trap_bounce(v, tb) )
|
||||
tb->flags = 0;
|
||||
}
|
||||
|
||||
static long register_guest_callback(struct callback_register *reg)
|
||||
{
|
||||
long ret = 0;
|
||||
|
||||
@@ -170,6 +170,7 @@ int compat_memory_op(unsigned int cmd, XEN_GUEST_HANDLE(void) compat)
|
||||
|
||||
case XENMEM_current_reservation:
|
||||
case XENMEM_maximum_reservation:
|
||||
case XENMEM_maximum_gpfn:
|
||||
{
|
||||
#define xen_domid_t domid_t
|
||||
#define compat_domid_t domid_compat_t
|
||||
@@ -325,6 +326,7 @@ int compat_memory_op(unsigned int cmd, XEN_GUEST_HANDLE(void) compat)
|
||||
case XENMEM_maximum_ram_page:
|
||||
case XENMEM_current_reservation:
|
||||
case XENMEM_maximum_reservation:
|
||||
case XENMEM_maximum_gpfn:
|
||||
break;
|
||||
|
||||
case XENMEM_translate_gpfn_list:
|
||||
|
||||
+14
-1
@@ -584,6 +584,7 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg)
|
||||
|
||||
case XENMEM_current_reservation:
|
||||
case XENMEM_maximum_reservation:
|
||||
case XENMEM_maximum_gpfn:
|
||||
if ( copy_from_guest(&domid, arg, 1) )
|
||||
return -EFAULT;
|
||||
|
||||
@@ -594,7 +595,19 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg)
|
||||
else if ( (d = rcu_lock_domain_by_id(domid)) == NULL )
|
||||
return -ESRCH;
|
||||
|
||||
rc = (op == XENMEM_current_reservation) ? d->tot_pages : d->max_pages;
|
||||
switch ( op )
|
||||
{
|
||||
case XENMEM_current_reservation:
|
||||
rc = d->tot_pages;
|
||||
break;
|
||||
case XENMEM_maximum_reservation:
|
||||
rc = d->max_pages;
|
||||
break;
|
||||
default:
|
||||
ASSERT(op == XENMEM_maximum_gpfn);
|
||||
rc = domain_get_maximum_gpfn(d);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( unlikely(domid != DOMID_SELF) )
|
||||
rcu_unlock_domain(d);
|
||||
|
||||
+4
-13
@@ -136,8 +136,8 @@ static xen_sysctl_perfc_desc_t perfc_d[NR_PERFCTRS];
|
||||
static xen_sysctl_perfc_val_t *perfc_vals;
|
||||
static int perfc_nbr_vals;
|
||||
static int perfc_init = 0;
|
||||
static int perfc_copy_info(XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t) desc,
|
||||
XEN_GUEST_HANDLE(xen_sysctl_perfc_val_t) val)
|
||||
static int perfc_copy_info(XEN_GUEST_HANDLE_64(xen_sysctl_perfc_desc_t) desc,
|
||||
XEN_GUEST_HANDLE_64(xen_sysctl_perfc_val_t) val)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned int v = 0;
|
||||
@@ -217,29 +217,20 @@ static int perfc_copy_info(XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t) desc,
|
||||
int perfc_control(xen_sysctl_perfc_op_t *pc)
|
||||
{
|
||||
static DEFINE_SPINLOCK(lock);
|
||||
XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t) desc;
|
||||
XEN_GUEST_HANDLE(xen_sysctl_perfc_val_t) val;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* 64 bit guest handles cannot be passed as parameters to
|
||||
* functions so cast to a regular guest handle.
|
||||
*/
|
||||
desc = guest_handle_cast(pc->desc, xen_sysctl_perfc_desc_t);
|
||||
val = guest_handle_cast(pc->val, xen_sysctl_perfc_val_t);
|
||||
|
||||
spin_lock(&lock);
|
||||
|
||||
switch ( pc->cmd )
|
||||
{
|
||||
case XEN_SYSCTL_PERFCOP_reset:
|
||||
perfc_copy_info(desc, val);
|
||||
perfc_copy_info(pc->desc, pc->val);
|
||||
perfc_reset(0);
|
||||
rc = 0;
|
||||
break;
|
||||
|
||||
case XEN_SYSCTL_PERFCOP_query:
|
||||
perfc_copy_info(desc, val);
|
||||
perfc_copy_info(pc->desc, pc->val);
|
||||
rc = 0;
|
||||
break;
|
||||
|
||||
|
||||
@@ -511,4 +511,6 @@ int steal_page(
|
||||
|
||||
#define domain_clamp_alloc_bitsize(d, b) (b)
|
||||
|
||||
#define domain_get_maximum_gpfn(d) (-ENOSYS)
|
||||
|
||||
#endif /* __ASM_IA64_MM_H__ */
|
||||
@@ -278,4 +278,6 @@ extern int steal_page(struct domain *d, struct page_info *page,
|
||||
|
||||
#define domain_clamp_alloc_bitsize(d, b) (b)
|
||||
|
||||
#define domain_get_maximum_gpfn(d) (-ENOSYS)
|
||||
|
||||
#endif
|
||||
@@ -248,6 +248,9 @@ struct arch_vcpu
|
||||
#ifdef CONFIG_X86_32
|
||||
struct desc_struct int80_desc;
|
||||
#endif
|
||||
#ifdef CONFIG_X86_64
|
||||
struct trap_bounce int80_bounce;
|
||||
#endif
|
||||
|
||||
/* Virtual Machine Extensions */
|
||||
struct hvm_vcpu hvm_vcpu;
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
#include <asm/i387.h>
|
||||
|
||||
extern void svm_dump_vmcb(const char *from, struct vmcb_struct *vmcb);
|
||||
extern void svm_do_launch(struct vcpu *v);
|
||||
extern void arch_svm_do_resume(struct vcpu *v);
|
||||
|
||||
extern u64 root_vmcb_pa[NR_CPUS];
|
||||
|
||||
|
||||
@@ -447,7 +447,7 @@ struct arch_svm_struct {
|
||||
u32 *msrpm;
|
||||
u64 vmexit_tsc; /* tsc read at #VMEXIT. for TSC_OFFSET */
|
||||
int saved_irq_vector;
|
||||
u32 launch_core;
|
||||
int launch_core;
|
||||
|
||||
unsigned long flags; /* VMCB flags */
|
||||
unsigned long cpu_shadow_cr0; /* Guest value for CR0 */
|
||||
|
||||
@@ -404,5 +404,6 @@ unsigned int domain_clamp_alloc_bitsize(struct domain *d, unsigned int bits);
|
||||
# define domain_clamp_alloc_bitsize(d, b) (b)
|
||||
#endif
|
||||
|
||||
unsigned long domain_get_maximum_gpfn(struct domain *d);
|
||||
|
||||
#endif /* __ASM_X86_MM_H__ */
|
||||
@@ -455,16 +455,16 @@ extern idt_entry_t *idt_tables[];
|
||||
|
||||
extern struct tss_struct init_tss[NR_CPUS];
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
|
||||
extern void init_int80_direct_trap(struct vcpu *v);
|
||||
|
||||
#if defined(CONFIG_X86_32)
|
||||
|
||||
#define set_int80_direct_trap(_ed) \
|
||||
(memcpy(idt_tables[(_ed)->processor] + 0x80, \
|
||||
&((_ed)->arch.int80_desc), 8))
|
||||
|
||||
#else
|
||||
|
||||
#define init_int80_direct_trap(_ed) ((void)0)
|
||||
#define set_int80_direct_trap(_ed) ((void)0)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
(hnd).p = val; \
|
||||
} while ( 0 )
|
||||
#define uint64_aligned_t uint64_t __attribute__((aligned(8)))
|
||||
#define XEN_GUEST_HANDLE_64(name) __guest_handle_64_ ## name __attribute__((aligned(8)))
|
||||
#define XEN_GUEST_HANDLE_64(name) __guest_handle_64_ ## name
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
Loaded 100 of 103 files, more files were not shown because too many files have changed in this diff.
Show more