[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Merged.
# HG changeset patch # User emellor@xxxxxxxxxxxxxxxxxxxxxx # Node ID d3b10a2a82d47bb3e52faf2fa4ba27217f486c54 # Parent 11cd619db03540476cef8ec523d46d9a1d13973c # Parent 931acb64fbaf762fd47f9035b411ae6f1b5cb50b Merged. diff -r 11cd619db035 -r d3b10a2a82d4 Makefile --- a/Makefile Tue Dec 20 17:16:15 2005 +++ b/Makefile Tue Dec 20 17:16:24 2005 @@ -10,7 +10,7 @@ # Export target architecture overrides to Xen and Linux sub-trees. ifneq ($(XEN_TARGET_ARCH),) SUBARCH := $(subst x86_32,i386,$(XEN_TARGET_ARCH)) -export XEN_TARGET_ARCH SUBARCH +export XEN_TARGET_ARCH SUBARCH XEN_SYSTYPE endif # Default target must appear before any include lines diff -r 11cd619db035 -r d3b10a2a82d4 buildconfigs/mk.linux-2.6-xen --- a/buildconfigs/mk.linux-2.6-xen Tue Dec 20 17:16:15 2005 +++ b/buildconfigs/mk.linux-2.6-xen Tue Dec 20 17:16:24 2005 @@ -30,7 +30,7 @@ CONFIG_VERSION=$$(sed -ne 's/^EXTRAVERSION = //p' $(LINUX_DIR)/Makefile); \ [ -r $(DESTDIR)/boot/config-$(LINUX_VER)$$CONFIG_VERSION-$(EXTRAVERSION) ] && \ cp $(DESTDIR)/boot/config-$(LINUX_VER)$$CONFIG_VERSION-$(EXTRAVERSION) $(LINUX_DIR)/.config \ - || cp $(LINUX_DIR)/arch/xen/configs/$(EXTRAVERSION)_defconfig_$(XEN_TARGET_ARCH) \ + || cp $(LINUX_DIR)/arch/xen/configs/$(EXTRAVERSION)_defconfig_$(XEN_TARGET_ARCH)$(XEN_SYSTYPE) \ $(LINUX_DIR)/.config # See if we need to munge config to enable PAE $(MAKE) CONFIG_FILE=$(LINUX_DIR)/.config -f buildconfigs/Rules.mk config-update-pae diff -r 11cd619db035 -r d3b10a2a82d4 linux-2.6-xen-sparse/arch/xen/i386/kernel/ldt.c --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/ldt.c Tue Dec 20 17:16:15 2005 +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/ldt.c Tue Dec 20 17:16:24 2005 @@ -186,8 +186,7 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) { struct mm_struct * mm = current->mm; - __u32 entry_1, entry_2, *lp; - maddr_t mach_lp; + __u32 entry_1, entry_2; int error; struct user_desc ldt_info; @@ -215,9 +214,6 @@ goto out_unlock; } - lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt); - mach_lp = arbitrary_virt_to_machine(lp); - /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { if (oldmode || LDT_empty(&ldt_info)) { @@ -234,8 +230,8 @@ /* Install the new entry ... */ install: - error = HYPERVISOR_update_descriptor( - mach_lp, (u64)entry_1 | ((u64)entry_2<<32)); + error = write_ldt_entry(mm->context.ldt, ldt_info.entry_number, + entry_1, entry_2); out_unlock: up(&mm->context.sem); diff -r 11cd619db035 -r d3b10a2a82d4 linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c Tue Dec 20 17:16:15 2005 +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c Tue Dec 20 17:16:24 2005 @@ -24,6 +24,7 @@ #include <asm/io.h> #include <asm/pci.h> #include <asm/dma.h> +#include <asm/uaccess.h> #include <asm-xen/xen-public/memory.h> #define OFFSET(val,align) ((unsigned long)((val) & ( (align) - 1))) @@ -201,6 +202,12 @@ printk(KERN_INFO "Software IO TLB disabled\n"); } +/* + * We use __copy_to_user to transfer to the host buffer because the buffer + * may be mapped read-only (e.g, in blkback driver) but lower-level + * drivers map the buffer for DMA_BIDIRECTIONAL access. This causes an + * unnecessary copy from the aperture to the host buffer, and a page fault. + */ static void __sync_single(struct phys_addr buffer, char *dma_addr, size_t size, int dir) { @@ -214,9 +221,11 @@ kmp = kmap_atomic(buffer.page, KM_SWIOTLB); dev = dma_addr + size - len; host = kmp + buffer.offset; - memcpy((dir == DMA_FROM_DEVICE) ? host : dev, - (dir == DMA_FROM_DEVICE) ? dev : host, - bytes); + if (dir == DMA_FROM_DEVICE) { + if (__copy_to_user(host, dev, bytes)) + /* inaccessible */; + } else + memcpy(dev, host, bytes); kunmap_atomic(kmp, KM_SWIOTLB); len -= bytes; buffer.page++; @@ -225,9 +234,10 @@ } else { char *host = (char *)phys_to_virt( page_to_pseudophys(buffer.page)) + buffer.offset; - if (dir == DMA_FROM_DEVICE) - memcpy(host, dma_addr, size); - else if (dir == DMA_TO_DEVICE) + if (dir == DMA_FROM_DEVICE) { + if (__copy_to_user(host, dma_addr, size)) + /* inaccessible */; + } else if (dir == DMA_TO_DEVICE) memcpy(dma_addr, host, size); } } diff -r 11cd619db035 -r d3b10a2a82d4 linux-2.6-xen-sparse/arch/xen/i386/mm/hypervisor.c --- a/linux-2.6-xen-sparse/arch/xen/i386/mm/hypervisor.c Tue Dec 20 17:16:15 2005 +++ b/linux-2.6-xen-sparse/arch/xen/i386/mm/hypervisor.c Tue Dec 20 17:16:24 2005 @@ -438,6 +438,16 @@ balloon_unlock(flags); } +#ifdef __i386__ +int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b) +{ + __u32 *lp = (__u32 *)((char *)ldt + entry * 8); + maddr_t mach_lp = arbitrary_virt_to_machine(lp); + return HYPERVISOR_update_descriptor( + mach_lp, (u64)entry_a | ((u64)entry_b<<32)); +} +#endif + /* * Local variables: * c-file-style: "linux" diff -r 11cd619db035 -r d3b10a2a82d4 linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c --- a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c Tue Dec 20 17:16:15 2005 +++ b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c Tue Dec 20 17:16:24 2005 @@ -163,11 +163,10 @@ while (l1 != 0) { l1i = __ffs(l1); l1 &= ~(1UL << l1i); - + while ((l2 = active_evtchns(cpu, s, l1i)) != 0) { l2i = __ffs(l2); - l2 &= ~(1UL << l2i); - + port = (l1i * BITS_PER_LONG) + l2i; if ((irq = evtchn_to_irq[port]) != -1) do_IRQ(irq, regs); diff -r 11cd619db035 -r d3b10a2a82d4 linux-2.6-xen-sparse/include/asm-xen/asm-i386/desc.h --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/desc.h Tue Dec 20 17:16:15 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/desc.h Tue Dec 20 17:16:24 2005 @@ -87,6 +87,8 @@ (info)->seg_not_present == 1 && \ (info)->useable == 0 ) +extern int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b); + #if TLS_SIZE != 24 # error update this code. #endif diff -r 11cd619db035 -r d3b10a2a82d4 tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c --- a/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c Tue Dec 20 17:16:15 2005 +++ b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c Tue Dec 20 17:16:24 2005 @@ -36,11 +36,26 @@ #include <unistd.h> #include <errno.h> #include <xenctrl.h> +#include <thread_db.h> +#include <xc_ptrace.h> + #define TRACE_ENTER /* printf("enter %s\n", __FUNCTION__) */ long (*myptrace)(int xc_handle, enum __ptrace_request, uint32_t, long, long); int (*myxcwait)(int xc_handle, int domain, int *status, int options) ; static int xc_handle; + +static inline int +curvcpuid() +{ + struct process_info *process; + if (current_inferior == NULL) + return 0; + process = get_thread_process(current_inferior); + return (process->thread_known ? process->tid : 0); + +} + #define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */ #define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut down. */ @@ -48,11 +63,14 @@ #define DOMFLAGS_BLOCKED (1<<4) /* Currently blocked pending an event. */ #define DOMFLAGS_RUNNING (1<<5) /* Domain is currently running. */ + + struct inferior_list all_processes; -static int current_domain; +static int current_domid; static int expect_signal = 0; static int signal_to_send = 0; static void linux_resume (struct thread_resume *resume_info); +static void linux_set_inferior (void); int debug_threads; int using_threads; @@ -96,7 +114,6 @@ point at the following instruction. If we continue and hit a breakpoint instruction, our PC will point at the breakpoint instruction. */ -#if 0 static CORE_ADDR get_stop_pc (void) { @@ -107,9 +124,9 @@ else return stop_pc - the_low_target.decr_pc_after_break; } -#endif + static void * -add_process (int pid) +add_process (int pid, long tid) { struct process_info *process; @@ -118,9 +135,8 @@ process->head.id = pid; - /* Default to tid == lwpid == pid. */ - process->tid = pid; - process->lwpid = pid; + process->tid = tid; + process->lwpid = tid; add_inferior_to_list (&all_processes, &process->head); @@ -143,23 +159,25 @@ } int -linux_attach (int domain) +linux_attach (int domid) { struct process_info *new_process; - current_domain = domain; - if (myptrace (xc_handle, PTRACE_ATTACH, domain, 0, 0) != 0) { - fprintf (stderr, "Cannot attach to domain %d: %s (%d)\n", domain, + current_domid = domid; + /* this is handled for all active vcpus in PTRACE_ATTACH via the thread_create_callback */ + new_process = (struct process_info *) add_process (domid, curvcpuid()); + /* Don't ignore the initial SIGSTOP if we just attached to this process. */ + /* vcpuid == 0 */ + add_thread (0, new_process); + new_process->stop_expected = 0; + + if (myptrace (xc_handle, PTRACE_ATTACH, domid, 0, 0) != 0) { + fprintf (stderr, "Cannot attach to domain %d: %s (%d)\n", domid, strerror (errno), errno); fflush (stderr); - _exit (0177); - } - - new_process = (struct process_info *) add_process (domain); - add_thread (domain, new_process); - - /* Don't ignore the initial SIGSTOP if we just attached to this process. */ - new_process->stop_expected = 0; - + if (!using_threads) + _exit (0177); + } + return 0; } @@ -173,20 +191,18 @@ myptrace (xc_handle, PTRACE_KILL, pid_of (process), 0, 0); } + static void linux_kill (void) { for_each_inferior (&all_threads, linux_kill_one_process); } - static void linux_detach_one_process (struct inferior_list_entry *entry) { - struct thread_info *thread = (struct thread_info *) entry; - struct process_info *process = get_thread_process (thread); - - myptrace (xc_handle, PTRACE_DETACH, pid_of (process), 0, 0); + + myptrace (xc_handle, PTRACE_DETACH, current_domid, 0, 0); } @@ -212,14 +228,10 @@ linux_wait (char *status) { int w; - if (myxcwait(xc_handle, current_domain, &w, 0)) + if (myxcwait(xc_handle, current_domid, &w, 0)) return -1; - if (w & (DOMFLAGS_SHUTDOWN|DOMFLAGS_DYING)) { - *status = 'W'; - return 0; - } - + linux_set_inferior(); *status = 'T'; if (expect_signal) @@ -236,8 +248,10 @@ TRACE_ENTER; expect_signal = resume_info->sig; for_each_inferior(&all_threads, regcache_invalidate_one); - - myptrace (xc_handle, step ? PTRACE_SINGLESTEP : PTRACE_CONT, current_domain, 0, 0); + if (debug_threads) + fprintf(stderr, "step: %d\n", step); + myptrace (xc_handle, step ? PTRACE_SINGLESTEP : PTRACE_CONT, + resume_info->thread, 0, 0); } @@ -261,7 +275,9 @@ } buf = malloc (regset->size); - res = myptrace (xc_handle, regset->get_request, inferior_pid, 0, (PTRACE_XFER_TYPE)buf); + res = myptrace (xc_handle, regset->get_request, + curvcpuid(), + 0, (PTRACE_XFER_TYPE)buf); if (res < 0) { if (errno == EIO) @@ -313,7 +329,7 @@ buf = malloc (regset->size); regset->fill_function (buf); - res = myptrace (xc_handle, regset->set_request, inferior_pid, 0, (PTRACE_XFER_TYPE)buf); + res = myptrace (xc_handle, regset->set_request, curvcpuid(), 0, (PTRACE_XFER_TYPE)buf); if (res < 0) { if (errno == EIO) @@ -391,7 +407,7 @@ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - buffer[i] = myptrace (xc_handle, PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0); + buffer[i] = myptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(), (PTRACE_ARG3_TYPE) addr, 0); if (errno) return errno; } @@ -424,13 +440,13 @@ /* Fill start and end extra bytes of buffer with existing memory data. */ - buffer[0] = myptrace (xc_handle, PTRACE_PEEKTEXT, inferior_pid, + buffer[0] = myptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(), (PTRACE_ARG3_TYPE) addr, 0); if (count > 1) { buffer[count - 1] - = myptrace (xc_handle, PTRACE_PEEKTEXT, inferior_pid, + = myptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(), (PTRACE_ARG3_TYPE) (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE)), 0); @@ -444,7 +460,8 @@ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - myptrace (xc_handle, PTRACE_POKETEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]); + myptrace (xc_handle, PTRACE_POKETEXT, curvcpuid(), + (PTRACE_ARG3_TYPE) addr, buffer[i]); if (errno) return errno; } @@ -455,9 +472,11 @@ static void linux_look_up_symbols (void) { -#if 0 + if (using_threads) + return; + using_threads = thread_db_init (); -#endif + } static void @@ -535,6 +554,7 @@ void initialize_low (void) { + using_threads = 0; xc_handle = xc_interface_open(); set_target_ops (&linux_xen_target_ops); set_breakpoint_data (the_low_target.breakpoint, @@ -548,5 +568,122 @@ myptrace = xc_ptrace; myxcwait = xc_waitdomain; } - -} + using_threads = thread_db_init (); + +} + + +static void +thread_create_callback(long vcpuid) +{ + struct thread_info *inferior; + struct process_info *process; + + /* If we are attaching to our first thread, things are a little + * different. + */ + if (all_threads.head == all_threads.tail) + { + inferior = (struct thread_info *) all_threads.head; + process = get_thread_process (inferior); + if (process->thread_known == 0) + { + /* Switch to indexing the threads list by TID. */ + change_inferior_id (&all_threads, vcpuid); + goto found; + } + } + if (debug_threads) + fprintf (stderr, "looking up thread %ld\n", + vcpuid); + inferior = (struct thread_info *) find_inferior_id (&all_threads, + vcpuid); + /* if vcpu alread registered - do nothing */ + if (inferior != NULL) + return; + + if (debug_threads) + fprintf (stderr, "Attaching to thread %ld\n", + vcpuid); + + process = add_process(current_domid, vcpuid); + + add_thread(vcpuid, process); + inferior = (struct thread_info *) find_inferior_id (&all_threads, + vcpuid); + if (inferior == NULL) + { + warning ("Could not attach to thread %ld\n", + vcpuid); + return; + } + + +found: + if (debug_threads) + fprintf (stderr, "notifying of new thread %ld\n", + vcpuid); + new_thread_notify (vcpuid); + + process->tid = vcpuid; + process->lwpid = vcpuid; + + process->thread_known = 1; +} + +static void +thread_death_callback(long vcpuid) +{ + if (debug_threads) + fprintf (stderr, "Buuurp...! CPU down event.\n"); +} + +int +thread_db_init(void) +{ + debug_threads = 0; + xc_register_event_handler(thread_create_callback, TD_CREATE); + xc_register_event_handler(thread_death_callback, TD_DEATH); + return 1; +} + +/* XXX GAG ME */ +static int breakpoint_found; +static void +set_breakpoint_inferior (struct inferior_list_entry *entry) +{ + struct thread_info *thread = (struct thread_info *) entry; + struct thread_info *saved_inferior = current_inferior; + CORE_ADDR eip; + unsigned char buf[2] = {0, 0}; + current_inferior = thread; + if (!breakpoint_found) { + eip = get_stop_pc(); + linux_read_memory(eip, buf, 1); + if (buf[0] == 0xcc) { + breakpoint_found = 1; + return; + } + } else if (breakpoint_found == 2) { + if (get_thread_process (current_inferior)->stepping) { + printf("stepping\n"); + breakpoint_found = 1; + return; + } + } + current_inferior = saved_inferior; + + +} + +static void +linux_set_inferior (void) +{ + breakpoint_found = 0; + for_each_inferior (&all_threads, set_breakpoint_inferior); + if (!breakpoint_found) { + breakpoint_found = 2; + for_each_inferior (&all_threads, set_breakpoint_inferior); + } +} + diff -r 11cd619db035 -r d3b10a2a82d4 tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c --- a/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c Tue Dec 20 17:16:15 2005 +++ b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c Tue Dec 20 17:16:24 2005 @@ -20,7 +20,7 @@ Boston, MA 02111-1307, USA. */ #include "server.h" - +#include "linux-low.h" #include <unistd.h> #include <signal.h> #include <sys/wait.h> @@ -102,7 +102,15 @@ strcpy (own_buf, "OK"); return; } - + if (strcmp ("qC", own_buf) == 0) + { + struct process_info *process; + if (current_inferior == NULL) + return; + process = get_thread_process(current_inferior); + sprintf(own_buf, "QC%x", process->thread_known ? process->tid : 0); + + } if (strcmp ("qfThreadInfo", own_buf) == 0) { thread_ptr = all_threads.head; diff -r 11cd619db035 -r d3b10a2a82d4 tools/examples/xend-config.sxp --- a/tools/examples/xend-config.sxp Tue Dec 20 17:16:15 2005 +++ b/tools/examples/xend-config.sxp Tue Dec 20 17:16:24 2005 @@ -4,9 +4,9 @@ # Xend configuration file. # -# This example configuration is appropriate for an installation that trusts -# only localhost connections, and is otherwise fully functional, with a -# bridged network configuration. +# This example configuration is appropriate for an installation that +# utilizes a bridged network configuration. Access to xend via http +# is disabled. # Commented out entries show the default for that entry, unless otherwise # specified. @@ -15,7 +15,6 @@ #(loglevel DEBUG) #(xend-http-server no) -(xend-http-server yes) #(xend-unix-server yes) #(xend-relocation-server no) (xend-relocation-server yes) @@ -34,7 +33,7 @@ # Specifying 'localhost' prevents remote connections. # Specifying the empty string '' (the default) allows all connections. #(xend-address '') -(xend-address localhost) +#(xend-address localhost) # Address xend should listen on for relocation-socket connections, if # xend-relocation-server is set. diff -r 11cd619db035 -r d3b10a2a82d4 tools/examples/xmexample.vmx --- a/tools/examples/xmexample.vmx Tue Dec 20 17:16:15 2005 +++ b/tools/examples/xmexample.vmx Tue Dec 20 17:16:24 2005 @@ -135,7 +135,7 @@ #----------------------------------------------------------------------------- # enable audio support -#enable-audio=1 +#audio=1 #----------------------------------------------------------------------------- diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/cpu-all.h --- a/tools/ioemu/cpu-all.h Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/cpu-all.h Tue Dec 20 17:16:24 2005 @@ -668,7 +668,7 @@ #endif /* memory API */ -extern int phys_ram_size; +extern uint64_t phys_ram_size; extern int phys_ram_fd; extern uint8_t *phys_ram_base; extern uint8_t *phys_ram_dirty; diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/exec.c --- a/tools/ioemu/exec.c Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/exec.c Tue Dec 20 17:16:24 2005 @@ -61,7 +61,7 @@ uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; uint8_t *code_gen_ptr; -int phys_ram_size; +uint64_t phys_ram_size; int phys_ram_fd; uint8_t *phys_ram_base; uint8_t *phys_ram_dirty; diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/hw/pc.c --- a/tools/ioemu/hw/pc.c Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/hw/pc.c Tue Dec 20 17:16:24 2005 @@ -119,7 +119,7 @@ } /* hd_table must contain 4 block drivers */ -static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table) +static void cmos_init(uint64_t ram_size, int boot_device, BlockDriverState **hd_table) { RTCState *s = rtc_state; int val; @@ -375,7 +375,7 @@ #define NOBIOS 1 /* PC hardware initialisation */ -void pc_init(int ram_size, int vga_ram_size, int boot_device, +void pc_init(uint64_t ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename) @@ -563,6 +563,15 @@ kbd_init(); DMA_init(0); + + if (audio_enabled) { + AUD_init(); +#ifdef USE_SB16 + if (sb16_enabled) + SB16_init(); +#endif + } + floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/hw/pcnet.h --- a/tools/ioemu/hw/pcnet.h Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/hw/pcnet.h Tue Dec 20 17:16:24 2005 @@ -92,7 +92,7 @@ #define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16)) #define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16)) #define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16)) -#define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16)) +#define CSR_CRDA(S) ((S)->csr[28] | (((uint32_t)((S)->csr[29])) << 16)) #define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16)) #define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16)) #define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16)) @@ -102,7 +102,7 @@ #define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16)) #define PHYSADDR(S,A) \ - (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16)) + (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(S)->csr[2])<<16)) struct pcnet_initblk16 { uint16_t mode; diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/target-i386-dm/Makefile --- a/tools/ioemu/target-i386-dm/Makefile Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/target-i386-dm/Makefile Tue Dec 20 17:16:24 2005 @@ -272,6 +272,7 @@ VL_OBJS+= ide.o ne2000.o pckbd.o vga.o dma.o VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259_stub.o i8254.o pc.o port-e9.o VL_OBJS+= cirrus_vga.o pcnet.o +VL_OBJS+= $(SOUND_HW) $(AUDIODRV) mixeng.o ifeq ($(TARGET_ARCH), ppc) VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/vl.c --- a/tools/ioemu/vl.c Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/vl.c Tue Dec 20 17:16:24 2005 @@ -119,7 +119,7 @@ const char* keyboard_layout = 0; int64_t ticks_per_sec; int boot_device = 'c'; -int ram_size; +uint64_t ram_size; int domid = -1; static char network_script[1024]; int pit_min_timer_count = 0; @@ -2906,7 +2906,7 @@ help(); break; case QEMU_OPTION_m: - ram_size = atoi(optarg) * 1024 * 1024; + ram_size = atol(optarg) * 1024 * 1024; if (ram_size <= 0) help(); break; diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/vl.h --- a/tools/ioemu/vl.h Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/vl.h Tue Dec 20 17:16:24 2005 @@ -37,6 +37,7 @@ #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> +#include "audio/audio.h" #ifndef O_LARGEFILE #define O_LARGEFILE 0 @@ -116,7 +117,7 @@ extern int sb16_enabled; extern int adlib_enabled; extern int gus_enabled; -extern int ram_size; +extern uint64_t ram_size; extern int bios_size; extern int rtc_utc; extern int cirrus_vga_enabled; @@ -649,7 +650,7 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); /* pc.c */ -void pc_init(int ram_size, int vga_ram_size, int boot_device, +void pc_init(uint64_t ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename); diff -r 11cd619db035 -r d3b10a2a82d4 tools/libxc/xc_domain.c --- a/tools/libxc/xc_domain.c Tue Dec 20 17:16:15 2005 +++ b/tools/libxc/xc_domain.c Tue Dec 20 17:16:24 2005 @@ -380,6 +380,30 @@ return do_dom0_op(xc_handle, &op); } +int xc_domain_setinfo(int xc_handle, + uint32_t domid, + uint32_t vcpu, + vcpu_guest_context_t *ctxt) +{ + dom0_op_t op; + int rc; + + op.cmd = DOM0_SETDOMAININFO; + op.u.setdomaininfo.domain = domid; + op.u.setdomaininfo.vcpu = vcpu; + op.u.setdomaininfo.ctxt = ctxt; + + if ( (rc = mlock(ctxt, sizeof(*ctxt))) != 0 ) + return rc; + + rc = do_dom0_op(xc_handle, &op); + + safe_munlock(ctxt, sizeof(*ctxt)); + + return rc; + +} + /* * Local variables: * mode: C diff -r 11cd619db035 -r d3b10a2a82d4 tools/libxc/xc_ptrace.c --- a/tools/libxc/xc_ptrace.c Tue Dec 20 17:16:15 2005 +++ b/tools/libxc/xc_ptrace.c Tue Dec 20 17:16:24 2005 @@ -1,130 +1,134 @@ +#define XC_PTRACE_PRIVATE + + #include <sys/ptrace.h> #include <sys/wait.h> +#include <time.h> + #include "xc_private.h" #include "xg_private.h" -#include <time.h> - -#define X86_CR0_PE 0x00000001 /* Enable Protected Mode (RW) */ -#define X86_CR0_PG 0x80000000 /* Paging (RW) */ -#define BSD_PAGE_MASK (PAGE_SIZE-1) -#define PDRSHIFT 22 -#define PSL_T 0x00000100 /* trace enable bit */ -#define VCPU 0 /* XXX */ - -char * ptrace_names[] = { - "PTRACE_TRACEME", - "PTRACE_PEEKTEXT", - "PTRACE_PEEKDATA", - "PTRACE_PEEKUSER", - "PTRACE_POKETEXT", - "PTRACE_POKEDATA", - "PTRACE_POKEUSER", - "PTRACE_CONT", - "PTRACE_KILL", - "PTRACE_SINGLESTEP", - "PTRACE_INVALID", - "PTRACE_INVALID", - "PTRACE_GETREGS", - "PTRACE_SETREGS", - "PTRACE_GETFPREGS", - "PTRACE_SETFPREGS", - "PTRACE_ATTACH", - "PTRACE_DETACH", - "PTRACE_GETFPXREGS", - "PTRACE_SETFPXREGS", - "PTRACE_INVALID", - "PTRACE_INVALID", - "PTRACE_INVALID", - "PTRACE_INVALID", - "PTRACE_SYSCALL", -}; - -struct gdb_regs { - long ebx; /* 0 */ - long ecx; /* 4 */ - long edx; /* 8 */ - long esi; /* 12 */ - long edi; /* 16 */ - long ebp; /* 20 */ - long eax; /* 24 */ - int xds; /* 28 */ - int xes; /* 32 */ - int xfs; /* 36 */ - int xgs; /* 40 */ - long orig_eax; /* 44 */ - long eip; /* 48 */ - int xcs; /* 52 */ - long eflags; /* 56 */ - long esp; /* 60 */ - int xss; /* 64 */ -}; - -#define FETCH_REGS(cpu) \ - if (!regs_valid[cpu]) \ - { \ - int retval = xc_domain_get_vcpu_context( \ - xc_handle, domid, cpu, &ctxt[cpu]); \ - if (retval) \ - goto error_out; \ - cr3[cpu] = ctxt[cpu].ctrlreg[3]; /* physical address */ \ - regs_valid[cpu] = 1; \ - } - -#define printval(x) printf("%s = %lx\n", #x, (long)x); -#define SET_PT_REGS(pt, xc) \ -{ \ - pt.ebx = xc.ebx; \ - pt.ecx = xc.ecx; \ - pt.edx = xc.edx; \ - pt.esi = xc.esi; \ - pt.edi = xc.edi; \ - pt.ebp = xc.ebp; \ - pt.eax = xc.eax; \ - pt.eip = xc.eip; \ - pt.xcs = xc.cs; \ - pt.eflags = xc.eflags; \ - pt.esp = xc.esp; \ - pt.xss = xc.ss; \ - pt.xes = xc.es; \ - pt.xds = xc.ds; \ - pt.xfs = xc.fs; \ - pt.xgs = xc.gs; \ -} - -#define SET_XC_REGS(pt, xc) \ -{ \ - xc.ebx = pt->ebx; \ - xc.ecx = pt->ecx; \ - xc.edx = pt->edx; \ - xc.esi = pt->esi; \ - xc.edi = pt->edi; \ - xc.ebp = pt->ebp; \ - xc.eax = pt->eax; \ - xc.eip = pt->eip; \ - xc.cs = pt->xcs; \ - xc.eflags = pt->eflags; \ - xc.esp = pt->esp; \ - xc.ss = pt->xss; \ - xc.es = pt->xes; \ - xc.ds = pt->xds; \ - xc.fs = pt->xfs; \ - xc.gs = pt->xgs; \ -} - -#define vtopdi(va) ((va) >> PDRSHIFT) -#define vtopti(va) (((va) >> PAGE_SHIFT) & 0x3ff) +#include <thread_db.h> +#include "xc_ptrace.h" + /* XXX application state */ -static long nr_pages = 0; -unsigned long *page_array = NULL; -static int regs_valid[MAX_VIRT_CPUS]; -static unsigned long cr3[MAX_VIRT_CPUS]; -static vcpu_guest_context_t ctxt[MAX_VIRT_CPUS]; - -static inline int paging_enabled(vcpu_guest_context_t *v) +static long nr_pages = 0; +static unsigned long *page_array = NULL; +static int current_domid = -1; + +static cpumap_t online_cpumap; +static cpumap_t regs_valid; +static vcpu_guest_context_t ctxt[MAX_VIRT_CPUS]; + +extern int ffsll(long long int); +#define FOREACH_CPU(cpumap, i) for ( cpumap = online_cpumap; (i = ffsll(cpumap)); cpumap &= ~(1 << (index - 1)) ) + + +static int +fetch_regs(int xc_handle, int cpu, int *online) +{ + xc_vcpuinfo_t info; + int retval = 0; + + if (online) + *online = 0; + if ( !(regs_valid & (1 << cpu)) ) { + retval = xc_domain_get_vcpu_context(xc_handle, current_domid, + cpu, &ctxt[cpu]); + if ( retval ) + goto done; + regs_valid |= (1 << cpu); + + } + if ( online == NULL ) + goto done; + + retval = xc_domain_get_vcpu_info(xc_handle, current_domid, + cpu, &info); + *online = info.online; + + done: + return retval; +} + +#define FETCH_REGS(cpu) if (fetch_regs(xc_handle, cpu, NULL)) goto error_out; + + +static struct thr_ev_handlers { + thr_ev_handler_t td_create; + thr_ev_handler_t td_death; +} handlers; + +void +xc_register_event_handler(thr_ev_handler_t h, + td_event_e e) +{ + switch (e) { + case TD_CREATE: + handlers.td_create = h; + break; + case TD_DEATH: + handlers.td_death = h; + break; + default: + abort(); /* XXX */ + } +} + +static inline int +paging_enabled(vcpu_guest_context_t *v) { unsigned long cr0 = v->ctrlreg[0]; return (cr0 & X86_CR0_PE) && (cr0 & X86_CR0_PG); +} + +/* + * Fetch registers for all online cpus and set the cpumap + * to indicate which cpus are online + * + */ + +static int +get_online_cpumap(int xc_handle, dom0_getdomaininfo_t *d, cpumap_t *cpumap) +{ + int i, online, retval; + + *cpumap = 0; + for (i = 0; i <= d->max_vcpu_id; i++) { + if ((retval = fetch_regs(xc_handle, i, &online))) + goto error_out; + if (online) + *cpumap |= (1 << i); + } + + return 0; + error_out: + return retval; +} + +/* + * Notify GDB of any vcpus that have come online or gone offline + * update online_cpumap + * + */ + +static void +online_vcpus_changed(cpumap_t cpumap) +{ + cpumap_t changed_cpumap = cpumap ^ online_cpumap; + int index; + + while ( (index = ffsll(changed_cpumap)) ) { + if ( cpumap & (1 << (index - 1)) ) { + if (handlers.td_create) handlers.td_create(index - 1); + } else { + printf("thread death: %d\n", index - 1); + if (handlers.td_death) handlers.td_death(index - 1); + } + changed_cpumap &= ~(1 << (index - 1)); + } + online_cpumap = cpumap; + } /* --------------------- */ @@ -132,7 +136,6 @@ static void * map_domain_va_pae( int xc_handle, - unsigned long domid, int cpu, void *guest_va, int perm) @@ -144,24 +147,24 @@ FETCH_REGS(cpu); l3 = xc_map_foreign_range( - xc_handle, domid, PAGE_SIZE, PROT_READ, cr3[cpu] >> PAGE_SHIFT); + xc_handle, current_domid, PAGE_SIZE, PROT_READ, ctxt[cpu].ctrlreg[3] >> PAGE_SHIFT); if ( l3 == NULL ) goto error_out; l2p = l3[l3_table_offset_pae(va)] >> PAGE_SHIFT; - l2 = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ, l2p); + l2 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, PROT_READ, l2p); if ( l2 == NULL ) goto error_out; l1p = l2[l2_table_offset_pae(va)] >> PAGE_SHIFT; - l1 = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, perm, l1p); + l1 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, perm, l1p); if ( l1 == NULL ) goto error_out; p = l1[l1_table_offset_pae(va)] >> PAGE_SHIFT; if ( v != NULL ) munmap(v, PAGE_SIZE); - v = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, perm, p); + v = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, perm, p); if ( v == NULL ) goto error_out; @@ -174,16 +177,17 @@ static void * map_domain_va( int xc_handle, - unsigned long domid, int cpu, void *guest_va, int perm) { + unsigned long pde, page; unsigned long va = (unsigned long)guest_va; - long npgs = xc_get_tot_pages(xc_handle, domid); - - static unsigned long cr3_phys[MAX_VIRT_CPUS]; + long npgs = xc_get_tot_pages(xc_handle, current_domid); + + + static uint32_t cr3_phys[MAX_VIRT_CPUS]; static unsigned long *cr3_virt[MAX_VIRT_CPUS]; static unsigned long pde_phys[MAX_VIRT_CPUS]; static unsigned long *pde_virt[MAX_VIRT_CPUS]; @@ -202,7 +206,7 @@ } if ( mode == MODE_PAE ) - return map_domain_va_pae(xc_handle, domid, cpu, guest_va, perm); + return map_domain_va_pae(xc_handle, cpu, guest_va, perm); if ( nr_pages != npgs ) { @@ -214,7 +218,7 @@ printf("Could not allocate memory\n"); goto error_out; } - if ( xc_get_pfn_list(xc_handle, domid, + if ( xc_get_pfn_list(xc_handle, current_domid, page_array, nr_pages) != nr_pages ) { printf("Could not get the page frame list\n"); @@ -224,13 +228,13 @@ FETCH_REGS(cpu); - if ( cr3[cpu] != cr3_phys[cpu] ) - { - cr3_phys[cpu] = cr3[cpu]; + if ( ctxt[cpu].ctrlreg[3] != cr3_phys[cpu] ) + { + cr3_phys[cpu] = ctxt[cpu].ctrlreg[3]; if ( cr3_virt[cpu] ) munmap(cr3_virt[cpu], PAGE_SIZE); cr3_virt[cpu] = xc_map_foreign_range( - xc_handle, domid, PAGE_SIZE, PROT_READ, + xc_handle, current_domid, PAGE_SIZE, PROT_READ, cr3_phys[cpu] >> PAGE_SHIFT); if ( cr3_virt[cpu] == NULL ) goto error_out; @@ -245,7 +249,7 @@ if ( pde_virt[cpu] ) munmap(pde_virt[cpu], PAGE_SIZE); pde_virt[cpu] = xc_map_foreign_range( - xc_handle, domid, PAGE_SIZE, PROT_READ, + xc_handle, current_domid, PAGE_SIZE, PROT_READ, pde_phys[cpu] >> PAGE_SHIFT); if ( pde_virt[cpu] == NULL ) goto error_out; @@ -260,7 +264,7 @@ if ( page_virt[cpu] ) munmap(page_virt[cpu], PAGE_SIZE); page_virt[cpu] = xc_map_foreign_range( - xc_handle, domid, PAGE_SIZE, perm, + xc_handle, current_domid, PAGE_SIZE, perm, page_phys[cpu] >> PAGE_SHIFT); if ( page_virt[cpu] == NULL ) { @@ -286,12 +290,15 @@ DECLARE_DOM0_OP; int retval; struct timespec ts; + cpumap_t cpumap; + ts.tv_sec = 0; ts.tv_nsec = 10*1000*1000; op.cmd = DOM0_GETDOMAININFO; op.u.getdomaininfo.domain = domain; - + + retry: retval = do_dom0_op(xc_handle, &op); if ( retval || (op.u.getdomaininfo.domain != domain) ) @@ -309,17 +316,22 @@ nanosleep(&ts,NULL); goto retry; } - + /* XXX check for ^C here */ done: + if (get_online_cpumap(xc_handle, &op.u.getdomaininfo, &cpumap)) + printf("get_online_cpumap failed\n"); + if (online_cpumap != cpumap) + online_vcpus_changed(cpumap); return retval; } + long xc_ptrace( int xc_handle, enum __ptrace_request request, - uint32_t domid, + uint32_t domid_tid, long eaddr, long edata) { @@ -328,18 +340,19 @@ struct gdb_regs pt; long retval = 0; unsigned long *guest_va; - int cpu = VCPU; + cpumap_t cpumap; + int cpu, index; void *addr = (char *)eaddr; void *data = (char *)edata; - op.interface_version = DOM0_INTERFACE_VERSION; + cpu = (request != PTRACE_ATTACH) ? domid_tid : 0; switch ( request ) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: guest_va = (unsigned long *)map_domain_va( - xc_handle, domid, cpu, addr, PROT_READ); + xc_handle, cpu, addr, PROT_READ); if ( guest_va == NULL ) { status = EFAULT; @@ -350,10 +363,10 @@ case PTRACE_POKETEXT: case PTRACE_POKEDATA: + /* XXX assume that all CPUs have the same address space */ guest_va = (unsigned long *)map_domain_va( - xc_handle, domid, cpu, addr, PROT_READ|PROT_WRITE); - if ( guest_va == NULL ) - { + xc_handle, cpu, addr, PROT_READ|PROT_WRITE); + if ( guest_va == NULL ) { status = EFAULT; goto error_out; } @@ -363,6 +376,7 @@ case PTRACE_GETREGS: case PTRACE_GETFPREGS: case PTRACE_GETFPXREGS: + FETCH_REGS(cpu); if ( request == PTRACE_GETREGS ) { @@ -380,44 +394,18 @@ break; case PTRACE_SETREGS: - op.cmd = DOM0_SETDOMAININFO; - SET_XC_REGS(((struct gdb_regs *)data), ctxt[VCPU].user_regs); - op.u.setdomaininfo.domain = domid; - /* XXX need to understand multiple vcpus */ - op.u.setdomaininfo.vcpu = cpu; - op.u.setdomaininfo.ctxt = &ctxt[cpu]; - retval = do_dom0_op(xc_handle, &op); + SET_XC_REGS(((struct gdb_regs *)data), ctxt[cpu].user_regs); + retval = xc_domain_setinfo(xc_handle, current_domid, cpu, &ctxt[cpu]); if (retval) goto error_out; break; - case PTRACE_ATTACH: - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = domid; - retval = do_dom0_op(xc_handle, &op); - if ( retval || (op.u.getdomaininfo.domain != domid) ) - { - perror("dom0 op failed"); - goto error_out; - } - if ( op.u.getdomaininfo.flags & DOMFLAGS_PAUSED ) - { - printf("domain currently paused\n"); - goto error_out; - } - printf("domain not currently paused\n"); - op.cmd = DOM0_PAUSEDOMAIN; - op.u.pausedomain.domain = domid; - retval = do_dom0_op(xc_handle, &op); - break; - case PTRACE_SINGLESTEP: - ctxt[VCPU].user_regs.eflags |= PSL_T; - op.cmd = DOM0_SETDOMAININFO; - op.u.setdomaininfo.domain = domid; - op.u.setdomaininfo.vcpu = 0; - op.u.setdomaininfo.ctxt = &ctxt[cpu]; - retval = do_dom0_op(xc_handle, &op); + /* XXX we can still have problems if the user switches threads + * during single-stepping - but that just seems retarded + */ + ctxt[cpu].user_regs.eflags |= PSL_T; + retval = xc_domain_setinfo(xc_handle, current_domid, cpu, &ctxt[cpu]); if ( retval ) { perror("dom0 op failed"); @@ -429,27 +417,56 @@ case PTRACE_DETACH: if ( request != PTRACE_SINGLESTEP ) { - FETCH_REGS(cpu); - /* Clear trace flag */ - if ( ctxt[cpu].user_regs.eflags & PSL_T ) - { - ctxt[cpu].user_regs.eflags &= ~PSL_T; - op.cmd = DOM0_SETDOMAININFO; - op.u.setdomaininfo.domain = domid; - op.u.setdomaininfo.vcpu = cpu; - op.u.setdomaininfo.ctxt = &ctxt[cpu]; - retval = do_dom0_op(xc_handle, &op); - if ( retval ) - { - perror("dom0 op failed"); - goto error_out; + FOREACH_CPU(cpumap, index) { + cpu = index - 1; + FETCH_REGS(cpu); + /* Clear trace flag */ + if ( ctxt[cpu].user_regs.eflags & PSL_T ) { + ctxt[cpu].user_regs.eflags &= ~PSL_T; + retval = xc_domain_setinfo(xc_handle, current_domid, + cpu, &ctxt[cpu]); + if ( retval ) { + perror("dom0 op failed"); + goto error_out; + } } } } - regs_valid[cpu] = 0; - op.cmd = DOM0_UNPAUSEDOMAIN; - op.u.unpausedomain.domain = domid > 0 ? domid : -domid; + if ( request == PTRACE_DETACH ) + { + op.cmd = DOM0_SETDEBUGGING; + op.u.setdebugging.domain = current_domid; + op.u.setdebugging.enable = 0; + retval = do_dom0_op(xc_handle, &op); + } + regs_valid = 0; + xc_domain_unpause(xc_handle, current_domid > 0 ? current_domid : -current_domid); + break; + + case PTRACE_ATTACH: + current_domid = domid_tid; + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = current_domid; retval = do_dom0_op(xc_handle, &op); + if ( retval || (op.u.getdomaininfo.domain != current_domid) ) + { + perror("dom0 op failed"); + goto error_out; + } + if ( op.u.getdomaininfo.flags & DOMFLAGS_PAUSED ) + { + printf("domain currently paused\n"); + } else + retval = xc_domain_pause(xc_handle, current_domid); + op.cmd = DOM0_SETDEBUGGING; + op.u.setdebugging.domain = current_domid; + op.u.setdebugging.enable = 1; + retval = do_dom0_op(xc_handle, &op); + + if (get_online_cpumap(xc_handle, &op.u.getdomaininfo, &cpumap)) + printf("get_online_cpumap failed\n"); + if (online_cpumap != cpumap) + online_vcpus_changed(cpumap); break; case PTRACE_SETFPREGS: diff -r 11cd619db035 -r d3b10a2a82d4 tools/libxc/xc_vmx_build.c --- a/tools/libxc/xc_vmx_build.c Tue Dec 20 17:16:15 2005 +++ b/tools/libxc/xc_vmx_build.c Tue Dec 20 17:16:24 2005 @@ -288,11 +288,11 @@ l2_pgentry_t *vl2tab=NULL, *vl2e=NULL; unsigned long *page_array = NULL; #ifdef __x86_64__ - l3_pgentry_t *vl3tab=NULL, *vl3e=NULL; + l3_pgentry_t *vl3tab=NULL; unsigned long l3tab; #endif - unsigned long l2tab; - unsigned long l1tab; + unsigned long l2tab = 0; + unsigned long l1tab = 0; unsigned long count, i; shared_info_t *shared_info; void *e820_page; @@ -323,7 +323,7 @@ } /* memsize is in megabytes */ - v_end = memsize << 20; + v_end = (unsigned long)memsize << 20; #ifdef __i386__ nr_pt_pages = 1 + ((memsize + 3) >> 2); @@ -435,15 +435,16 @@ goto error_out; memset(vl2tab, 0, PAGE_SIZE); munmap(vl2tab, PAGE_SIZE); + vl2tab = NULL; vl3tab[i] = l2tab | L3_PROT; } - vl3e = &vl3tab[l3_table_offset(0)]; for ( count = 0; count < (v_end >> PAGE_SHIFT); count++ ) { - if (!(count & (1 << (L3_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)))){ + if ( !(count & ((1 << (L3_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)) - 1)) ) + { l2tab = vl3tab[count >> (L3_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)] - & PAGE_MASK; + & PAGE_MASK; if (vl2tab != NULL) munmap(vl2tab, PAGE_SIZE); diff -r 11cd619db035 -r d3b10a2a82d4 tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Tue Dec 20 17:16:15 2005 +++ b/tools/libxc/xenctrl.h Tue Dec 20 17:16:24 2005 @@ -94,25 +94,12 @@ } xc_core_header_t; -long xc_ptrace( - int xc_handle, - enum __ptrace_request request, - uint32_t domid, - long addr, - long data); - long xc_ptrace_core( int xc_handle, enum __ptrace_request request, uint32_t domid, long addr, long data); - -int xc_waitdomain( - int xc_handle, - int domain, - int *status, - int options); int xc_waitdomain_core( int xc_handle, @@ -219,6 +206,20 @@ unsigned int max_doms, xc_dominfo_t *info); + +/** + * This function will set the vcpu context for the specified domain. + * + * @parm xc_handle a handle to an open hypervisor interface + * @parm domid the domain to set the vcpu context for + * @parm vcpu the vcpu number for the context + * @parm ctxt pointer to the the cpu context with the values to set + * @return the number of domains enumerated or -1 on error + */ +int xc_domain_setinfo(int xc_handle, + uint32_t domid, + uint32_t vcpu, + vcpu_guest_context_t *ctxt); /** * This function will return information about one or more domains, using a * single hypercall. The domain information will be stored into the supplied diff -r 11cd619db035 -r d3b10a2a82d4 tools/python/xen/xend/image.py --- a/tools/python/xen/xend/image.py Tue Dec 20 17:16:15 2005 +++ b/tools/python/xen/xend/image.py Tue Dec 20 17:16:24 2005 @@ -237,7 +237,7 @@ # Return a list of cmd line args to the device models based on the # xm config file def parseDeviceModelArgs(self, imageConfig, deviceConfig): - dmargs = [ 'cdrom', 'boot', 'fda', 'fdb', 'ne2000', + dmargs = [ 'cdrom', 'boot', 'fda', 'fdb', 'ne2000', 'audio', 'localtime', 'serial', 'stdvga', 'isa', 'vcpus'] ret = [] for a in dmargs: @@ -246,9 +246,10 @@ # python doesn't allow '-' in variable names if a == 'stdvga': a = 'std-vga' if a == 'ne2000': a = 'nic-ne2000' + if a == 'audio': a = 'enable-audio' # Handle booleans gracefully - if a in ['localtime', 'std-vga', 'isa', 'nic-ne2000']: + if a in ['localtime', 'std-vga', 'isa', 'nic-ne2000', 'enable-audio']: if v != None: v = int(v) if v: ret.append("-%s" % a) else: diff -r 11cd619db035 -r d3b10a2a82d4 tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Tue Dec 20 17:16:15 2005 +++ b/tools/python/xen/xm/create.py Tue Dec 20 17:16:24 2005 @@ -371,6 +371,10 @@ gopts.var('ne2000', val='no|yes', fn=set_bool, default=0, use="Should device models use ne2000?") + +gopts.var('audio', val='no|yes', + fn=set_bool, default=0, + use="Should device models enable audio?") gopts.var('vnc', val='', fn=set_value, default=None, @@ -521,7 +525,7 @@ """Create the config for VMX devices. """ args = [ 'device_model', 'vcpus', 'cdrom', 'boot', 'fda', 'fdb', - 'localtime', 'serial', 'stdvga', 'isa', 'nographic', + 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'audio', 'vnc', 'vncviewer', 'sdl', 'display', 'ne2000', 'lapic'] for a in args: if (vals.__dict__[a]): diff -r 11cd619db035 -r d3b10a2a82d4 tools/vtpm_manager/manager/securestorage.c --- a/tools/vtpm_manager/manager/securestorage.c Tue Dec 20 17:16:15 2005 +++ b/tools/vtpm_manager/manager/securestorage.c Tue Dec 20 17:16:24 2005 @@ -54,48 +54,138 @@ #include "buffer.h" #include "log.h" +TPM_RESULT envelope_encrypt(const buffer_t *inbuf, + CRYPTO_INFO *asymkey, + buffer_t *sealed_data) { + TPM_RESULT status = TPM_SUCCESS; + symkey_t symkey; + buffer_t data_cipher = NULL_BUF, + symkey_cipher = NULL_BUF; + + UINT32 i; + struct pack_constbuf_t symkey_cipher32, data_cipher32; + + vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Enveloping[%d]: 0x", buffer_len(inbuf)); + for (i=0; i< buffer_len(inbuf); i++) + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", inbuf->bytes[i]); + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n"); + + // Generate a sym key and encrypt state with it + TPMTRY(TPM_ENCRYPT_ERROR, Crypto_symcrypto_genkey (&symkey) ); + TPMTRY(TPM_ENCRYPT_ERROR, Crypto_symcrypto_encrypt (&symkey, inbuf, &data_cipher) ); + + // Encrypt symmetric key + TPMTRYRETURN( VTSP_Bind( asymkey, + &symkey.key, + &symkey_cipher) ); + + // Create output blob: symkey_size + symkey_cipher + state_cipher_size + state_cipher + + symkey_cipher32.size = buffer_len(&symkey_cipher); + symkey_cipher32.data = symkey_cipher.bytes; + + data_cipher32.size = buffer_len(&data_cipher); + data_cipher32.data = data_cipher.bytes; + + TPMTRYRETURN( buffer_init(sealed_data, 2 * sizeof(UINT32) + symkey_cipher32.size + data_cipher32.size, NULL)); + + BSG_PackList(sealed_data->bytes, 2, + BSG_TPM_SIZE32_DATA, &symkey_cipher32, + BSG_TPM_SIZE32_DATA, &data_cipher32); + + vtpmloginfo(VTPM_LOG_VTPM, "Saved %d bytes of E(symkey) + %d bytes of E(data)\n", buffer_len(&symkey_cipher), buffer_len(&data_cipher)); + goto egress; + + abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "Failed to envelope encrypt\n."); + + egress: + + buffer_free ( &data_cipher); + buffer_free ( &symkey_cipher); + Crypto_symcrypto_freekey (&symkey); + + return status; +} + +TPM_RESULT envelope_decrypt(const long cipher_size, + const BYTE *cipher, + TCS_CONTEXT_HANDLE TCSContext, + TPM_HANDLE keyHandle, + const TPM_AUTHDATA *key_usage_auth, + buffer_t *unsealed_data) { + + TPM_RESULT status = TPM_SUCCESS; + symkey_t symkey; + buffer_t data_cipher = NULL_BUF, + symkey_clear = NULL_BUF, + symkey_cipher = NULL_BUF; + struct pack_buf_t symkey_cipher32, data_cipher32; + int i; + + memset(&symkey, 0, sizeof(symkey_t)); + + vtpmloginfo(VTPM_LOG_VTPM_DEEP, "envelope decrypting[%ld]: 0x", cipher_size); + for (i=0; i< cipher_size; i++) + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", cipher[i]); + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n"); + + BSG_UnpackList(cipher, 2, + BSG_TPM_SIZE32_DATA, &symkey_cipher32, + BSG_TPM_SIZE32_DATA, &data_cipher32); + + TPMTRYRETURN( buffer_init_convert (&symkey_cipher, + symkey_cipher32.size, + symkey_cipher32.data) ); + + TPMTRYRETURN( buffer_init_convert (&data_cipher, + data_cipher32.size, + data_cipher32.data) ); + + // Decrypt Symmetric Key + TPMTRYRETURN( VTSP_Unbind( TCSContext, + keyHandle, + &symkey_cipher, + key_usage_auth, + &symkey_clear, + &(vtpm_globals->keyAuth) ) ); + + // create symmetric key using saved bits + Crypto_symcrypto_initkey (&symkey, &symkey_clear); + + // Decrypt State + TPMTRY(TPM_DECRYPT_ERROR, Crypto_symcrypto_decrypt (&symkey, &data_cipher, unsealed_data) ); + + goto egress; + + abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "Failed to envelope decrypt data\n."); + + egress: + buffer_free ( &data_cipher); + buffer_free ( &symkey_clear); + buffer_free ( &symkey_cipher); + Crypto_symcrypto_freekey (&symkey); + + return status; +} + TPM_RESULT VTPM_Handle_Save_NVM(VTPM_DMI_RESOURCE *myDMI, const buffer_t *inbuf, buffer_t *outbuf) { TPM_RESULT status = TPM_SUCCESS; - symkey_t symkey; - buffer_t state_cipher = NULL_BUF, - symkey_cipher = NULL_BUF; int fh; long bytes_written; - BYTE *sealed_NVM=NULL; - UINT32 sealed_NVM_size, i; - struct pack_constbuf_t symkey_cipher32, state_cipher32; - - vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Save_NVMing[%d]: 0x", buffer_len(inbuf)); - for (i=0; i< buffer_len(inbuf); i++) - vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", inbuf->bytes[i]); - vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n"); - - // Generate a sym key and encrypt state with it - TPMTRY(TPM_ENCRYPT_ERROR, Crypto_symcrypto_genkey (&symkey) ); - TPMTRY(TPM_ENCRYPT_ERROR, Crypto_symcrypto_encrypt (&symkey, inbuf, &state_cipher) ); - - // Encrypt symmetric key - TPMTRYRETURN( VTSP_Bind( &vtpm_globals->storageKey, - &symkey.key, - &symkey_cipher) ); - - // Create output blob: symkey_size + symkey_cipher + state_cipher_size + state_cipher - - symkey_cipher32.size = buffer_len(&symkey_cipher); - symkey_cipher32.data = symkey_cipher.bytes; - - state_cipher32.size = buffer_len(&state_cipher); - state_cipher32.data = state_cipher.bytes; - - sealed_NVM = (BYTE *) malloc( 2 * sizeof(UINT32) + symkey_cipher32.size + state_cipher32.size); - - sealed_NVM_size = BSG_PackList(sealed_NVM, 2, - BSG_TPM_SIZE32_DATA, &symkey_cipher32, - BSG_TPM_SIZE32_DATA, &state_cipher32); - + buffer_t sealed_NVM; + + + vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Save_NVMing[%d]: 0x\n", buffer_len(inbuf)); + + TPMTRYRETURN( envelope_encrypt(inbuf, + &vtpm_globals->storageKey, + &sealed_NVM) ); + // Mark DMI Table so new save state info will get pushed to disk on return. vtpm_globals->DMI_table_dirty = TRUE; @@ -104,28 +194,22 @@ // after writing the file? We can't get the old one back. // TODO: Backup old file and try and recover that way. fh = open(myDMI->NVMLocation, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE); - if ( (bytes_written = write(fh, sealed_NVM, sealed_NVM_size) ) != (long) sealed_NVM_size) { - vtpmlogerror(VTPM_LOG_VTPM, "We just overwrote a DMI_NVM and failed to finish. %ld/%ld bytes.\n", bytes_written, (long)sealed_NVM_size); + if ( (bytes_written = write(fh, sealed_NVM.bytes, buffer_len(&sealed_NVM) ) != (long) buffer_len(&sealed_NVM))) { + vtpmlogerror(VTPM_LOG_VTPM, "We just overwrote a DMI_NVM and failed to finish. %ld/%ld bytes.\n", bytes_written, (long)buffer_len(&sealed_NVM)); status = TPM_IOERROR; goto abort_egress; } close(fh); - Crypto_SHA1Full (sealed_NVM, sealed_NVM_size, (BYTE *) &myDMI->NVM_measurement); - - vtpmloginfo(VTPM_LOG_VTPM, "Saved %d bytes of E(symkey) + %d bytes of E(NVM)\n", buffer_len(&symkey_cipher), buffer_len(&state_cipher)); - goto egress; - - abort_egress: - vtpmlogerror(VTPM_LOG_VTPM, "Failed to load NVM\n."); - - egress: - - buffer_free ( &state_cipher); - buffer_free ( &symkey_cipher); - free(sealed_NVM); - Crypto_symcrypto_freekey (&symkey); - + Crypto_SHA1Full (sealed_NVM.bytes, buffer_len(&sealed_NVM), (BYTE *) &myDMI->NVM_measurement); + + goto egress; + + abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "Failed to save NVM\n."); + + egress: + buffer_free(&sealed_NVM); return status; } @@ -136,11 +220,7 @@ buffer_t *outbuf) { TPM_RESULT status = TPM_SUCCESS; - symkey_t symkey; - buffer_t state_cipher = NULL_BUF, - symkey_clear = NULL_BUF, - symkey_cipher = NULL_BUF; - struct pack_buf_t symkey_cipher32, state_cipher32; + UINT32 sealed_NVM_size; BYTE *sealed_NVM = NULL; @@ -148,9 +228,7 @@ int fh, stat_ret, i; struct stat file_stat; TPM_DIGEST sealedNVMHash; - - memset(&symkey, 0, sizeof(symkey_t)); - + if (myDMI->NVMLocation == NULL) { vtpmlogerror(VTPM_LOG_VTPM, "Unable to load NVM because the file name NULL.\n"); status = TPM_AUTHFAIL; @@ -168,28 +246,14 @@ } sealed_NVM = (BYTE *) malloc(fh_size); + sealed_NVM_size = (UINT32) fh_size; if (read(fh, sealed_NVM, fh_size) != fh_size) { status = TPM_IOERROR; goto abort_egress; } close(fh); - vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Load_NVMing[%ld]: 0x", fh_size); - for (i=0; i< fh_size; i++) - vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", sealed_NVM[i]); - vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n"); - - sealed_NVM_size = BSG_UnpackList(sealed_NVM, 2, - BSG_TPM_SIZE32_DATA, &symkey_cipher32, - BSG_TPM_SIZE32_DATA, &state_cipher32); - - TPMTRYRETURN( buffer_init_convert (&symkey_cipher, - symkey_cipher32.size, - symkey_cipher32.data) ); - - TPMTRYRETURN( buffer_init_convert (&state_cipher, - state_cipher32.size, - state_cipher32.data) ); + vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Load_NVMing[%ld],\n", fh_size); Crypto_SHA1Full(sealed_NVM, sealed_NVM_size, (BYTE *) &sealedNVMHash); @@ -210,32 +274,19 @@ goto abort_egress; } - // Decrypt Symmetric Key - TPMTRYRETURN( VTSP_Unbind( myDMI->TCSContext, - vtpm_globals->storageKeyHandle, - &symkey_cipher, - (const TPM_AUTHDATA*)&vtpm_globals->storage_key_usage_auth, - &symkey_clear, - &(vtpm_globals->keyAuth) ) ); - - // create symmetric key using saved bits - Crypto_symcrypto_initkey (&symkey, &symkey_clear); - - // Decrypt State - TPMTRY(TPM_DECRYPT_ERROR, Crypto_symcrypto_decrypt (&symkey, &state_cipher, outbuf) ); - + TPMTRYRETURN( envelope_decrypt(fh_size, + sealed_NVM, + myDMI->TCSContext, + vtpm_globals->storageKeyHandle, + (const TPM_AUTHDATA*)&vtpm_globals->storage_key_usage_auth, + outbuf) ); goto egress; abort_egress: vtpmlogerror(VTPM_LOG_VTPM, "Failed to load NVM\n."); egress: - - buffer_free ( &state_cipher); - buffer_free ( &symkey_clear); - buffer_free ( &symkey_cipher); free( sealed_NVM ); - Crypto_symcrypto_freekey (&symkey); return status; } diff -r 11cd619db035 -r d3b10a2a82d4 tools/xm-test/README --- a/tools/xm-test/README Tue Dec 20 17:16:15 2005 +++ b/tools/xm-test/README Tue Dec 20 17:16:24 2005 @@ -54,6 +54,26 @@ you should not attempt to use a ramdisk from a previous minor version of xm-test (i.e., don't use a ramdisk from 0.4.0 with 0.5.0. 0.5.0 should work for 0.5.3 though) + +If you'd like to build and run this with hardware virtual machine assist +(HVM) support to test fully virtualized disk images on VMX hardware, +please add the --enable-vmx-support option to configure: + + # ./autogen + # ./configure --enable-vmx-support + # make + +The ramdisk/bin/create_disk_image script, which builds the full virt +disk.img, requires Lilo 22.7+ to be installed on the system. Lilo is +used to install the bootloader on the disk.img. + +If HVM / VMX support is enabled, the ramdisk/bin/create_disk_image script +will be run to create a full virt disk.img in the ramdisk directory. The +script, by default, will look in /boot for the first non-Xen kernel it +runs across. If you wish to use a different kernel or the script fails +to find a kernel, please run the script manually to make a disk.img +using the -k option. Xm-test will look for disk.img in the ramdisk +directory when run by default. Running diff -r 11cd619db035 -r d3b10a2a82d4 tools/xm-test/ramdisk/Makefile.am --- a/tools/xm-test/ramdisk/Makefile.am Tue Dec 20 17:16:15 2005 +++ b/tools/xm-test/ramdisk/Makefile.am Tue Dec 20 17:16:24 2005 @@ -45,7 +45,7 @@ disk.img: $(XMTEST_VER_IMG) chmod a+x $(VMX_SCRIPT) - $(VMX_SCRIPT) -r $(XMTEST_VER_IMG) -i disk.img + $(VMX_SCRIPT) -r $(XMTEST_VER_IMG) existing: @[ -f $(XMTEST_VER_IMG) ] && ln -sf $(XMTEST_VER_IMG) initrd.img || \ diff -r 11cd619db035 -r d3b10a2a82d4 tools/xm-test/ramdisk/bin/create_disk_image --- a/tools/xm-test/ramdisk/bin/create_disk_image Tue Dec 20 17:16:15 2005 +++ b/tools/xm-test/ramdisk/bin/create_disk_image Tue Dec 20 17:16:24 2005 @@ -77,7 +77,7 @@ function initialize_globals() { PROGNAME="create_disk_image" - IMAGE="hvm.img" + IMAGE="disk.img" KERNEL="" LCONF="lilo.conf" LOOPD="" # Loop device for entire disk image diff -r 11cd619db035 -r d3b10a2a82d4 xen/Rules.mk --- a/xen/Rules.mk Tue Dec 20 17:16:15 2005 +++ b/xen/Rules.mk Tue Dec 20 17:16:24 2005 @@ -6,7 +6,6 @@ debug ?= n perfc ?= n perfc_arrays?= n -domu_debug ?= n crash_debug ?= n XEN_ROOT=$(BASEDIR)/.. @@ -54,10 +53,6 @@ CFLAGS += -g -DVERBOSE endif -ifeq ($(domu_debug),y) -CFLAGS += -DDOMU_DEBUG -endif - ifeq ($(crash_debug),y) CFLAGS += -g -DCRASH_DEBUG endif diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/audit.c --- a/xen/arch/x86/audit.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/audit.c Tue Dec 20 17:16:24 2005 @@ -61,7 +61,7 @@ #ifdef __i386__ #ifdef CONFIG_X86_PAE /* 32b PAE */ - if ( (( frame_table[mfn].u.inuse.type_info & PGT_va_mask ) + if ( (( pfn_to_page(mfn)->u.inuse.type_info & PGT_va_mask ) >> PGT_va_shift) == 3 ) return l2_table_offset(HYPERVISOR_VIRT_START); else @@ -364,7 +364,7 @@ { gmfn = __gpfn_to_mfn(d, a->gpfn_and_flags & PGT_mfn_mask); smfn = a->smfn; - page = &frame_table[smfn]; + page = pfn_to_page(smfn); switch ( a->gpfn_and_flags & PGT_type_mask ) { case PGT_writable_pred: @@ -433,11 +433,13 @@ for_each_vcpu(d, v) { if ( pagetable_get_paddr(v->arch.guest_table) ) - adjust(&frame_table[pagetable_get_pfn(v->arch.guest_table)], !shadow_mode_refcounts(d)); + adjust(pfn_to_page(pagetable_get_pfn(v->arch.guest_table)), + !shadow_mode_refcounts(d)); if ( pagetable_get_paddr(v->arch.shadow_table) ) - adjust(&frame_table[pagetable_get_pfn(v->arch.shadow_table)], 0); + adjust(pfn_to_page(pagetable_get_pfn(v->arch.shadow_table)), + 0); if ( v->arch.monitor_shadow_ref ) - adjust(&frame_table[v->arch.monitor_shadow_ref], 0); + adjust(pfn_to_page(v->arch.monitor_shadow_ref), 0); } } @@ -617,7 +619,7 @@ void scan_for_pfn_in_mfn(struct domain *d, unsigned long xmfn, unsigned long mfn) { - struct pfn_info *page = &frame_table[mfn]; + struct pfn_info *page = pfn_to_page(mfn); l1_pgentry_t *pt = map_domain_page(mfn); int i; diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/dom0_ops.c --- a/xen/arch/x86/dom0_ops.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/dom0_ops.c Tue Dec 20 17:16:24 2005 @@ -210,7 +210,7 @@ unlikely((d = find_domain_by_id(dom)) == NULL) ) break; - page = &frame_table[pfn]; + page = pfn_to_page(pfn); if ( likely(get_page(page, d)) ) { @@ -285,7 +285,7 @@ struct pfn_info *page; unsigned long mfn = l_arr[j]; - page = &frame_table[mfn]; + page = pfn_to_page(mfn); if ( likely(pfn_valid(mfn) && get_page(page, d)) ) { @@ -350,15 +350,14 @@ list_ent = d->page_list.next; for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ ) { - pfn = list_entry(list_ent, struct pfn_info, list) - - frame_table; + pfn = page_to_pfn(list_entry(list_ent, struct pfn_info, list)); if ( put_user(pfn, buffer) ) { ret = -EFAULT; break; } buffer++; - list_ent = frame_table[pfn].list.next; + list_ent = pfn_to_page(pfn)->list.next; } spin_unlock(&d->page_alloc_lock); diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/domain.c --- a/xen/arch/x86/domain.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/domain.c Tue Dec 20 17:16:24 2005 @@ -190,7 +190,7 @@ list_for_each_entry ( page, &d->page_list, list ) { printk("Page %p: mfn=%p, caf=%08x, taf=%" PRtype_info "\n", - _p(page_to_phys(page)), _p(page - frame_table), + _p(page_to_phys(page)), _p(page_to_pfn(page)), page->count_info, page->u.inuse.type_info); } } @@ -198,13 +198,13 @@ list_for_each_entry ( page, &d->xenpage_list, list ) { printk("XenPage %p: mfn=%p, caf=%08x, taf=%" PRtype_info "\n", - _p(page_to_phys(page)), _p(page - frame_table), + _p(page_to_phys(page)), _p(page_to_pfn(page)), page->count_info, page->u.inuse.type_info); } page = virt_to_page(d->shared_info); printk("Shared_info@%p: mfn=%p, caf=%08x, taf=%" PRtype_info "\n", - _p(page_to_phys(page)), _p(page - frame_table), page->count_info, + _p(page_to_phys(page)), _p(page_to_pfn(page)), page->count_info, page->u.inuse.type_info); } @@ -391,19 +391,19 @@ if ( shadow_mode_refcounts(d) ) { - if ( !get_page(&frame_table[phys_basetab>>PAGE_SHIFT], d) ) + if ( !get_page(pfn_to_page(phys_basetab>>PAGE_SHIFT), d) ) return -EINVAL; } else if ( !(c->flags & VGCF_VMX_GUEST) ) { - if ( !get_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT], d, + if ( !get_page_and_type(pfn_to_page(phys_basetab>>PAGE_SHIFT), d, PGT_base_page_table) ) return -EINVAL; } if ( (rc = (int)set_gdt(v, c->gdt_frames, c->gdt_ents)) != 0 ) { - put_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT]); + put_page_and_type(pfn_to_page(phys_basetab>>PAGE_SHIFT)); return rc; } diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/domain_build.c --- a/xen/arch/x86/domain_build.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/domain_build.c Tue Dec 20 17:16:24 2005 @@ -405,7 +405,7 @@ *l1tab = l1e_from_pfn(mfn, L1_PROT); l1tab++; - page = &frame_table[mfn]; + page = pfn_to_page(mfn); if ( !get_page_and_type(page, d, PGT_writable_page) ) BUG(); @@ -418,7 +418,7 @@ l1tab += l1_table_offset(vpt_start); for ( count = 0; count < nr_pt_pages; count++ ) { - page = &frame_table[l1e_get_pfn(*l1tab)]; + page = pfn_to_page(l1e_get_pfn(*l1tab)); if ( !opt_dom0_shadow ) l1e_remove_flags(*l1tab, _PAGE_RW); else @@ -548,7 +548,7 @@ *l1tab = l1e_from_pfn(mfn, L1_PROT); l1tab++; - page = &frame_table[mfn]; + page = pfn_to_page(mfn); if ( (page->u.inuse.type_info == 0) && !get_page_and_type(page, d, PGT_writable_page) ) BUG(); @@ -567,7 +567,7 @@ for ( count = 0; count < nr_pt_pages; count++ ) { l1e_remove_flags(*l1tab, _PAGE_RW); - page = &frame_table[l1e_get_pfn(*l1tab)]; + page = pfn_to_page(l1e_get_pfn(*l1tab)); /* Read-only mapping + PGC_allocated + page-table page. */ page->count_info = PGC_allocated | 3; diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/mm.c --- a/xen/arch/x86/mm.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/mm.c Tue Dec 20 17:16:24 2005 @@ -202,7 +202,7 @@ /* First 1MB of RAM is historically marked as I/O. */ for ( i = 0; i < 0x100; i++ ) { - page = &frame_table[i]; + page = pfn_to_page(i); page->count_info = PGC_allocated | 1; page->u.inuse.type_info = PGT_writable_page | PGT_validated | 1; page_set_owner(page, dom_io); @@ -216,10 +216,10 @@ /* Every page from cursor to start of next RAM region is I/O. */ rstart_pfn = PFN_UP(e820.map[i].addr); rend_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); - while ( pfn < rstart_pfn ) + for ( ; pfn < rstart_pfn; pfn++ ) { BUG_ON(!pfn_valid(pfn)); - page = &frame_table[pfn++]; + page = pfn_to_page(pfn); page->count_info = PGC_allocated | 1; page->u.inuse.type_info = PGT_writable_page | PGT_validated | 1; page_set_owner(page, dom_io); @@ -253,7 +253,7 @@ pfn = l1e_get_pfn(v->arch.perdomain_ptes[i]); if ( pfn == 0 ) continue; v->arch.perdomain_ptes[i] = l1e_empty(); - page = &frame_table[pfn]; + page = pfn_to_page(pfn); ASSERT_PAGE_IS_TYPE(page, PGT_ldt_page); ASSERT_PAGE_IS_DOMAIN(page, v->domain); put_page_and_type(page); @@ -320,13 +320,13 @@ if ( unlikely(!VALID_MFN(gmfn)) ) return 0; - res = get_page_and_type(&frame_table[gmfn], d, PGT_ldt_page); + res = get_page_and_type(pfn_to_page(gmfn), d, PGT_ldt_page); if ( !res && unlikely(shadow_mode_refcounts(d)) ) { shadow_lock(d); shadow_remove_all_write_access(d, gpfn, gmfn); - res = get_page_and_type(&frame_table[gmfn], d, PGT_ldt_page); + res = get_page_and_type(pfn_to_page(gmfn), d, PGT_ldt_page); shadow_unlock(d); } @@ -344,7 +344,7 @@ static int get_page_from_pagenr(unsigned long page_nr, struct domain *d) { - struct pfn_info *page = &frame_table[page_nr]; + struct pfn_info *page = pfn_to_page(page_nr); if ( unlikely(!pfn_valid(page_nr)) || unlikely(!get_page(page, d)) ) { @@ -360,7 +360,7 @@ unsigned long type, struct domain *d) { - struct pfn_info *page = &frame_table[page_nr]; + struct pfn_info *page = pfn_to_page(page_nr); if ( unlikely(!get_page_from_pagenr(page_nr, d)) ) return 0; @@ -412,7 +412,7 @@ * Make sure that the mapped frame is an already-validated L2 table. * If so, atomically increment the count (checking for overflow). */ - page = &frame_table[pfn]; + page = pfn_to_page(pfn); y = page->u.inuse.type_info; do { x = y; @@ -435,7 +435,7 @@ l1_pgentry_t l1e, struct domain *d) { unsigned long mfn = l1e_get_pfn(l1e); - struct pfn_info *page = &frame_table[mfn]; + struct pfn_info *page = pfn_to_page(mfn); int okay; extern int domain_iomem_in_pfn(struct domain *d, unsigned long pfn); @@ -587,7 +587,7 @@ void put_page_from_l1e(l1_pgentry_t l1e, struct domain *d) { unsigned long pfn = l1e_get_pfn(l1e); - struct pfn_info *page = &frame_table[pfn]; + struct pfn_info *page = pfn_to_page(pfn); struct domain *e; struct vcpu *v; @@ -645,7 +645,7 @@ { if ( (l2e_get_flags(l2e) & _PAGE_PRESENT) && (l2e_get_pfn(l2e) != pfn) ) - put_page_and_type(&frame_table[l2e_get_pfn(l2e)]); + put_page_and_type(pfn_to_page(l2e_get_pfn(l2e))); } @@ -655,7 +655,7 @@ { if ( (l3e_get_flags(l3e) & _PAGE_PRESENT) && (l3e_get_pfn(l3e) != pfn) ) - put_page_and_type(&frame_table[l3e_get_pfn(l3e)]); + put_page_and_type(pfn_to_page(l3e_get_pfn(l3e))); } #endif @@ -666,7 +666,7 @@ { if ( (l4e_get_flags(l4e) & _PAGE_PRESENT) && (l4e_get_pfn(l4e) != pfn) ) - put_page_and_type(&frame_table[l4e_get_pfn(l4e)]); + put_page_and_type(pfn_to_page(l4e_get_pfn(l4e))); } #endif @@ -1584,9 +1584,9 @@ write_ptbase(v); if ( shadow_mode_refcounts(d) ) - put_page(&frame_table[old_base_mfn]); + put_page(pfn_to_page(old_base_mfn)); else - put_page_and_type(&frame_table[old_base_mfn]); + put_page_and_type(pfn_to_page(old_base_mfn)); /* CR3 also holds a ref to its shadow... */ if ( shadow_mode_enabled(d) ) @@ -1595,7 +1595,7 @@ put_shadow_ref(v->arch.monitor_shadow_ref); v->arch.monitor_shadow_ref = pagetable_get_pfn(v->arch.monitor_table); - ASSERT(!page_get_owner(&frame_table[v->arch.monitor_shadow_ref])); + ASSERT(!page_get_owner(pfn_to_page(v->arch.monitor_shadow_ref))); get_shadow_ref(v->arch.monitor_shadow_ref); } } @@ -1763,7 +1763,7 @@ okay = 1; mfn = op.arg1.mfn; - page = &frame_table[mfn]; + page = pfn_to_page(mfn); switch ( op.cmd ) { @@ -1845,7 +1845,7 @@ pagetable_get_pfn(v->arch.guest_table_user); v->arch.guest_table_user = mk_pagetable(mfn << PAGE_SHIFT); if ( old_mfn != 0 ) - put_page_and_type(&frame_table[old_mfn]); + put_page_and_type(pfn_to_page(old_mfn)); } break; #endif @@ -2145,7 +2145,7 @@ va = map_domain_page_with_cache(mfn, &mapcache); va = (void *)((unsigned long)va + (unsigned long)(req.ptr & ~PAGE_MASK)); - page = &frame_table[mfn]; + page = pfn_to_page(mfn); switch ( (type_info = page->u.inuse.type_info) & PGT_type_mask ) { @@ -2285,7 +2285,7 @@ mark_dirty(FOREIGNDOM, mfn); - put_page(&frame_table[mfn]); + put_page(pfn_to_page(mfn)); break; default: @@ -2728,7 +2728,7 @@ for ( i = 0; i < FIRST_RESERVED_GDT_PAGE; i++ ) { if ( (pfn = l1e_get_pfn(v->arch.perdomain_ptes[i])) != 0 ) - put_page_and_type(&frame_table[pfn]); + put_page_and_type(pfn_to_page(pfn)); v->arch.perdomain_ptes[i] = l1e_empty(); v->arch.guest_context.gdt_frames[i] = 0; } @@ -2753,7 +2753,7 @@ for ( i = 0; i < nr_pages; i++ ) { pfn = frames[i]; if ((pfn >= max_page) || - !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) ) + !get_page_and_type(pfn_to_page(pfn), d, PGT_gdt_page) ) goto fail; } @@ -2773,7 +2773,7 @@ fail: while ( i-- > 0 ) - put_page_and_type(&frame_table[frames[i]]); + put_page_and_type(pfn_to_page(frames[i])); return -EINVAL; } @@ -2827,7 +2827,7 @@ return -EINVAL; } - page = &frame_table[mfn]; + page = pfn_to_page(mfn); if ( unlikely(!get_page(page, dom)) ) { UNLOCK_BIGLOCK(dom); @@ -3037,7 +3037,7 @@ if ( likely(l1e_get_intpte(ol1e) == (l1e_get_intpte(nl1e)|_PAGE_RW)) ) { if ( likely(l1e_get_flags(nl1e) & _PAGE_PRESENT) ) - put_page_type(&frame_table[l1e_get_pfn(nl1e)]); + put_page_type(pfn_to_page(l1e_get_pfn(nl1e))); continue; } @@ -3220,7 +3220,7 @@ } pfn = l1e_get_pfn(pte); - page = &frame_table[pfn]; + page = pfn_to_page(pfn); /* We are looking only for read-only mappings of p.t. pages. */ if ( ((l1e_get_flags(pte) & (_PAGE_RW|_PAGE_PRESENT)) != _PAGE_PRESENT) || @@ -3331,7 +3331,7 @@ } pfn = l1e_get_pfn(pte); - page = &frame_table[pfn]; + page = pfn_to_page(pfn); #ifdef CONFIG_X86_64 #define WRPT_PTE_FLAGS (_PAGE_RW | _PAGE_PRESENT | _PAGE_USER) diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/setup.c --- a/xen/arch/x86/setup.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/setup.c Tue Dec 20 17:16:24 2005 @@ -264,7 +264,7 @@ unsigned long _initrd_start = 0, _initrd_len = 0; unsigned int initrdidx = 1; physaddr_t s, e; - int i, e820_raw_nr = 0, bytes = 0; + int i, e820_warn = 0, e820_raw_nr = 0, bytes = 0; struct ns16550_defaults ns16550 = { .data_bits = 8, .parity = 'n', @@ -313,6 +313,22 @@ while ( bytes < mbi->mmap_length ) { memory_map_t *map = __va(mbi->mmap_addr + bytes); + + /* + * This is a gross workaround for a BIOS bug. Some bootloaders do + * not write e820 map entries into pre-zeroed memory. This is + * okay if the BIOS fills in all fields of the map entry, but + * some broken BIOSes do not bother to write the high word of + * the length field if the length is smaller than 4GB. We + * detect and fix this by flagging sections below 4GB that + * appear to be larger than 4GB in size. + */ + if ( (map->base_addr_high == 0) && (map->length_high != 0) ) + { + e820_warn = 1; + map->length_high = 0; + } + e820_raw[e820_raw_nr].addr = ((u64)map->base_addr_high << 32) | (u64)map->base_addr_low; e820_raw[e820_raw_nr].size = @@ -320,6 +336,7 @@ e820_raw[e820_raw_nr].type = (map->type > E820_SHARED_PAGE) ? E820_RESERVED : map->type; e820_raw_nr++; + bytes += map->size + 4; } } @@ -338,6 +355,10 @@ printk("FATAL ERROR: Bootloader provided no memory information.\n"); for ( ; ; ) ; } + + if ( e820_warn ) + printk("WARNING: Buggy e820 map detected and fixed " + "(truncated length fields).\n"); max_page = init_e820(e820_raw, &e820_raw_nr); diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/shadow.c --- a/xen/arch/x86/shadow.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/shadow.c Tue Dec 20 17:16:24 2005 @@ -504,7 +504,7 @@ l2e_from_pfn(smfn, __PAGE_HYPERVISOR); spl2e[l2_table_offset(PERDOMAIN_VIRT_START)] = - l2e_from_paddr(__pa(page_get_owner(&frame_table[gmfn])->arch.mm_perdomain_pt), + l2e_from_paddr(__pa(page_get_owner(pfn_to_page(gmfn))->arch.mm_perdomain_pt), __PAGE_HYPERVISOR); if ( shadow_mode_translate(d) ) // NB: not external @@ -670,7 +670,7 @@ set_guest_back_ptr(d, sl1e, sl1mfn, i); } - frame_table[sl1mfn].tlbflush_timestamp = + pfn_to_page(sl1mfn)->tlbflush_timestamp = SHADOW_ENCODE_MIN_MAX(min, max); unmap_domain_page(gpl1e); @@ -907,7 +907,7 @@ u32 min_max = 0; int min, max, length; - if ( test_and_set_bit(_PGC_out_of_sync, &frame_table[gmfn].count_info) ) + if ( test_and_set_bit(_PGC_out_of_sync, &pfn_to_page(gmfn)->count_info) ) { ASSERT(__shadow_status(d, gpfn, PGT_snapshot)); return SHADOW_SNAPSHOT_ELSEWHERE; @@ -953,7 +953,7 @@ unsigned long mfn) { struct domain *d = v->domain; - struct pfn_info *page = &frame_table[mfn]; + struct pfn_info *page = pfn_to_page(mfn); struct out_of_sync_entry *entry = shadow_alloc_oos_entry(d); ASSERT(shadow_lock_is_acquired(d)); @@ -1174,7 +1174,7 @@ && i == PAGING_L4) continue; /* skip the top-level for 3-level */ - if ( page_out_of_sync(&frame_table[gmfn]) && + if ( page_out_of_sync(pfn_to_page(gmfn)) && !snapshot_entry_matches( d, guest_pt, gpfn, table_offset_64(va, i)) ) { @@ -1200,7 +1200,7 @@ } /* L2 */ - if ( page_out_of_sync(&frame_table[gmfn]) && + if ( page_out_of_sync(pfn_to_page(gmfn)) && !snapshot_entry_matches(d, guest_pt, gpfn, l2_table_offset(va)) ) { unmap_and_return (1); @@ -1214,7 +1214,7 @@ #undef unmap_and_return #endif /* CONFIG_PAGING_LEVELS >= 3 */ { - if ( page_out_of_sync(&frame_table[l2mfn]) && + if ( page_out_of_sync(pfn_to_page(l2mfn)) && !snapshot_entry_matches(d, (guest_l1_pgentry_t *)v->arch.guest_vtable, l2pfn, guest_l2_table_offset(va)) ) return 1; @@ -1234,7 +1234,7 @@ guest_pt = (guest_l1_pgentry_t *) map_domain_page(l1mfn); - if ( page_out_of_sync(&frame_table[l1mfn]) && + if ( page_out_of_sync(pfn_to_page(l1mfn)) && !snapshot_entry_matches( d, guest_pt, l1pfn, guest_l1_table_offset(va)) ) { @@ -1324,18 +1324,18 @@ int i; u32 found = 0; int is_l1_shadow = - ((frame_table[pt_mfn].u.inuse.type_info & PGT_type_mask) == + ((pfn_to_page(pt_mfn)->u.inuse.type_info & PGT_type_mask) == PGT_l1_shadow); #if CONFIG_PAGING_LEVELS == 4 is_l1_shadow |= - ((frame_table[pt_mfn].u.inuse.type_info & PGT_type_mask) == + ((pfn_to_page(pt_mfn)->u.inuse.type_info & PGT_type_mask) == PGT_fl1_shadow); #endif match = l1e_from_pfn(readonly_gmfn, flags); if ( shadow_mode_external(d) ) { - i = (frame_table[readonly_gmfn].u.inuse.type_info & PGT_va_mask) + i = (pfn_to_page(readonly_gmfn)->u.inuse.type_info & PGT_va_mask) >> PGT_va_shift; if ( (i >= 0 && i < L1_PAGETABLE_ENTRIES) && @@ -1373,7 +1373,7 @@ // If it's not a writable page, then no writable refs can be outstanding. // - if ( (frame_table[readonly_gmfn].u.inuse.type_info & PGT_type_mask) != + if ( (pfn_to_page(readonly_gmfn)->u.inuse.type_info & PGT_type_mask) != PGT_writable_page ) { perfc_incrc(remove_write_not_writable); @@ -1383,7 +1383,7 @@ // How many outstanding writable PTEs for this page are there? // write_refs = - (frame_table[readonly_gmfn].u.inuse.type_info & PGT_count_mask); + (pfn_to_page(readonly_gmfn)->u.inuse.type_info & PGT_count_mask); if ( write_refs && MFN_PINNED(readonly_gmfn) ) { write_refs--; @@ -1401,7 +1401,7 @@ // Use the back pointer to locate the shadow page that can contain // the PTE of interest - if ( (predicted_smfn = frame_table[readonly_gmfn].tlbflush_timestamp) ) { + if ( (predicted_smfn = pfn_to_page(readonly_gmfn)->tlbflush_timestamp) ) { found += remove_all_write_access_in_ptpage( d, predicted_smfn, predicted_smfn, readonly_gpfn, readonly_gmfn, write_refs, 0); if ( found == write_refs ) @@ -1670,7 +1670,7 @@ if ( !(entry_get_flags(guest_pt[i]) & _PAGE_PRESENT) && unlikely(entry_get_value(guest_pt[i]) != 0) && !unshadow && - (frame_table[smfn].u.inuse.type_info & PGT_pinned) ) + (pfn_to_page(smfn)->u.inuse.type_info & PGT_pinned) ) unshadow = 1; } #endif @@ -1718,7 +1718,7 @@ if ( !(guest_root_get_flags(new_root_e) & _PAGE_PRESENT) && unlikely(guest_root_get_intpte(new_root_e) != 0) && !unshadow && - (frame_table[smfn].u.inuse.type_info & PGT_pinned) ) + (pfn_to_page(smfn)->u.inuse.type_info & PGT_pinned) ) unshadow = 1; } if ( max == -1 ) @@ -2401,7 +2401,7 @@ { printk("eff_guest_pfn=%lx eff_guest_mfn=%lx shadow_mfn=%lx t=0x%08lx page_table_page=%d\n", eff_guest_pfn, eff_guest_mfn, shadow_mfn, - frame_table[eff_guest_mfn].u.inuse.type_info, + pfn_to_page(eff_guest_mfn)->u.inuse.type_info, page_table_page); FAIL("RW coherence"); } @@ -2412,7 +2412,7 @@ { printk("eff_guest_pfn=%lx eff_guest_mfn=%lx shadow_mfn=%lx t=0x%08lx page_table_page=%d\n", eff_guest_pfn, eff_guest_mfn, shadow_mfn, - frame_table[eff_guest_mfn].u.inuse.type_info, + pfn_to_page(eff_guest_mfn)->u.inuse.type_info, page_table_page); FAIL("RW2 coherence"); } @@ -2781,7 +2781,7 @@ * When we free L2 pages, we need to tell if the page contains * Xen private mappings. Use the va_mask part. */ - frame_table[s2mfn].u.inuse.type_info |= + pfn_to_page(s2mfn)->u.inuse.type_info |= (unsigned long) 3 << PGT_score_shift; memset(spl2e, 0, @@ -2794,7 +2794,7 @@ for ( i = 0; i < PDPT_L2_ENTRIES; i++ ) spl2e[l2_table_offset(PERDOMAIN_VIRT_START) + i] = l2e_from_page( - virt_to_page(page_get_owner(&frame_table[gmfn])->arch.mm_perdomain_pt) + i, + virt_to_page(page_get_owner(pfn_to_page(gmfn))->arch.mm_perdomain_pt) + i, __PAGE_HYPERVISOR); for ( i = 0; i < (LINEARPT_MBYTES >> (L2_PAGETABLE_SHIFT - 20)); i++ ) spl2e[l2_table_offset(LINEAR_PT_VIRT_START) + i] = @@ -2896,7 +2896,7 @@ ROOT_PAGETABLE_XEN_SLOTS * sizeof(l4_pgentry_t)); spl4e[l4_table_offset(PERDOMAIN_VIRT_START)] = - l4e_from_paddr(__pa(page_get_owner(&frame_table[gmfn])->arch.mm_perdomain_l3), + l4e_from_paddr(__pa(page_get_owner(pfn_to_page(gmfn))->arch.mm_perdomain_l3), __PAGE_HYPERVISOR); if ( shadow_mode_translate(d) ) // NB: not external diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/shadow32.c --- a/xen/arch/x86/shadow32.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/shadow32.c Tue Dec 20 17:16:24 2005 @@ -30,7 +30,7 @@ #include <xen/sched.h> #include <xen/trace.h> -#define MFN_PINNED(_x) (frame_table[_x].u.inuse.type_info & PGT_pinned) +#define MFN_PINNED(_x) (pfn_to_page(_x)->u.inuse.type_info & PGT_pinned) #define va_to_l1mfn(_ed, _va) \ (l2e_get_pfn(linear_l2_table(_ed)[_va>>L2_PAGETABLE_SHIFT])) @@ -144,11 +144,11 @@ if ( !shadow_mode_refcounts(d) ) return; - ASSERT(frame_table[gmfn].count_info & PGC_page_table); + ASSERT(pfn_to_page(gmfn)->count_info & PGC_page_table); if ( shadow_max_pgtable_type(d, gpfn, NULL) == PGT_none ) { - clear_bit(_PGC_page_table, &frame_table[gmfn].count_info); + clear_bit(_PGC_page_table, &pfn_to_page(gmfn)->count_info); if ( page_out_of_sync(pfn_to_page(gmfn)) ) { @@ -380,7 +380,7 @@ void free_shadow_page(unsigned long smfn) { - struct pfn_info *page = &frame_table[smfn]; + struct pfn_info *page = pfn_to_page(smfn); unsigned long gmfn = page->u.inuse.type_info & PGT_mfn_mask; struct domain *d = page_get_owner(pfn_to_page(gmfn)); unsigned long gpfn = __mfn_to_gpfn(d, gmfn); @@ -465,8 +465,8 @@ { struct pfn_info *page; - page = &frame_table[entry->gmfn]; - + page = pfn_to_page(entry->gmfn); + // Decrement ref count of guest & shadow pages // put_page(page); @@ -795,7 +795,7 @@ */ mfn = pagetable_get_pfn(v->arch.monitor_table); unmap_domain_page(v->arch.monitor_vtable); - free_domheap_page(&frame_table[mfn]); + free_domheap_page(pfn_to_page(mfn)); v->arch.monitor_table = mk_pagetable(0); v->arch.monitor_vtable = 0; @@ -1018,8 +1018,8 @@ { // external guests provide their own memory for their P2M maps. // - ASSERT( d == page_get_owner( - &frame_table[pagetable_get_pfn(d->arch.phys_table)]) ); + ASSERT(d == page_get_owner(pfn_to_page(pagetable_get_pfn( + d->arch.phys_table)))); } } @@ -1543,7 +1543,7 @@ l2e_from_pfn(smfn, __PAGE_HYPERVISOR); spl2e[l2_table_offset(PERDOMAIN_VIRT_START)] = - l2e_from_paddr(__pa(page_get_owner(&frame_table[gmfn])->arch.mm_perdomain_pt), + l2e_from_paddr(__pa(page_get_owner(pfn_to_page(gmfn))->arch.mm_perdomain_pt), __PAGE_HYPERVISOR); if ( shadow_mode_translate(d) ) // NB: not external @@ -1675,7 +1675,7 @@ set_guest_back_ptr(d, sl1e, sl1mfn, i); } - frame_table[sl1mfn].tlbflush_timestamp = + pfn_to_page(sl1mfn)->tlbflush_timestamp = SHADOW_ENCODE_MIN_MAX(min, max); } } @@ -1758,7 +1758,7 @@ u32 min_max = 0; int min, max, length; - if ( test_and_set_bit(_PGC_out_of_sync, &frame_table[gmfn].count_info) ) + if ( test_and_set_bit(_PGC_out_of_sync, &pfn_to_page(gmfn)->count_info) ) { ASSERT(__shadow_status(d, gpfn, PGT_snapshot)); return SHADOW_SNAPSHOT_ELSEWHERE; @@ -1809,7 +1809,7 @@ // Clear the out_of_sync bit. // - clear_bit(_PGC_out_of_sync, &frame_table[entry->gmfn].count_info); + clear_bit(_PGC_out_of_sync, &pfn_to_page(entry->gmfn)->count_info); // XXX Need to think about how to protect the domain's // information less expensively. @@ -1826,7 +1826,7 @@ unsigned long mfn) { struct domain *d = v->domain; - struct pfn_info *page = &frame_table[mfn]; + struct pfn_info *page = pfn_to_page(mfn); struct out_of_sync_entry *entry = shadow_alloc_oos_entry(d); ASSERT(shadow_lock_is_acquired(d)); @@ -1992,7 +1992,7 @@ perfc_incrc(shadow_out_of_sync_calls); - if ( page_out_of_sync(&frame_table[l2mfn]) && + if ( page_out_of_sync(pfn_to_page(l2mfn)) && !snapshot_entry_matches(d, (l1_pgentry_t *)v->arch.guest_vtable, l2pfn, l2_table_offset(va)) ) return 1; @@ -2008,7 +2008,7 @@ if ( !VALID_MFN(l1mfn) ) return 0; - if ( page_out_of_sync(&frame_table[l1mfn]) && + if ( page_out_of_sync(pfn_to_page(l1mfn)) && !snapshot_entry_matches( d, &linear_pg_table[l1_linear_offset(va) & ~(L1_PAGETABLE_ENTRIES-1)], l1pfn, l1_table_offset(va)) ) @@ -2136,13 +2136,13 @@ int i; u32 found = 0; int is_l1_shadow = - ((frame_table[pt_mfn].u.inuse.type_info & PGT_type_mask) == + ((pfn_to_page(pt_mfn)->u.inuse.type_info & PGT_type_mask) == PGT_l1_shadow); match = l1e_from_pfn(readonly_gmfn, flags); if ( shadow_mode_external(d) ) { - i = (frame_table[readonly_gmfn].u.inuse.type_info & PGT_va_mask) + i = (pfn_to_page(readonly_gmfn)->u.inuse.type_info & PGT_va_mask) >> PGT_va_shift; if ( (i >= 0 && i < L1_PAGETABLE_ENTRIES) && @@ -2180,7 +2180,7 @@ // If it's not a writable page, then no writable refs can be outstanding. // - if ( (frame_table[readonly_gmfn].u.inuse.type_info & PGT_type_mask) != + if ( (pfn_to_page(readonly_gmfn)->u.inuse.type_info & PGT_type_mask) != PGT_writable_page ) { perfc_incrc(remove_write_not_writable); @@ -2190,7 +2190,7 @@ // How many outstanding writable PTEs for this page are there? // write_refs = - (frame_table[readonly_gmfn].u.inuse.type_info & PGT_count_mask); + (pfn_to_page(readonly_gmfn)->u.inuse.type_info & PGT_count_mask); if ( write_refs && MFN_PINNED(readonly_gmfn) ) { write_refs--; @@ -2208,7 +2208,7 @@ // Use the back pointer to locate the shadow page that can contain // the PTE of interest - if ( (predicted_smfn = frame_table[readonly_gmfn].tlbflush_timestamp) ) { + if ( (predicted_smfn = pfn_to_page(readonly_gmfn)->tlbflush_timestamp) ) { found += remove_all_write_access_in_ptpage( d, predicted_smfn, predicted_smfn, readonly_gpfn, readonly_gmfn, write_refs, 0); if ( found == write_refs ) @@ -2249,7 +2249,7 @@ int i; u32 count = 0; int is_l1_shadow = - ((frame_table[l1mfn].u.inuse.type_info & PGT_type_mask) == + ((pfn_to_page(l1mfn)->u.inuse.type_info & PGT_type_mask) == PGT_l1_shadow); match = l1e_from_pfn(forbidden_gmfn, flags); @@ -2266,7 +2266,7 @@ if ( is_l1_shadow ) shadow_put_page_from_l1e(ol2e, d); else /* must be an hl2 page */ - put_page(&frame_table[forbidden_gmfn]); + put_page(pfn_to_page(forbidden_gmfn)); } unmap_domain_page(pl1e); @@ -2982,6 +2982,23 @@ } } +void clear_all_shadow_status(struct domain *d) +{ + shadow_lock(d); + free_shadow_pages(d); + free_shadow_ht_entries(d); + d->arch.shadow_ht = + xmalloc_array(struct shadow_status, shadow_ht_buckets); + if ( d->arch.shadow_ht == NULL ) { + printk("clear all shadow status:xmalloc fail\n"); + domain_crash_synchronous(); + } + memset(d->arch.shadow_ht, 0, + shadow_ht_buckets * sizeof(struct shadow_status)); + + free_out_of_sync_entries(d); + shadow_unlock(d); +} /************************************************************************/ /************************************************************************/ @@ -3139,7 +3156,7 @@ { printk("eff_guest_pfn=%lx eff_guest_mfn=%lx shadow_mfn=%lx t=%lx page_table_page=%d\n", eff_guest_pfn, eff_guest_mfn, shadow_mfn, - frame_table[eff_guest_mfn].u.inuse.type_info, + pfn_to_page(eff_guest_mfn)->u.inuse.type_info, page_table_page); FAIL("RW coherence"); } @@ -3150,7 +3167,7 @@ { printk("eff_guest_pfn=%lx eff_guest_mfn=%lx shadow_mfn=%lx t=%lx page_table_page=%d\n", eff_guest_pfn, eff_guest_mfn, shadow_mfn, - frame_table[eff_guest_mfn].u.inuse.type_info, + pfn_to_page(eff_guest_mfn)->u.inuse.type_info, page_table_page); FAIL("RW2 coherence"); } diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/shadow_public.c --- a/xen/arch/x86/shadow_public.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/shadow_public.c Tue Dec 20 17:16:24 2005 @@ -168,14 +168,14 @@ #if CONFIG_PAGING_LEVELS >=3 if ( d->arch.ops->guest_paging_levels == PAGING_L2 ) { - struct pfn_info *page = &frame_table[smfn]; + struct pfn_info *page = pfn_to_page(smfn); for ( i = 0; i < PDP_ENTRIES; i++ ) { if ( entry_get_flags(ple[i]) & _PAGE_PRESENT ) free_fake_shadow_l2(d,entry_get_pfn(ple[i])); } - page = &frame_table[entry_get_pfn(ple[0])]; + page = pfn_to_page(entry_get_pfn(ple[0])); free_domheap_pages(page, SL2_ORDER); unmap_domain_page(ple); } @@ -208,7 +208,7 @@ break; if ( level == PAGING_L2 ) { - struct pfn_info *page = &frame_table[smfn]; + struct pfn_info *page = pfn_to_page(smfn); if ( is_xen_l2_slot(page->u.inuse.type_info, i) ) continue; } @@ -299,7 +299,7 @@ */ mfn = pagetable_get_pfn(v->arch.monitor_table); unmap_domain_page(v->arch.monitor_vtable); - free_domheap_page(&frame_table[mfn]); + free_domheap_page(pfn_to_page(mfn)); v->arch.monitor_table = mk_pagetable(0); v->arch.monitor_vtable = 0; @@ -394,7 +394,7 @@ */ mfn = pagetable_get_pfn(v->arch.monitor_table); unmap_domain_page(v->arch.monitor_vtable); - free_domheap_page(&frame_table[mfn]); + free_domheap_page(pfn_to_page(mfn)); v->arch.monitor_table = mk_pagetable(0); v->arch.monitor_vtable = 0; @@ -411,7 +411,7 @@ // Clear the out_of_sync bit. // - clear_bit(_PGC_out_of_sync, &frame_table[entry->gmfn].count_info); + clear_bit(_PGC_out_of_sync, &pfn_to_page(entry->gmfn)->count_info); // XXX Need to think about how to protect the domain's // information less expensively. @@ -428,7 +428,7 @@ { struct pfn_info *page; - page = &frame_table[entry->gmfn]; + page = pfn_to_page(entry->gmfn); // Decrement ref count of guest & shadow pages // @@ -501,11 +501,11 @@ if ( !shadow_mode_refcounts(d) ) return; - ASSERT(frame_table[gmfn].count_info & PGC_page_table); + ASSERT(pfn_to_page(gmfn)->count_info & PGC_page_table); if ( shadow_max_pgtable_type(d, gpfn, NULL) == PGT_none ) { - clear_bit(_PGC_page_table, &frame_table[gmfn].count_info); + clear_bit(_PGC_page_table, &pfn_to_page(gmfn)->count_info); if ( page_out_of_sync(pfn_to_page(gmfn)) ) { @@ -600,7 +600,7 @@ void free_shadow_page(unsigned long smfn) { - struct pfn_info *page = &frame_table[smfn]; + struct pfn_info *page = pfn_to_page(smfn); unsigned long gmfn = page->u.inuse.type_info & PGT_mfn_mask; struct domain *d = page_get_owner(pfn_to_page(gmfn)); @@ -1067,8 +1067,8 @@ { // external guests provide their own memory for their P2M maps. // - ASSERT( d == page_get_owner( - &frame_table[pagetable_get_pfn(d->arch.phys_table)]) ); + ASSERT(d == page_get_owner(pfn_to_page(pagetable_get_pfn( + d->arch.phys_table)))); } } @@ -1643,7 +1643,7 @@ int i; u32 count = 0; int is_l1_shadow = - ((frame_table[l1mfn].u.inuse.type_info & PGT_type_mask) == + ((pfn_to_page(l1mfn)->u.inuse.type_info & PGT_type_mask) == PGT_l1_shadow); match = l1e_from_pfn(forbidden_gmfn, flags); @@ -1660,7 +1660,7 @@ if ( is_l1_shadow ) shadow_put_page_from_l1e(ol2e, d); else /* must be an hl2 page */ - put_page(&frame_table[forbidden_gmfn]); + put_page(pfn_to_page(forbidden_gmfn)); } unmap_domain_page(pl1e); @@ -1747,6 +1747,24 @@ shadow_unlock(d); } +void clear_all_shadow_status(struct domain *d) +{ + shadow_lock(d); + free_shadow_pages(d); + free_shadow_ht_entries(d); + d->arch.shadow_ht = + xmalloc_array(struct shadow_status, shadow_ht_buckets); + if ( d->arch.shadow_ht == NULL ) { + printk("clear all shadow status:xmalloc fail\n"); + domain_crash_synchronous(); + } + memset(d->arch.shadow_ht, 0, + shadow_ht_buckets * sizeof(struct shadow_status)); + + free_out_of_sync_entries(d); + shadow_unlock(d); +} + /* * Local variables: * mode: C diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/traps.c --- a/xen/arch/x86/traps.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/traps.c Tue Dec 20 17:16:24 2005 @@ -1074,29 +1074,35 @@ return 0; } -unsigned long nmi_softirq_reason; -static void nmi_softirq(void) + +/* Defer dom0 notification to softirq context (unsafe in NMI context). */ +static unsigned long nmi_dom0_softirq_reason; +#define NMI_DOM0_PARITY_ERR 0 +#define NMI_DOM0_IO_ERR 1 +#define NMI_DOM0_UNKNOWN 2 + +static void nmi_dom0_softirq(void) { if ( dom0 == NULL ) return; - if ( test_and_clear_bit(0, &nmi_softirq_reason) ) + if ( test_and_clear_bit(NMI_DOM0_PARITY_ERR, &nmi_dom0_softirq_reason) ) send_guest_virq(dom0->vcpu[0], VIRQ_PARITY_ERR); - if ( test_and_clear_bit(1, &nmi_softirq_reason) ) + if ( test_and_clear_bit(NMI_DOM0_IO_ERR, &nmi_dom0_softirq_reason) ) send_guest_virq(dom0->vcpu[0], VIRQ_IO_ERR); + + if ( test_and_clear_bit(NMI_DOM0_UNKNOWN, &nmi_dom0_softirq_reason) ) + send_guest_virq(dom0->vcpu[0], VIRQ_NMI); } asmlinkage void mem_parity_error(struct cpu_user_regs *regs) { - /* Clear and disable the parity-error line. */ - outb((inb(0x61)&15)|4,0x61); - switch ( opt_nmi[0] ) { case 'd': /* 'dom0' */ - set_bit(0, &nmi_softirq_reason); - raise_softirq(NMI_SOFTIRQ); + set_bit(NMI_DOM0_PARITY_ERR, &nmi_dom0_softirq_reason); + raise_softirq(NMI_DOM0_SOFTIRQ); case 'i': /* 'ignore' */ break; default: /* 'fatal' */ @@ -1104,18 +1110,19 @@ printk("\n\nNMI - MEMORY ERROR\n"); fatal_trap(TRAP_nmi, regs); } + + outb((inb(0x61) & 0x0f) | 0x04, 0x61); /* clear-and-disable parity check */ + mdelay(1); + outb((inb(0x61) & 0x0b) | 0x00, 0x61); /* enable parity check */ } asmlinkage void io_check_error(struct cpu_user_regs *regs) { - /* Clear and disable the I/O-error line. */ - outb((inb(0x61)&15)|8,0x61); - switch ( opt_nmi[0] ) { case 'd': /* 'dom0' */ - set_bit(0, &nmi_softirq_reason); - raise_softirq(NMI_SOFTIRQ); + set_bit(NMI_DOM0_IO_ERR, &nmi_dom0_softirq_reason); + raise_softirq(NMI_DOM0_SOFTIRQ); case 'i': /* 'ignore' */ break; default: /* 'fatal' */ @@ -1123,43 +1130,59 @@ printk("\n\nNMI - I/O ERROR\n"); fatal_trap(TRAP_nmi, regs); } + + outb((inb(0x61) & 0x0f) | 0x08, 0x61); /* clear-and-disable IOCK */ + mdelay(1); + outb((inb(0x61) & 0x07) | 0x00, 0x61); /* enable IOCK */ } static void unknown_nmi_error(unsigned char reason) { - printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); - printk("Dazed and confused, but trying to continue\n"); - printk("Do you have a strange power saving mode enabled?\n"); -} - -static void default_do_nmi(struct cpu_user_regs *regs, unsigned long reason) -{ - if ( nmi_watchdog ) - nmi_watchdog_tick(regs); - - if ( reason & 0x80 ) - mem_parity_error(regs); - else if ( reason & 0x40 ) - io_check_error(regs); - else if ( !nmi_watchdog ) - unknown_nmi_error((unsigned char)(reason&0xff)); + switch ( opt_nmi[0] ) + { + case 'd': /* 'dom0' */ + set_bit(NMI_DOM0_UNKNOWN, &nmi_dom0_softirq_reason); + raise_softirq(NMI_DOM0_SOFTIRQ); + case 'i': /* 'ignore' */ + break; + default: /* 'fatal' */ + printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); + printk("Dazed and confused, but trying to continue\n"); + printk("Do you have a strange power saving mode enabled?\n"); + } } static int dummy_nmi_callback(struct cpu_user_regs *regs, int cpu) { - return 0; + return 0; } static nmi_callback_t nmi_callback = dummy_nmi_callback; -asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason) +asmlinkage void do_nmi(struct cpu_user_regs *regs) { unsigned int cpu = smp_processor_id(); + unsigned char reason; ++nmi_count(cpu); - if ( !nmi_callback(regs, cpu) ) - default_do_nmi(regs, reason); + if ( nmi_callback(regs, cpu) ) + return; + + if ( nmi_watchdog ) + nmi_watchdog_tick(regs); + + /* Only the BSP gets external NMIs from the system. */ + if ( cpu == 0 ) + { + reason = inb(0x61); + if ( reason & 0x80 ) + mem_parity_error(regs); + else if ( reason & 0x40 ) + io_check_error(regs); + else if ( !nmi_watchdog ) + unknown_nmi_error((unsigned char)(reason&0xff)); + } } void set_nmi_callback(nmi_callback_t callback) @@ -1169,7 +1192,7 @@ void unset_nmi_callback(void) { - nmi_callback = dummy_nmi_callback; + nmi_callback = dummy_nmi_callback; } asmlinkage int math_state_restore(struct cpu_user_regs *regs) @@ -1318,7 +1341,7 @@ cpu_init(); - open_softirq(NMI_SOFTIRQ, nmi_softirq); + open_softirq(NMI_DOM0_SOFTIRQ, nmi_dom0_softirq); } diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/vmx.c --- a/xen/arch/x86/vmx.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/vmx.c Tue Dec 20 17:16:24 2005 @@ -102,7 +102,8 @@ if (v->vcpu_id == 0) { /* unmap IO shared page */ struct domain *d = v->domain; - unmap_domain_page((void *)d->arch.vmx_platform.shared_page_va); + if ( d->arch.vmx_platform.shared_page_va ) + unmap_domain_page((void *)d->arch.vmx_platform.shared_page_va); } destroy_vmcs(&v->arch.arch_vmx); @@ -110,12 +111,12 @@ vpit = &v->domain->arch.vmx_platform.vmx_pit; if ( active_ac_timer(&(vpit->pit_timer)) ) rem_ac_timer(&vpit->pit_timer); - if ( active_ac_timer(&v->arch.arch_vmx.hlt_timer) ) { + if ( active_ac_timer(&v->arch.arch_vmx.hlt_timer) ) rem_ac_timer(&v->arch.arch_vmx.hlt_timer); - } - if ( vmx_apic_support(v->domain) ) { - rem_ac_timer( &(VLAPIC(v)->vlapic_timer) ); - xfree( VLAPIC(v) ); + if ( vmx_apic_support(v->domain) && (VLAPIC(v) != NULL) ) + { + rem_ac_timer(&VLAPIC(v)->vlapic_timer); + xfree(VLAPIC(v)); } } @@ -334,7 +335,7 @@ extern long evtchn_send(int lport); extern long do_block(void); -void do_nmi(struct cpu_user_regs *, unsigned long); +void do_nmi(struct cpu_user_regs *); static int check_vmx_controls(ctrls, msr) { @@ -543,6 +544,13 @@ clear_bit(X86_FEATURE_VMXE & 31, &ecx); clear_bit(X86_FEATURE_MWAIT & 31, &ecx); } +#ifdef __i386__ + else if ( input == 0x80000001 ) + { + /* Mask feature for Intel ia32e or AMD long mode. */ + clear_bit(X86_FEATURE_LM & 31, &edx); + } +#endif regs->eax = (unsigned long) eax; regs->ebx = (unsigned long) ebx; @@ -1223,6 +1231,7 @@ } } + clear_all_shadow_status(v->domain); if (vmx_assist(v, VMX_ASSIST_INVOKE)) { set_bit(VMX_CPU_STATE_ASSIST_ENABLED, &v->arch.arch_vmx.cpu_state); __vmread(GUEST_RIP, &eip); @@ -1841,7 +1850,7 @@ break; } case TRAP_nmi: - do_nmi(®s, 0); + do_nmi(®s); break; default: vmx_reflect_exception(v); diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/vmx_intercept.c --- a/xen/arch/x86/vmx_intercept.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/vmx_intercept.c Tue Dec 20 17:16:24 2005 @@ -203,6 +203,12 @@ u64 nsec_delta = (unsigned int)((NOW() - vpit->inject_point)); if (nsec_delta > vpit->period) VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT:long time has passed from last injection!"); + if(vpit->init_val == 0) + { + printk("PIT init value == 0!\n"); + domain_crash_synchronous(); + } + vpit->count = vpit->init_val - ((nsec_delta * PIT_FREQ / 1000000000ULL) % vpit->init_val ); } diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/x86_32/entry.S --- a/xen/arch/x86/x86_32/entry.S Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/x86_32/entry.S Tue Dec 20 17:16:24 2005 @@ -601,15 +601,7 @@ pushl %eax SAVE_ALL_NOSEGREGS(a) - # Check for hardware problems. - inb $0x61,%al - testb $0x80,%al - jne nmi_parity_err - testb $0x40,%al - jne nmi_io_err - movl %eax,%ebx - - # Okay, its almost a normal NMI tick. We can only process it if: + # We can only process the NMI if: # A. We are the outermost Xen activation (in which case we have # the selectors safely saved on our stack) # B. DS and ES contain sane Xen values. @@ -619,7 +611,7 @@ movl UREGS_eflags(%esp),%eax movb UREGS_cs(%esp),%al testl $(3|X86_EFLAGS_VM),%eax - jnz do_watchdog_tick + jnz continue_nmi movl %ds,%eax cmpw $(__HYPERVISOR_DS),%ax jne defer_nmi @@ -627,15 +619,14 @@ cmpw $(__HYPERVISOR_DS),%ax jne defer_nmi -do_watchdog_tick: +continue_nmi: movl $(__HYPERVISOR_DS),%edx movl %edx,%ds movl %edx,%es movl %esp,%edx - pushl %ebx # reason - pushl %edx # regs + pushl %edx call do_nmi - addl $8,%esp + addl $4,%esp jmp ret_from_intr defer_nmi: @@ -648,55 +639,6 @@ movl $(APIC_DM_FIXED | APIC_DEST_SELF | APIC_DEST_LOGICAL | \ TRAP_deferred_nmi),%ss:APIC_ICR(%eax) jmp restore_all_xen - -nmi_parity_err: - # Clear and disable the parity-error line - andb $0xf,%al - orb $0x4,%al - outb %al,$0x61 - cmpb $'i',%ss:opt_nmi # nmi=ignore - je nmi_out - bts $0,%ss:nmi_softirq_reason - bts $NMI_SOFTIRQ,%ss:irq_stat - cmpb $'d',%ss:opt_nmi # nmi=dom0 - je nmi_out - movl $(__HYPERVISOR_DS),%edx # nmi=fatal - movl %edx,%ds - movl %edx,%es - movl %esp,%edx - push %edx - call mem_parity_error - addl $4,%esp -nmi_out:movl %ss:UREGS_eflags(%esp),%eax - movb %ss:UREGS_cs(%esp),%al - testl $(3|X86_EFLAGS_VM),%eax - jz restore_all_xen - movl $(__HYPERVISOR_DS),%edx - movl %edx,%ds - movl %edx,%es - GET_CURRENT(%ebx) - jmp test_all_events - -nmi_io_err: - # Clear and disable the I/O-error line - andb $0xf,%al - orb $0x8,%al - outb %al,$0x61 - cmpb $'i',%ss:opt_nmi # nmi=ignore - je nmi_out - bts $1,%ss:nmi_softirq_reason - bts $NMI_SOFTIRQ,%ss:irq_stat - cmpb $'d',%ss:opt_nmi # nmi=dom0 - je nmi_out - movl $(__HYPERVISOR_DS),%edx # nmi=fatal - movl %edx,%ds - movl %edx,%es - movl %esp,%edx - push %edx - call io_check_error - addl $4,%esp - jmp nmi_out - ENTRY(setup_vm86_frame) # Copies the entire stack frame forwards by 16 bytes. diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/x86_32/mm.c --- a/xen/arch/x86/x86_32/mm.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/x86_32/mm.c Tue Dec 20 17:16:24 2005 @@ -177,10 +177,11 @@ idle_pg_table_l2[l2_linear_offset(RDWR_MPT_VIRT_START) + i]); for ( j = 0; j < L2_PAGETABLE_ENTRIES; j++ ) { - frame_table[m2p_start_mfn+j].count_info = PGC_allocated | 1; + struct pfn_info *page = pfn_to_page(m2p_start_mfn + j); + page->count_info = PGC_allocated | 1; /* Ensure it's only mapped read-only by domains. */ - frame_table[m2p_start_mfn+j].u.inuse.type_info = PGT_gdt_page | 1; - page_set_owner(&frame_table[m2p_start_mfn+j], dom_xen); + page->u.inuse.type_info = PGT_gdt_page | 1; + page_set_owner(page, dom_xen); } } } diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/x86_32/traps.c --- a/xen/arch/x86/x86_32/traps.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/x86_32/traps.c Tue Dec 20 17:16:24 2005 @@ -160,9 +160,9 @@ BUILD_SMP_INTERRUPT(deferred_nmi, TRAP_deferred_nmi) asmlinkage void smp_deferred_nmi(struct cpu_user_regs regs) { - asmlinkage void do_nmi(struct cpu_user_regs *, unsigned long); + asmlinkage void do_nmi(struct cpu_user_regs *); ack_APIC_irq(); - do_nmi(®s, 0); + do_nmi(®s); } void __init percpu_traps_init(void) diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/x86_64/entry.S --- a/xen/arch/x86/x86_64/entry.S Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/x86_64/entry.S Tue Dec 20 17:16:24 2005 @@ -567,9 +567,7 @@ ENTRY(nmi) pushq $0 SAVE_ALL - inb $0x61,%al - movl %eax,%esi # reason - movq %rsp,%rdi # regs + movq %rsp,%rdi call do_nmi jmp restore_all_xen diff -r 11cd619db035 -r d3b10a2a82d4 xen/arch/x86/x86_64/mm.c --- a/xen/arch/x86/x86_64/mm.c Tue Dec 20 17:16:15 2005 +++ b/xen/arch/x86/x86_64/mm.c Tue Dec 20 17:16:24 2005 @@ -166,11 +166,12 @@ for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) { - frame_table[m2p_start_mfn+i].count_info = PGC_allocated | 1; + struct pfn_info *page = pfn_to_page(m2p_start_mfn + i); + page->count_info = PGC_allocated | 1; /* gdt to make sure it's only mapped read-only by non-privileged domains. */ - frame_table[m2p_start_mfn+i].u.inuse.type_info = PGT_gdt_page | 1; - page_set_owner(&frame_table[m2p_start_mfn+i], dom_xen); + page->u.inuse.type_info = PGT_gdt_page | 1; + page_set_owner(page, dom_xen); } } } diff -r 11cd619db035 -r d3b10a2a82d4 xen/common/dom0_ops.c --- a/xen/common/dom0_ops.c Tue Dec 20 17:16:15 2005 +++ b/xen/common/dom0_ops.c Tue Dec 20 17:16:24 2005 @@ -358,12 +358,17 @@ case DOM0_GETDOMAININFO: { struct domain *d; + domid_t dom; + + dom = op->u.getdomaininfo.domain; + if ( dom == DOMID_SELF ) + dom = current->domain->domain_id; read_lock(&domlist_lock); for_each_domain ( d ) { - if ( d->domain_id >= op->u.getdomaininfo.domain ) + if ( d->domain_id >= dom ) break; } @@ -577,6 +582,22 @@ } } break; + case DOM0_SETDEBUGGING: + { + struct domain *d; + ret = -ESRCH; + d = find_domain_by_id(op->u.setdebugging.domain); + if ( d != NULL ) + { + if ( op->u.setdebugging.enable ) + set_bit(_DOMF_debugging, &d->domain_flags); + else + clear_bit(_DOMF_debugging, &d->domain_flags); + put_domain(d); + ret = 0; + } + } + break; #ifdef PERF_COUNTERS case DOM0_PERFCCONTROL: diff -r 11cd619db035 -r d3b10a2a82d4 xen/common/grant_table.c --- a/xen/common/grant_table.c Tue Dec 20 17:16:15 2005 +++ b/xen/common/grant_table.c Tue Dec 20 17:16:24 2005 @@ -238,8 +238,8 @@ if ( unlikely(!pfn_valid(frame)) || unlikely(!((dev_hst_ro_flags & GNTMAP_readonly) ? - get_page(&frame_table[frame], rd) : - get_page_and_type(&frame_table[frame], rd, + get_page(pfn_to_page(frame), rd) : + get_page_and_type(pfn_to_page(frame), rd, PGT_writable_page))) ) { clear_bit(_GTF_writing, &sha->flags); @@ -301,7 +301,7 @@ sflags = prev_sflags; } - if ( unlikely(!get_page_type(&frame_table[frame], + if ( unlikely(!get_page_type(pfn_to_page(frame), PGT_writable_page)) ) { clear_bit(_GTF_writing, &sha->flags); @@ -347,14 +347,14 @@ if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 ) { clear_bit(_GTF_writing, &sha->flags); - put_page_type(&frame_table[frame]); + put_page_type(pfn_to_page(frame)); } } if ( act->pin == 0 ) { clear_bit(_GTF_reading, &sha->flags); - put_page(&frame_table[frame]); + put_page(pfn_to_page(frame)); } spin_unlock(&rd->grant_table->lock); @@ -500,14 +500,14 @@ !(flags & GNTMAP_readonly) ) { clear_bit(_GTF_writing, &sha->flags); - put_page_type(&frame_table[frame]); + put_page_type(pfn_to_page(frame)); } if ( act->pin == 0 ) { act->frame = 0xdeadbeef; clear_bit(_GTF_reading, &sha->flags); - put_page(&frame_table[frame]); + put_page(pfn_to_page(frame)); } unmap_out: @@ -691,7 +691,7 @@ } /* Check the passed page frame for basic validity. */ - page = &frame_table[gop.mfn]; + page = pfn_to_page(gop.mfn); if ( unlikely(!pfn_valid(gop.mfn) || IS_XEN_HEAP_FRAME(page)) ) { DPRINTK("gnttab_transfer: out-of-range or xen frame %lx\n", @@ -1016,14 +1016,14 @@ if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 ) { clear_bit(_GTF_writing, &sha->flags); - put_page_type(&frame_table[act->frame]); + put_page_type(pfn_to_page(act->frame)); } } if ( act->pin == 0 ) { clear_bit(_GTF_reading, &sha->flags); - put_page(&frame_table[act->frame]); + put_page(pfn_to_page(act->frame)); } spin_unlock(&rd->grant_table->lock); diff -r 11cd619db035 -r d3b10a2a82d4 xen/common/memory.c --- a/xen/common/memory.c Tue Dec 20 17:16:15 2005 +++ b/xen/common/memory.c Tue Dec 20 17:16:24 2005 @@ -102,7 +102,7 @@ return i; } - page = &frame_table[mpfn + j]; + page = pfn_to_page(mpfn + j); if ( unlikely(!get_page(page, d)) ) { DPRINTK("Bad page free for domain %u\n", d->domain_id); diff -r 11cd619db035 -r d3b10a2a82d4 xen/include/asm-x86/debugger.h --- a/xen/include/asm-x86/debugger.h Tue Dec 20 17:16:15 2005 +++ b/xen/include/asm-x86/debugger.h Tue Dec 20 17:16:24 2005 @@ -30,6 +30,8 @@ #ifndef __X86_DEBUGGER_H__ #define __X86_DEBUGGER_H__ +#include <xen/sched.h> +#include <asm/regs.h> #include <asm/processor.h> /* The main trap handlers use these helper macros which include early bail. */ @@ -41,9 +43,10 @@ #if defined(CRASH_DEBUG) extern int __trap_to_cdb(struct cpu_user_regs *r); -#define debugger_trap_entry(_v, _r) (0) -static inline int debugger_trap_fatal( +#define __debugger_trap_entry(_v, _r) (0) + +static inline int __debugger_trap_fatal( unsigned int vector, struct cpu_user_regs *regs) { (void)__trap_to_cdb(regs); @@ -51,60 +54,52 @@ } /* Int3 is a trivial way to gather cpu_user_regs context. */ -#define debugger_trap_immediate() __asm__ __volatile__ ( "int3" ); +#define __debugger_trap_immediate() __asm__ __volatile__ ( "int3" ); -#elif defined(DOMU_DEBUG) +#elif 0 -#include <xen/sched.h> -#include <asm/regs.h> +extern int kdb_trap(int, int, struct cpu_user_regs *); + +static inline int __debugger_trap_entry( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +static inline int __debugger_trap_fatal( + unsigned int vector, struct cpu_user_regs *regs) +{ + return kdb_trap(vector, 0, regs); +} + +/* Int3 is a trivial way to gather cpu_user_regs context. */ +#define __debugger_trap_immediate() __asm__ __volatile__ ( "int3" ) + +#else + +#define __debugger_trap_entry(_v, _r) (0) +#define __debugger_trap_fatal(_v, _r) (0) +#define __debugger_trap_immediate() ((void)0) + +#endif static inline int debugger_trap_entry( unsigned int vector, struct cpu_user_regs *regs) { struct vcpu *v = current; - if ( !KERNEL_MODE(v, regs) || (v->domain->domain_id == 0) ) - return 0; - - switch ( vector ) + if ( KERNEL_MODE(v, regs) && + test_bit(_DOMF_debugging, &v->domain->domain_flags) && + ((vector == TRAP_int3) || (vector == TRAP_debug)) ) { - case TRAP_int3: - case TRAP_debug: domain_pause_for_debugger(); return 1; } - return 0; + return __debugger_trap_entry(vector, regs); } -#define debugger_trap_fatal(_v, _r) (0) -#define debugger_trap_immediate() - -#elif 0 - -extern int kdb_trap(int, int, struct cpu_user_regs *); - -static inline int debugger_trap_entry( - unsigned int vector, struct cpu_user_regs *regs) -{ - return 0; -} - -static inline int debugger_trap_fatal( - unsigned int vector, struct cpu_user_regs *regs) -{ - return kdb_trap(vector, 0, regs); -} - -/* Int3 is a trivial way to gather cpu_user_regs context. */ -#define debugger_trap_immediate() __asm__ __volatile__ ( "int3" ); - -#else - -#define debugger_trap_entry(_v, _r) (0) -#define debugger_trap_fatal(_v, _r) (0) -#define debugger_trap_immediate() - -#endif +#define debugger_trap_fatal(v, r) (__debugger_trap_fatal(v, r)) +#define debugger_trap_immediate() (__debugger_trap_immediate()) #endif /* __X86_DEBUGGER_H__ */ diff -r 11cd619db035 -r d3b10a2a82d4 xen/include/asm-x86/shadow.h --- a/xen/include/asm-x86/shadow.h Tue Dec 20 17:16:15 2005 +++ b/xen/include/asm-x86/shadow.h Tue Dec 20 17:16:24 2005 @@ -493,9 +493,9 @@ SH_VLOG("mark_dirty OOR! mfn=%x pfn=%lx max=%x (dom %p)", mfn, pfn, d->arch.shadow_dirty_bitmap_size, d); SH_VLOG("dom=%p caf=%08x taf=%" PRtype_info, - page_get_owner(&frame_table[mfn]), - frame_table[mfn].count_info, - frame_table[mfn].u.inuse.type_info ); + page_get_owner(pfn_to_page(mfn)), + pfn_to_page(mfn)->count_info, + pfn_to_page(mfn)->u.inuse.type_info ); } #endif } @@ -648,20 +648,20 @@ ASSERT(pfn_valid(smfn)); - x = frame_table[smfn].count_info; + x = pfn_to_page(smfn)->count_info; nx = x + 1; if ( unlikely(nx == 0) ) { printk("get_shadow_ref overflow, gmfn=%" PRtype_info " smfn=%lx\n", - frame_table[smfn].u.inuse.type_info & PGT_mfn_mask, + pfn_to_page(smfn)->u.inuse.type_info & PGT_mfn_mask, smfn); BUG(); } // Guarded by the shadow lock... // - frame_table[smfn].count_info = nx; + pfn_to_page(smfn)->count_info = nx; return 1; } @@ -678,7 +678,7 @@ ASSERT(pfn_valid(smfn)); - x = frame_table[smfn].count_info; + x = pfn_to_page(smfn)->count_info; nx = x - 1; if ( unlikely(x == 0) ) @@ -686,14 +686,14 @@ printk("put_shadow_ref underflow, smfn=%lx oc=%08x t=%" PRtype_info "\n", smfn, - frame_table[smfn].count_info, - frame_table[smfn].u.inuse.type_info); + pfn_to_page(smfn)->count_info, + pfn_to_page(smfn)->u.inuse.type_info); BUG(); } // Guarded by the shadow lock... // - frame_table[smfn].count_info = nx; + pfn_to_page(smfn)->count_info = nx; if ( unlikely(nx == 0) ) { @@ -704,9 +704,9 @@ static inline void shadow_pin(unsigned long smfn) { - ASSERT( !(frame_table[smfn].u.inuse.type_info & PGT_pinned) ); - - frame_table[smfn].u.inuse.type_info |= PGT_pinned; + ASSERT( !(pfn_to_page(smfn)->u.inuse.type_info & PGT_pinned) ); + + pfn_to_page(smfn)->u.inuse.type_info |= PGT_pinned; if ( unlikely(!get_shadow_ref(smfn)) ) BUG(); } @@ -714,9 +714,9 @@ static inline void shadow_unpin(unsigned long smfn) { - ASSERT( (frame_table[smfn].u.inuse.type_info & PGT_pinned) ); - - frame_table[smfn].u.inuse.type_info &= ~PGT_pinned; + ASSERT( (pfn_to_page(smfn)->u.inuse.type_info & PGT_pinned) ); + + pfn_to_page(smfn)->u.inuse.type_info &= ~PGT_pinned; put_shadow_ref(smfn); } @@ -732,9 +732,9 @@ ASSERT(shadow_lock_is_acquired(d)); gmfn = l1e_get_pfn(spte); - frame_table[gmfn].tlbflush_timestamp = smfn; - frame_table[gmfn].u.inuse.type_info &= ~PGT_va_mask; - frame_table[gmfn].u.inuse.type_info |= (unsigned long) index << PGT_va_shift; + pfn_to_page(gmfn)->tlbflush_timestamp = smfn; + pfn_to_page(gmfn)->u.inuse.type_info &= ~PGT_va_mask; + pfn_to_page(gmfn)->u.inuse.type_info |= (unsigned long) index << PGT_va_shift; } } @@ -941,7 +941,7 @@ // perfc_incrc(validate_pte_changes2); if ( likely(l1e_get_flags(new_spte) & _PAGE_PRESENT) ) - shadow_put_page_type(d, &frame_table[l1e_get_pfn(new_spte)]); + shadow_put_page_type(d, pfn_to_page(l1e_get_pfn(new_spte))); } else if ( ((l1e_get_flags(old_spte) | l1e_get_flags(new_spte)) & _PAGE_PRESENT ) && @@ -1216,8 +1216,8 @@ printk("d->id=%d gpfn=%lx gmfn=%lx stype=%lx c=%x t=%" PRtype_info " " "mfn_out_of_sync(gmfn)=%d mfn_is_page_table(gmfn)=%d\n", d->domain_id, gpfn, gmfn, stype, - frame_table[gmfn].count_info, - frame_table[gmfn].u.inuse.type_info, + pfn_to_page(gmfn)->count_info, + pfn_to_page(gmfn)->u.inuse.type_info, mfn_out_of_sync(gmfn), mfn_is_page_table(gmfn)); BUG(); } @@ -1597,7 +1597,7 @@ struct vcpu *v = current; struct domain *d = v->domain; unsigned long mfn = __gpfn_to_mfn(d, gpfn); - u32 type = frame_table[mfn].u.inuse.type_info & PGT_type_mask; + u32 type = pfn_to_page(mfn)->u.inuse.type_info & PGT_type_mask; if ( shadow_mode_refcounts(d) && (type == PGT_writable_page) ) @@ -1707,6 +1707,8 @@ } } +void clear_all_shadow_status(struct domain *d); + #if SHADOW_DEBUG extern int _check_pagetable(struct vcpu *v, char *s); extern int _check_all_pagetables(struct vcpu *v, char *s); diff -r 11cd619db035 -r d3b10a2a82d4 xen/include/asm-x86/shadow_public.h --- a/xen/include/asm-x86/shadow_public.h Tue Dec 20 17:16:15 2005 +++ b/xen/include/asm-x86/shadow_public.h Tue Dec 20 17:16:24 2005 @@ -22,7 +22,7 @@ #ifndef _XEN_SHADOW_PUBLIC_H #define _XEN_SHADOW_PUBLIC_H #if CONFIG_PAGING_LEVELS >= 3 -#define MFN_PINNED(_x) (frame_table[_x].u.inuse.type_info & PGT_pinned) +#define MFN_PINNED(_x) (pfn_to_page(_x)->u.inuse.type_info & PGT_pinned) extern int alloc_p2m_table(struct domain *d); diff -r 11cd619db035 -r d3b10a2a82d4 xen/include/public/acm.h --- a/xen/include/public/acm.h Tue Dec 20 17:16:15 2005 +++ b/xen/include/public/acm.h Tue Dec 20 17:16:24 2005 @@ -1,25 +1,8 @@ -/**************************************************************** - * acm.h - * - * Copyright (C) 2005 IBM Corporation +/* + * acm.h: Xen access control module interface defintions * - * Author: * Reiner Sailer <sailer@xxxxxxxxxxxxxx> - * - * Contributors: - * Stefan Berger <stefanb@xxxxxxxxxxxxxx> - * added network byte order support for binary policies - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * sHype general access control module header file. - * here are all definitions that are shared between - * xen-core, guest-kernels, and applications. - * - * todo: move from static policy choice to compile option. + * Copyright (c) 2005, International Business Machines Corporation. */ #ifndef _XEN_PUBLIC_ACM_H diff -r 11cd619db035 -r d3b10a2a82d4 xen/include/public/acm_ops.h --- a/xen/include/public/acm_ops.h Tue Dec 20 17:16:15 2005 +++ b/xen/include/public/acm_ops.h Tue Dec 20 17:16:24 2005 @@ -1,19 +1,8 @@ -/****************************************************************************** - * acm_ops.h +/* + * acm_ops.h: Xen access control module hypervisor commands * - * Copyright (C) 2005 IBM Corporation - * - * Author: * Reiner Sailer <sailer@xxxxxxxxxxxxxx> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * Process acm policy command requests from guest OS. - * access checked by policy; not restricted to DOM0 - * + * Copyright (c) 2005, International Business Machines Corporation. */ #ifndef __XEN_PUBLIC_ACM_OPS_H__ diff -r 11cd619db035 -r d3b10a2a82d4 xen/include/public/dom0_ops.h --- a/xen/include/public/dom0_ops.h Tue Dec 20 17:16:15 2005 +++ b/xen/include/public/dom0_ops.h Tue Dec 20 17:16:24 2005 @@ -403,6 +403,12 @@ domid_t domain; xen_domain_handle_t handle; } dom0_setdomainhandle_t; + +#define DOM0_SETDEBUGGING 45 +typedef struct { + domid_t domain; + uint8_t enable; +} dom0_setdebugging_t; typedef struct { uint32_t cmd; @@ -440,7 +446,8 @@ dom0_platform_quirk_t platform_quirk; dom0_physical_memory_map_t physical_memory_map; dom0_max_vcpus_t max_vcpus; - dom0_setdomainhandle_t setdomainhandle; + dom0_setdomainhandle_t setdomainhandle; + dom0_setdebugging_t setdebugging; uint8_t pad[128]; } u; } dom0_op_t; diff -r 11cd619db035 -r d3b10a2a82d4 xen/include/public/vmx_assist.h --- a/xen/include/public/vmx_assist.h Tue Dec 20 17:16:15 2005 +++ b/xen/include/public/vmx_assist.h Tue Dec 20 17:16:24 2005 @@ -3,21 +3,8 @@ * * Leendert van Doorn, leendert@xxxxxxxxxxxxxx * Copyright (c) 2005, International Business Machines Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - * */ + #ifndef _VMX_ASSIST_H_ #define _VMX_ASSIST_H_ diff -r 11cd619db035 -r d3b10a2a82d4 xen/include/public/xen.h --- a/xen/include/public/xen.h Tue Dec 20 17:16:15 2005 +++ b/xen/include/public/xen.h Tue Dec 20 17:16:24 2005 @@ -67,12 +67,13 @@ */ #define VIRQ_TIMER 0 /* Timebase update, and/or requested timeout. */ #define VIRQ_DEBUG 1 /* Request guest to dump debug info. */ -#define VIRQ_CONSOLE 2 /* (DOM0) bytes received on emergency console. */ +#define VIRQ_CONSOLE 2 /* (DOM0) Bytes received on emergency console. */ #define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */ -#define VIRQ_PARITY_ERR 4 /* (DOM0) NMI parity error. */ -#define VIRQ_IO_ERR 5 /* (DOM0) NMI I/O error. */ +#define VIRQ_PARITY_ERR 4 /* (DOM0) NMI parity error (port 0x61, bit 7). */ +#define VIRQ_IO_ERR 5 /* (DOM0) NMI I/O error (port 0x61, bit 6). */ #define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */ -#define NR_VIRQS 7 +#define VIRQ_NMI 7 /* (DOM0) Unknown NMI (not from ISA port 0x61).*/ +#define NR_VIRQS 8 /* * MMU-UPDATE REQUESTS diff -r 11cd619db035 -r d3b10a2a82d4 xen/include/xen/sched.h --- a/xen/include/xen/sched.h Tue Dec 20 17:16:15 2005 +++ b/xen/include/xen/sched.h Tue Dec 20 17:16:24 2005 @@ -393,6 +393,10 @@ /* Domain is paused by controller software. */ #define _DOMF_ctrl_pause 6 #define DOMF_ctrl_pause (1UL<<_DOMF_ctrl_pause) + /* Domain is being debugged by controller software. */ +#define _DOMF_debugging 7 +#define DOMF_debugging (1UL<<_DOMF_debugging) + static inline int domain_runnable(struct vcpu *v) { diff -r 11cd619db035 -r d3b10a2a82d4 xen/include/xen/softirq.h --- a/xen/include/xen/softirq.h Tue Dec 20 17:16:15 2005 +++ b/xen/include/xen/softirq.h Tue Dec 20 17:16:24 2005 @@ -6,7 +6,7 @@ #define SCHEDULE_SOFTIRQ 1 #define NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ 2 #define KEYPRESS_SOFTIRQ 3 -#define NMI_SOFTIRQ 4 +#define NMI_DOM0_SOFTIRQ 4 #define PAGE_SCRUB_SOFTIRQ 5 #define DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ 6 #define NR_SOFTIRQS 7 diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/audio/audio.c --- /dev/null Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/audio/audio.c Tue Dec 20 17:16:24 2005 @@ -0,0 +1,910 @@ +/* + * QEMU Audio subsystem + * + * Copyright (c) 2003-2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include <assert.h> +#include "vl.h" + +#define USE_WAV_AUDIO + +#include "audio/audio_int.h" + +#define dolog(...) AUD_log ("audio", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif + +#define QC_AUDIO_DRV "QEMU_AUDIO_DRV" +#define QC_VOICES "QEMU_VOICES" +#define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT" +#define QC_FIXED_FREQ "QEMU_FIXED_FREQ" + +static HWVoice *hw_voices; + +AudioState audio_state = { + 1, /* use fixed settings */ + 44100, /* fixed frequency */ + 2, /* fixed channels */ + AUD_FMT_S16, /* fixed format */ + 1, /* number of hw voices */ + -1 /* voice size */ +}; + +/* http://www.df.lth.se/~john_e/gems/gem002d.html */ +/* http://www.multi-platforms.com/Tips/PopCount.htm */ +uint32_t popcount (uint32_t u) +{ + u = ((u&0x55555555) + ((u>>1)&0x55555555)); + u = ((u&0x33333333) + ((u>>2)&0x33333333)); + u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); + u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); + u = ( u&0x0000ffff) + (u>>16); + return u; +} + +inline uint32_t lsbindex (uint32_t u) +{ + return popcount ((u&-u)-1); +} + +int audio_get_conf_int (const char *key, int defval) +{ + int val = defval; + char *strval; + + strval = getenv (key); + if (strval) { + val = atoi (strval); + } + + return val; +} + +const char *audio_get_conf_str (const char *key, const char *defval) +{ + const char *val = getenv (key); + if (!val) + return defval; + else + return val; +} + +void AUD_log (const char *cap, const char *fmt, ...) +{ + va_list ap; + fprintf (stderr, "%s: ", cap); + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); +} + +/* + * Soft Voice + */ +void pcm_sw_free_resources (SWVoice *sw) +{ + if (sw->buf) qemu_free (sw->buf); + if (sw->rate) st_rate_stop (sw->rate); + sw->buf = NULL; + sw->rate = NULL; +} + +int pcm_sw_alloc_resources (SWVoice *sw) +{ + sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t)); + if (!sw->buf) + return -1; + + sw->rate = st_rate_start (sw->freq, sw->hw->freq); + if (!sw->rate) { + qemu_free (sw->buf); + sw->buf = NULL; + return -1; + } + return 0; +} + +void pcm_sw_fini (SWVoice *sw) +{ + pcm_sw_free_resources (sw); +} + +int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq, + int nchannels, audfmt_e fmt) +{ + int bits = 8, sign = 0; + + switch (fmt) { + case AUD_FMT_S8: + sign = 1; + case AUD_FMT_U8: + break; + + case AUD_FMT_S16: + sign = 1; + case AUD_FMT_U16: + bits = 16; + break; + } + + sw->hw = hw; + sw->freq = freq; + sw->fmt = fmt; + sw->nchannels = nchannels; + sw->shift = (nchannels == 2) + (bits == 16); + sw->align = (1 << sw->shift) - 1; + sw->left = 0; + sw->pos = 0; + sw->wpos = 0; + sw->live = 0; + sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq; + sw->bytes_per_second = sw->freq << sw->shift; + sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16]; + + pcm_sw_free_resources (sw); + return pcm_sw_alloc_resources (sw); +} + +/* Hard voice */ +void pcm_hw_free_resources (HWVoice *hw) +{ + if (hw->mix_buf) + qemu_free (hw->mix_buf); + hw->mix_buf = NULL; +} + +int pcm_hw_alloc_resources (HWVoice *hw) +{ + hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t)); + if (!hw->mix_buf) + return -1; + return 0; +} + +void pcm_hw_fini (HWVoice *hw) +{ + if (hw->active) { + ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt); + pcm_hw_free_resources (hw); + hw->pcm_ops->fini (hw); + memset (hw, 0, audio_state.drv->voice_size); + } +} + +void pcm_hw_gc (HWVoice *hw) +{ + if (hw->nb_voices) + return; + + pcm_hw_fini (hw); +} + +int pcm_hw_get_live (HWVoice *hw) +{ + int i, alive = 0, live = hw->samples; + + for (i = 0; i < hw->nb_voices; i++) { + if (hw->pvoice[i]->live) { + live = audio_MIN (hw->pvoice[i]->live, live); + alive += 1; + } + } + + if (alive) + return live; + else + return -1; +} + +int pcm_hw_get_live2 (HWVoice *hw, int *nb_active) +{ + int i, alive = 0, live = hw->samples; + + *nb_active = 0; + for (i = 0; i < hw->nb_voices; i++) { + if (hw->pvoice[i]->live) { + if (hw->pvoice[i]->live < live) { + *nb_active = hw->pvoice[i]->active != 0; + live = hw->pvoice[i]->live; + } + alive += 1; + } + } + + if (alive) + return live; + else + return -1; +} + +void pcm_hw_dec_live (HWVoice *hw, int decr) +{ + int i; + + for (i = 0; i < hw->nb_voices; i++) { + if (hw->pvoice[i]->live) { + hw->pvoice[i]->live -= decr; + } + } +} + +void pcm_hw_clear (HWVoice *hw, void *buf, int len) +{ + if (!len) + return; + + switch (hw->fmt) { + case AUD_FMT_S16: + case AUD_FMT_S8: + memset (buf, len << hw->shift, 0x00); + break; + + case AUD_FMT_U8: + memset (buf, len << hw->shift, 0x80); + break; + + case AUD_FMT_U16: + { + unsigned int i; + uint16_t *p = buf; + int shift = hw->nchannels - 1; + + for (i = 0; i < len << shift; i++) { + p[i] = INT16_MAX; + } + } + break; + } +} + +int pcm_hw_write (SWVoice *sw, void *buf, int size) +{ + int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck; + int ret = 0, pos = 0; + if (!sw) + return size; + + hwsamples = sw->hw->samples; + samples = size >> sw->shift; + + if (!sw->live) { + sw->wpos = sw->hw->rpos; + } + wpos = sw->wpos; + live = sw->live; + dead = hwsamples - live; + swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio; + swlim = audio_MIN (swlim, samples); + + ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n", + size, live, dead, swlim, wpos); + if (swlim) + sw->conv (sw->buf, buf, swlim); + + while (swlim) { + dead = hwsamples - live; + left = hwsamples - wpos; + blck = audio_MIN (dead, left); + if (!blck) { + /* dolog ("swlim=%d\n", swlim); */ + break; + } + isamp = swlim; + osamp = blck; + st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp); + ret += isamp; + swlim -= isamp; + pos += isamp; + live += osamp; + wpos = (wpos + osamp) % hwsamples; + } + + sw->wpos = wpos; + sw->live = live; + return ret << sw->shift; +} + +int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +{ + int sign = 0, bits = 8; + + pcm_hw_fini (hw); + ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt); + if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) { + memset (hw, 0, audio_state.drv->voice_size); + return -1; + } + + switch (hw->fmt) { + case AUD_FMT_S8: + sign = 1; + case AUD_FMT_U8: + break; + + case AUD_FMT_S16: + sign = 1; + case AUD_FMT_U16: + bits = 16; + break; + } + + hw->nb_voices = 0; + hw->active = 1; + hw->shift = (hw->nchannels == 2) + (bits == 16); + hw->bytes_per_second = hw->freq << hw->shift; + hw->align = (1 << hw->shift) - 1; + hw->samples = hw->bufsize >> hw->shift; + hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16]; + if (pcm_hw_alloc_resources (hw)) { + pcm_hw_fini (hw); + return -1; + } + return 0; +} + +static int dist (void *hw) +{ + if (hw) { + return (((uint8_t *) hw - (uint8_t *) hw_voices) + / audio_state.voice_size) + 1; + } + else { + return 0; + } +} + +#define ADVANCE(hw) hw ? advance (hw, audio_state.voice_size) : hw_voices + +HWVoice *pcm_hw_find_any (HWVoice *hw) +{ + int i = dist (hw); + for (; i < audio_state.nb_hw_voices; i++) { + hw = ADVANCE (hw); + return hw; + } + return NULL; +} + +HWVoice *pcm_hw_find_any_active (HWVoice *hw) +{ + int i = dist (hw); + for (; i < audio_state.nb_hw_voices; i++) { + hw = ADVANCE (hw); + if (hw->active) + return hw; + } + return NULL; +} + +HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw) +{ + int i = dist (hw); + for (; i < audio_state.nb_hw_voices; i++) { + hw = ADVANCE (hw); + if (hw->active && hw->enabled) + return hw; + } + return NULL; +} + +HWVoice *pcm_hw_find_any_passive (HWVoice *hw) +{ + int i = dist (hw); + for (; i < audio_state.nb_hw_voices; i++) { + hw = ADVANCE (hw); + if (!hw->active) + return hw; + } + return NULL; +} + +HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq, + int nchannels, audfmt_e fmt) +{ + while ((hw = pcm_hw_find_any_active (hw))) { + if (hw->freq == freq && + hw->nchannels == nchannels && + hw->fmt == fmt) + return hw; + } + return NULL; +} + +HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt) +{ + HWVoice *hw; + + if (audio_state.fixed_format) { + freq = audio_state.fixed_freq; + nchannels = audio_state.fixed_channels; + fmt = audio_state.fixed_fmt; + } + + hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt); + + if (hw) + return hw; + + hw = pcm_hw_find_any_passive (NULL); + if (hw) { + hw->pcm_ops = audio_state.drv->pcm_ops; + if (!hw->pcm_ops) + return NULL; + + if (pcm_hw_init (hw, freq, nchannels, fmt)) { + pcm_hw_gc (hw); + return NULL; + } + else + return hw; + } + + return pcm_hw_find_any (NULL); +} + +int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw) +{ + SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw)); + if (!pvoice) + return -1; + + memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw)); + qemu_free (hw->pvoice); + hw->pvoice = pvoice; + hw->pvoice[hw->nb_voices++] = sw; + return 0; +} + +int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw) +{ + int i, j; + if (hw->nb_voices > 1) { + SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw)); + + if (!pvoice) { + dolog ("Can not maintain consistent state (not enough memory)\n"); + return -1; + } + + for (i = 0, j = 0; i < hw->nb_voices; i++) { + if (j >= hw->nb_voices - 1) { + dolog ("Can not maintain consistent state " + "(invariant violated)\n"); + return -1; + } + if (hw->pvoice[i] != sw) + pvoice[j++] = hw->pvoice[i]; + } + qemu_free (hw->pvoice); + hw->pvoice = pvoice; + hw->nb_voices -= 1; + } + else { + qemu_free (hw->pvoice); + hw->pvoice = NULL; + hw->nb_voices = 0; + } + return 0; +} + +SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt) +{ + SWVoice *sw; + HWVoice *hw; + + sw = qemu_mallocz (sizeof (*sw)); + if (!sw) + goto err1; + + hw = pcm_hw_add (freq, nchannels, fmt); + if (!hw) + goto err2; + + if (pcm_hw_add_sw (hw, sw)) + goto err3; + + if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) + goto err4; + + return sw; + +err4: + pcm_hw_del_sw (hw, sw); +err3: + pcm_hw_gc (hw); +err2: + qemu_free (sw); +err1: + return NULL; +} + +SWVoice *AUD_open (SWVoice *sw, const char *name, + int freq, int nchannels, audfmt_e fmt) +{ + if (!audio_state.drv) { + return NULL; + } + + if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) { + return sw; + } + + if (sw) { + ldebug ("Different format %s %d %d %d\n", + name, + sw->freq == freq, + sw->nchannels == nchannels, + sw->fmt == fmt); + } + + if (nchannels != 1 && nchannels != 2) { + dolog ("Bogus channel count %d for voice %s\n", nchannels, name); + return NULL; + } + + if (!audio_state.fixed_format && sw) { + pcm_sw_fini (sw); + pcm_hw_del_sw (sw->hw, sw); + pcm_hw_gc (sw->hw); + if (sw->name) { + qemu_free (sw->name); + sw->name = NULL; + } + qemu_free (sw); + sw = NULL; + } + + if (sw) { + HWVoice *hw = sw->hw; + if (!hw) { + dolog ("Internal logic error voice %s has no hardware store\n", + name); + return sw; + } + + if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) { + pcm_sw_fini (sw); + pcm_hw_del_sw (hw, sw); + pcm_hw_gc (hw); + if (sw->name) { + qemu_free (sw->name); + sw->name = NULL; + } + qemu_free (sw); + return NULL; + } + } + else { + sw = pcm_create_voice_pair (freq, nchannels, fmt); + if (!sw) { + dolog ("Failed to create voice %s\n", name); + return NULL; + } + } + + if (sw->name) { + qemu_free (sw->name); + sw->name = NULL; + } + sw->name = qemu_strdup (name); + return sw; +} + +void AUD_close (SWVoice *sw) +{ + if (!sw) + return; + + pcm_sw_fini (sw); + pcm_hw_del_sw (sw->hw, sw); + pcm_hw_gc (sw->hw); + if (sw->name) { + qemu_free (sw->name); + sw->name = NULL; + } + qemu_free (sw); +} + +int AUD_write (SWVoice *sw, void *buf, int size) +{ + int bytes; + + if (!sw->hw->enabled) + dolog ("Writing to disabled voice %s\n", sw->name); + bytes = sw->hw->pcm_ops->write (sw, buf, size); + return bytes; +} + +void AUD_run (void) +{ + HWVoice *hw = NULL; + + while ((hw = pcm_hw_find_any_active_enabled (hw))) { + int i; + if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) { + hw->enabled = 0; + hw->pcm_ops->ctl (hw, VOICE_DISABLE); + for (i = 0; i < hw->nb_voices; i++) { + hw->pvoice[i]->live = 0; + /* hw->pvoice[i]->old_ticks = 0; */ + } + continue; + } + + hw->pcm_ops->run (hw); + assert (hw->rpos < hw->samples); + for (i = 0; i < hw->nb_voices; i++) { + SWVoice *sw = hw->pvoice[i]; + if (!sw->active && !sw->live && sw->old_ticks) { + int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks; + if (delta > audio_state.ticks_threshold) { + ldebug ("resetting old_ticks for %s\n", sw->name); + sw->old_ticks = 0; + } + } + } + } +} + +int AUD_get_free (SWVoice *sw) +{ + int free; + + if (!sw) + return 4096; + + free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio + / INT_MAX; + + free &= ~sw->hw->align; + if (!free) return 0; + + return free; +} + +int AUD_get_buffer_size (SWVoice *sw) +{ + return sw->hw->bufsize; +} + +void AUD_adjust (SWVoice *sw, int bytes) +{ + if (!sw) + return; + sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second; +} + +void AUD_reset (SWVoice *sw) +{ + sw->active = 0; + sw->old_ticks = 0; +} + +int AUD_calc_elapsed (SWVoice *sw) +{ + int64_t now, delta, bytes; + int dead, swlim; + + if (!sw) + return 0; + + now = qemu_get_clock (vm_clock); + delta = now - sw->old_ticks; + bytes = (delta * sw->bytes_per_second) / ticks_per_sec; + if (delta < 0) { + dolog ("whoops delta(<0)=%lld\n", delta); + return 0; + } + + dead = sw->hw->samples - sw->live; + swlim = ((dead * (int64_t) INT_MAX) / sw->ratio); + + if (bytes > swlim) { + return swlim; + } + else { + return bytes; + } +} + +void AUD_enable (SWVoice *sw, int on) +{ + int i; + HWVoice *hw; + + if (!sw) + return; + + hw = sw->hw; + if (on) { + if (!sw->live) + sw->wpos = sw->hw->rpos; + if (!sw->old_ticks) { + sw->old_ticks = qemu_get_clock (vm_clock); + } + } + + if (sw->active != on) { + if (on) { + hw->pending_disable = 0; + if (!hw->enabled) { + hw->enabled = 1; + for (i = 0; i < hw->nb_voices; i++) { + ldebug ("resetting voice\n"); + sw = hw->pvoice[i]; + sw->old_ticks = qemu_get_clock (vm_clock); + } + hw->pcm_ops->ctl (hw, VOICE_ENABLE); + } + } + else { + if (hw->enabled && !hw->pending_disable) { + int nb_active = 0; + for (i = 0; i < hw->nb_voices; i++) { + nb_active += hw->pvoice[i]->active != 0; + } + + if (nb_active == 1) { + hw->pending_disable = 1; + } + } + } + sw->active = on; + } +} + +static struct audio_output_driver *drvtab[] = { +#ifdef CONFIG_OSS + &oss_output_driver, +#endif +#ifdef CONFIG_FMOD + &fmod_output_driver, +#endif +#ifdef CONFIG_SDL + &sdl_output_driver, +#endif + &no_output_driver, +#ifdef USE_WAV_AUDIO + &wav_output_driver, +#endif +}; + +static int voice_init (struct audio_output_driver *drv) +{ + audio_state.opaque = drv->init (); + if (audio_state.opaque) { + if (audio_state.nb_hw_voices > drv->max_voices) { + dolog ("`%s' does not support %d multiple hardware channels\n" + "Resetting to %d\n", + drv->name, audio_state.nb_hw_voices, drv->max_voices); + audio_state.nb_hw_voices = drv->max_voices; + } + hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size); + if (hw_voices) { + audio_state.drv = drv; + return 1; + } + else { + dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n", + audio_state.nb_hw_voices, drv->name, drv->voice_size); + drv->fini (audio_state.opaque); + return 0; + } + } + else { + dolog ("Could not init `%s' audio\n", drv->name); + return 0; + } +} + +static void audio_vm_stop_handler (void *opaque, int reason) +{ + HWVoice *hw = NULL; + + while ((hw = pcm_hw_find_any (hw))) { + if (!hw->pcm_ops) + continue; + + hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE); + } +} + +static void audio_atexit (void) +{ + HWVoice *hw = NULL; + + while ((hw = pcm_hw_find_any (hw))) { + if (!hw->pcm_ops) + continue; + + hw->pcm_ops->ctl (hw, VOICE_DISABLE); + hw->pcm_ops->fini (hw); + } + audio_state.drv->fini (audio_state.opaque); +} + +static void audio_save (QEMUFile *f, void *opaque) +{ +} + +static int audio_load (QEMUFile *f, void *opaque, int version_id) +{ + if (version_id != 1) + return -EINVAL; + + return 0; +} + +void AUD_init (void) +{ + int i; + int done = 0; + const char *drvname; + + audio_state.fixed_format = + !!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format); + audio_state.fixed_freq = + audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq); + audio_state.nb_hw_voices = + audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices); + + if (audio_state.nb_hw_voices <= 0) { + dolog ("Bogus number of voices %d, resetting to 1\n", + audio_state.nb_hw_voices); + } + + drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL); + if (drvname) { + int found = 0; + for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { + if (!strcmp (drvname, drvtab[i]->name)) { + done = voice_init (drvtab[i]); + found = 1; + break; + } + } + if (!found) { + dolog ("Unknown audio driver `%s'\n", drvname); + } + } + + qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL); + atexit (audio_atexit); + + if (!done) { + for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { + if (drvtab[i]->can_be_default) + done = voice_init (drvtab[i]); + } + } + + audio_state.ticks_threshold = ticks_per_sec / 50; + audio_state.freq_threshold = 100; + + register_savevm ("audio", 0, 1, audio_save, audio_load, NULL); + if (!done) { + dolog ("Can not initialize audio subsystem\n"); + voice_init (&no_output_driver); + } +} diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/audio/audio.h --- /dev/null Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/audio/audio.h Tue Dec 20 17:16:24 2005 @@ -0,0 +1,65 @@ +/* + * QEMU Audio subsystem header + * + * Copyright (c) 2003-2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_AUDIO_H +#define QEMU_AUDIO_H + +#include "mixeng.h" + +typedef enum { + AUD_FMT_U8, + AUD_FMT_S8, + AUD_FMT_U16, + AUD_FMT_S16 +} audfmt_e; + +typedef struct SWVoice SWVoice; + +SWVoice * AUD_open (SWVoice *sw, const char *name, int freq, + int nchannels, audfmt_e fmt); +void AUD_init (void); +void AUD_log (const char *cap, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3)));; +void AUD_close (SWVoice *sw); +int AUD_write (SWVoice *sw, void *pcm_buf, int size); +void AUD_adjust (SWVoice *sw, int leftover); +void AUD_reset (SWVoice *sw); +int AUD_get_free (SWVoice *sw); +int AUD_get_buffer_size (SWVoice *sw); +void AUD_run (void); +void AUD_enable (SWVoice *sw, int on); +int AUD_calc_elapsed (SWVoice *sw); + +static inline void *advance (void *p, int incr) +{ + uint8_t *d = p; + return (d + incr); +} + +uint32_t popcount (uint32_t u); +inline uint32_t lsbindex (uint32_t u); + +#define audio_MIN(a, b) ((a)>(b)?(b):(a)) +#define audio_MAX(a, b) ((a)<(b)?(b):(a)) + +#endif /* audio.h */ diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/audio/audio_int.h --- /dev/null Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/audio/audio_int.h Tue Dec 20 17:16:24 2005 @@ -0,0 +1,164 @@ +/* + * QEMU Audio subsystem header + * + * Copyright (c) 2003-2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_AUDIO_INT_H +#define QEMU_AUDIO_INT_H + +#include "vl.h" + +struct pcm_ops; + +typedef struct HWVoice { + int active; + int enabled; + int pending_disable; + int valid; + int freq; + + f_sample *clip; + audfmt_e fmt; + int nchannels; + + int align; + int shift; + + int rpos; + int bufsize; + + int bytes_per_second; + st_sample_t *mix_buf; + + int samples; + int64_t old_ticks; + int nb_voices; + struct SWVoice **pvoice; + struct pcm_ops *pcm_ops; +} HWVoice; + +extern struct pcm_ops no_pcm_ops; +extern struct audio_output_driver no_output_driver; + +extern struct pcm_ops oss_pcm_ops; +extern struct audio_output_driver oss_output_driver; + +extern struct pcm_ops sdl_pcm_ops; +extern struct audio_output_driver sdl_output_driver; + +extern struct pcm_ops wav_pcm_ops; +extern struct audio_output_driver wav_output_driver; + +extern struct pcm_ops fmod_pcm_ops; +extern struct audio_output_driver fmod_output_driver; + +struct audio_output_driver { + const char *name; + void *(*init) (void); + void (*fini) (void *); + struct pcm_ops *pcm_ops; + int can_be_default; + int max_voices; + int voice_size; +}; + +typedef struct AudioState { + int fixed_format; + int fixed_freq; + int fixed_channels; + int fixed_fmt; + int nb_hw_voices; + int voice_size; + int64_t ticks_threshold; + int freq_threshold; + void *opaque; + struct audio_output_driver *drv; +} AudioState; +extern AudioState audio_state; + +struct SWVoice { + int freq; + audfmt_e fmt; + int nchannels; + + int shift; + int align; + + t_sample *conv; + + int left; + int pos; + int bytes_per_second; + int64_t ratio; + st_sample_t *buf; + void *rate; + + int wpos; + int live; + int active; + int64_t old_ticks; + HWVoice *hw; + char *name; +}; + +struct pcm_ops { + int (*init) (HWVoice *hw, int freq, int nchannels, audfmt_e fmt); + void (*fini) (HWVoice *hw); + void (*run) (HWVoice *hw); + int (*write) (SWVoice *sw, void *buf, int size); + int (*ctl) (HWVoice *hw, int cmd, ...); +}; + +void pcm_sw_free_resources (SWVoice *sw); +int pcm_sw_alloc_resources (SWVoice *sw); +void pcm_sw_fini (SWVoice *sw); +int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq, + int nchannels, audfmt_e fmt); + +void pcm_hw_clear (HWVoice *hw, void *buf, int len); +HWVoice * pcm_hw_find_any (HWVoice *hw); +HWVoice * pcm_hw_find_any_active (HWVoice *hw); +HWVoice * pcm_hw_find_any_passive (HWVoice *hw); +HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq, + int nchannels, audfmt_e fmt); +HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt); +int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw); +int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw); +SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt); + +void pcm_hw_free_resources (HWVoice *hw); +int pcm_hw_alloc_resources (HWVoice *hw); +void pcm_hw_fini (HWVoice *hw); +void pcm_hw_gc (HWVoice *hw); +int pcm_hw_get_live (HWVoice *hw); +int pcm_hw_get_live2 (HWVoice *hw, int *nb_active); +void pcm_hw_dec_live (HWVoice *hw, int decr); +int pcm_hw_write (SWVoice *sw, void *buf, int len); + +int audio_get_conf_int (const char *key, int defval); +const char *audio_get_conf_str (const char *key, const char *defval); + +struct audio_output_driver; + +#define VOICE_ENABLE 1 +#define VOICE_DISABLE 2 + +#endif /* audio_int.h */ diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/audio/mixeng.c --- /dev/null Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/audio/mixeng.c Tue Dec 20 17:16:24 2005 @@ -0,0 +1,255 @@ +/* + * QEMU Mixing engine + * + * Copyright (c) 2004 Vassili Karpov (malc) + * Copyright (c) 1998 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +//#define DEBUG_FP +#include "audio/mixeng.h" + +#define IN_T int8_t +#define IN_MIN CHAR_MIN +#define IN_MAX CHAR_MAX +#define SIGNED +#include "mixeng_template.h" +#undef SIGNED +#undef IN_MAX +#undef IN_MIN +#undef IN_T + +#define IN_T uint8_t +#define IN_MIN 0 +#define IN_MAX UCHAR_MAX +#include "mixeng_template.h" +#undef IN_MAX +#undef IN_MIN +#undef IN_T + +#define IN_T int16_t +#define IN_MIN SHRT_MIN +#define IN_MAX SHRT_MAX +#define SIGNED +#include "mixeng_template.h" +#undef SIGNED +#undef IN_MAX +#undef IN_MIN +#undef IN_T + +#define IN_T uint16_t +#define IN_MIN 0 +#define IN_MAX USHRT_MAX +#include "mixeng_template.h" +#undef IN_MAX +#undef IN_MIN +#undef IN_T + +t_sample *mixeng_conv[2][2][2] = { + { + { + conv_uint8_t_to_mono, + conv_uint16_t_to_mono + }, + { + conv_int8_t_to_mono, + conv_int16_t_to_mono + } + }, + { + { + conv_uint8_t_to_stereo, + conv_uint16_t_to_stereo + }, + { + conv_int8_t_to_stereo, + conv_int16_t_to_stereo + } + } +}; + +f_sample *mixeng_clip[2][2][2] = { + { + { + clip_uint8_t_from_mono, + clip_uint16_t_from_mono + }, + { + clip_int8_t_from_mono, + clip_int16_t_from_mono + } + }, + { + { + clip_uint8_t_from_stereo, + clip_uint16_t_from_stereo + }, + { + clip_int8_t_from_stereo, + clip_int16_t_from_stereo + } + } +}; + +/* + * August 21, 1998 + * Copyright 1998 Fabrice Bellard. + * + * [Rewrote completly the code of Lance Norskog And Sundry + * Contributors with a more efficient algorithm.] + * + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Lance Norskog And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +/* + * Sound Tools rate change effect file. + */ +/* + * Linear Interpolation. + * + * The use of fractional increment allows us to use no buffer. It + * avoid the problems at the end of the buffer we had with the old + * method which stored a possibly big buffer of size + * lcm(in_rate,out_rate). + * + * Limited to 16 bit samples and sampling frequency <= 65535 Hz. If + * the input & output frequencies are equal, a delay of one sample is + * introduced. Limited to processing 32-bit count worth of samples. + * + * 1 << FRAC_BITS evaluating to zero in several places. Changed with + * an (unsigned long) cast to make it safe. MarkMLl 2/1/99 + */ + +/* Private data */ +typedef struct ratestuff { + uint64_t opos; + uint64_t opos_inc; + uint32_t ipos; /* position in the input stream (integer) */ + st_sample_t ilast; /* last sample in the input stream */ +} *rate_t; + +/* + * Prepare processing. + */ +void *st_rate_start (int inrate, int outrate) +{ + rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff)); + + if (!rate) { + exit (EXIT_FAILURE); + } + + if (inrate == outrate) { + // exit (EXIT_FAILURE); + } + + if (inrate >= 65535 || outrate >= 65535) { + // exit (EXIT_FAILURE); + } + + rate->opos = 0; + + /* increment */ + rate->opos_inc = (inrate * ((int64_t) UINT_MAX)) / outrate; + + rate->ipos = 0; + rate->ilast.l = 0; + rate->ilast.r = 0; + return rate; +} + +/* + * Processed signed long samples from ibuf to obuf. + * Return number of samples processed. + */ +void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, + int *isamp, int *osamp) +{ + rate_t rate = (rate_t) opaque; + st_sample_t *istart, *iend; + st_sample_t *ostart, *oend; + st_sample_t ilast, icur, out; + int64_t t; + + ilast = rate->ilast; + + istart = ibuf; + iend = ibuf + *isamp; + + ostart = obuf; + oend = obuf + *osamp; + + if (rate->opos_inc == 1ULL << 32) { + int i, n = *isamp > *osamp ? *osamp : *isamp; + for (i = 0; i < n; i++) { + obuf[i].l += ibuf[i].r; + obuf[i].r += ibuf[i].r; + } + *isamp = n; + *osamp = n; + return; + } + + while (obuf < oend) { + + /* Safety catch to make sure we have input samples. */ + if (ibuf >= iend) + break; + + /* read as many input samples so that ipos > opos */ + + while (rate->ipos <= (rate->opos >> 32)) { + ilast = *ibuf++; + rate->ipos++; + /* See if we finished the input buffer yet */ + if (ibuf >= iend) goto the_end; + } + + icur = *ibuf; + + /* interpolate */ + t = rate->opos & 0xffffffff; + out.l = (ilast.l * (INT_MAX - t) + icur.l * t) / INT_MAX; + out.r = (ilast.r * (INT_MAX - t) + icur.r * t) / INT_MAX; + + /* output sample & increment position */ +#if 0 + *obuf++ = out; +#else + obuf->l += out.l; + obuf->r += out.r; + obuf += 1; +#endif + rate->opos += rate->opos_inc; + } + +the_end: + *isamp = ibuf - istart; + *osamp = obuf - ostart; + rate->ilast = ilast; +} + +void st_rate_stop (void *opaque) +{ + qemu_free (opaque); +} diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/audio/mixeng.h --- /dev/null Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/audio/mixeng.h Tue Dec 20 17:16:24 2005 @@ -0,0 +1,39 @@ +/* + * QEMU Mixing engine header + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_MIXENG_H +#define QEMU_MIXENG_H + +typedef void (t_sample) (void *dst, const void *src, int samples); +typedef void (f_sample) (void *dst, const void *src, int samples); +typedef struct { int64_t l; int64_t r; } st_sample_t; + +extern t_sample *mixeng_conv[2][2][2]; +extern f_sample *mixeng_clip[2][2][2]; + +void *st_rate_start (int inrate, int outrate); +void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, + int *isamp, int *osamp); +void st_rate_stop (void *opaque); + +#endif /* mixeng.h */ diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/audio/mixeng_template.h --- /dev/null Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/audio/mixeng_template.h Tue Dec 20 17:16:24 2005 @@ -0,0 +1,111 @@ +/* + * QEMU Mixing engine + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* + * Tusen tack till Mike Nordell + * dec++'ified by Dscho + */ + +#ifdef SIGNED +#define HALFT IN_MAX +#define HALF IN_MAX +#else +#define HALFT ((IN_MAX)>>1) +#define HALF HALFT +#endif + +static int64_t inline glue(conv_,IN_T) (IN_T v) +{ +#ifdef SIGNED + return (INT_MAX*(int64_t)v)/HALF; +#else + return (INT_MAX*((int64_t)v-HALFT))/HALF; +#endif +} + +static IN_T inline glue(clip_,IN_T) (int64_t v) +{ + if (v >= INT_MAX) + return IN_MAX; + else if (v < -INT_MAX) + return IN_MIN; + +#ifdef SIGNED + return (IN_T) (v*HALF/INT_MAX); +#else + return (IN_T) (v+INT_MAX/2)*HALF/INT_MAX; +#endif +} + +static void glue(glue(conv_,IN_T),_to_stereo) (void *dst, const void *src, + int samples) +{ + st_sample_t *out = (st_sample_t *) dst; + IN_T *in = (IN_T *) src; + while (samples--) { + out->l = glue(conv_,IN_T) (*in++); + out->r = glue(conv_,IN_T) (*in++); + out += 1; + } +} + +static void glue(glue(conv_,IN_T),_to_mono) (void *dst, const void *src, + int samples) +{ + st_sample_t *out = (st_sample_t *) dst; + IN_T *in = (IN_T *) src; + while (samples--) { + out->l = glue(conv_,IN_T) (in[0]); + out->r = out->l; + out += 1; + in += 1; + } +} + +static void glue(glue(clip_,IN_T),_from_stereo) (void *dst, const void *src, + int samples) +{ + st_sample_t *in = (st_sample_t *) src; + IN_T *out = (IN_T *) dst; + while (samples--) { + *out++ = glue(clip_,IN_T) (in->l); + *out++ = glue(clip_,IN_T) (in->r); + in += 1; + } +} + +static void glue(glue(clip_,IN_T),_from_mono) (void *dst, const void *src, + int samples) +{ + st_sample_t *in = (st_sample_t *) src; + IN_T *out = (IN_T *) dst; + while (samples--) { + *out++ = glue(clip_,IN_T) (in->l + in->r); + in += 1; + } +} + +#undef HALF +#undef HALFT + diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/audio/noaudio.c --- /dev/null Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/audio/noaudio.c Tue Dec 20 17:16:24 2005 @@ -0,0 +1,130 @@ +/* + * QEMU NULL audio output driver + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#include "audio/audio_int.h" + +typedef struct NoVoice { + HWVoice hw; + int64_t old_ticks; +} NoVoice; + +#define dolog(...) AUD_log ("noaudio", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif + +static void no_hw_run (HWVoice *hw) +{ + NoVoice *no = (NoVoice *) hw; + int rpos, live, decr, samples; + uint8_t *dst; + st_sample_t *src; + int64_t now = qemu_get_clock (vm_clock); + int64_t ticks = now - no->old_ticks; + int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec; + + if (bytes > INT_MAX) + samples = INT_MAX >> hw->shift; + else + samples = bytes >> hw->shift; + + live = pcm_hw_get_live (hw); + if (live <= 0) + return; + + no->old_ticks = now; + decr = audio_MIN (live, samples); + samples = decr; + rpos = hw->rpos; + while (samples) { + int left_till_end_samples = hw->samples - rpos; + int convert_samples = audio_MIN (samples, left_till_end_samples); + + src = advance (hw->mix_buf, rpos * sizeof (st_sample_t)); + memset (src, 0, convert_samples * sizeof (st_sample_t)); + + rpos = (rpos + convert_samples) % hw->samples; + samples -= convert_samples; + } + + pcm_hw_dec_live (hw, decr); + hw->rpos = rpos; +} + +static int no_hw_write (SWVoice *sw, void *buf, int len) +{ + return pcm_hw_write (sw, buf, len); +} + +static int no_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +{ + NoVoice *no = (NoVoice *) hw; + hw->freq = freq; + hw->nchannels = nchannels; + hw->fmt = fmt; + hw->bufsize = 4096; + return 0; +} + +static void no_hw_fini (HWVoice *hw) +{ + (void) hw; +} + +static int no_hw_ctl (HWVoice *hw, int cmd, ...) +{ + (void) hw; + (void) cmd; + return 0; +} + +static void *no_audio_init (void) +{ + return &no_audio_init; +} + +static void no_audio_fini (void *opaque) +{ +} + +struct pcm_ops no_pcm_ops = { + no_hw_init, + no_hw_fini, + no_hw_run, + no_hw_write, + no_hw_ctl +}; + +struct audio_output_driver no_output_driver = { + "none", + no_audio_init, + no_audio_fini, + &no_pcm_ops, + 1, + 1, + sizeof (NoVoice) +}; diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/audio/ossaudio.c --- /dev/null Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/audio/ossaudio.c Tue Dec 20 17:16:24 2005 @@ -0,0 +1,475 @@ +/* + * QEMU OSS audio output driver + * + * Copyright (c) 2003-2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/soundcard.h> +#include <assert.h> +#include "vl.h" + +#include "audio/audio_int.h" + +typedef struct OSSVoice { + HWVoice hw; + void *pcm_buf; + int fd; + int nfrags; + int fragsize; + int mmapped; + int old_optr; +} OSSVoice; + +#define dolog(...) AUD_log ("oss", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif + +#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE" +#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS" +#define QC_OSS_MMAP "QEMU_OSS_MMAP" +#define QC_OSS_DEV "QEMU_OSS_DEV" + +#define errstr() strerror (errno) + +static struct { + int try_mmap; + int nfrags; + int fragsize; + const char *dspname; +} conf = { + .try_mmap = 0, + .nfrags = 4, + .fragsize = 4096, + .dspname = "/dev/dsp" +}; + +struct oss_params { + int freq; + audfmt_e fmt; + int nchannels; + int nfrags; + int fragsize; +}; + +static int oss_hw_write (SWVoice *sw, void *buf, int len) +{ + return pcm_hw_write (sw, buf, len); +} + +static int AUD_to_ossfmt (audfmt_e fmt) +{ + switch (fmt) { + case AUD_FMT_S8: return AFMT_S8; + case AUD_FMT_U8: return AFMT_U8; + case AUD_FMT_S16: return AFMT_S16_LE; + case AUD_FMT_U16: return AFMT_U16_LE; + default: + dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt); + exit (EXIT_FAILURE); + } +} + +static int oss_to_audfmt (int fmt) +{ + switch (fmt) { + case AFMT_S8: return AUD_FMT_S8; + case AFMT_U8: return AUD_FMT_U8; + case AFMT_S16_LE: return AUD_FMT_S16; + case AFMT_U16_LE: return AUD_FMT_U16; + default: + dolog ("Internal logic error: Unrecognized OSS audio format %d\n" + "Aborting\n", + fmt); + exit (EXIT_FAILURE); + } +} + +#ifdef DEBUG_PCM +static void oss_dump_pcm_info (struct oss_params *req, struct oss_params *obt) +{ + dolog ("parameter | requested value | obtained value\n"); + dolog ("format | %10d | %10d\n", req->fmt, obt->fmt); + dolog ("channels | %10d | %10d\n", req->nchannels, obt->nchannels); + dolog ("frequency | %10d | %10d\n", req->freq, obt->freq); + dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags); + dolog ("fragsize | %10d | %10d\n", req->fragsize, obt->fragsize); +} +#endif + +static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd) +{ + int fd; + int mmmmssss; + audio_buf_info abinfo; + int fmt, freq, nchannels; + const char *dspname = conf.dspname; + + fd = open (dspname, O_RDWR | O_NONBLOCK); + if (-1 == fd) { + dolog ("Could not initialize audio hardware. Failed to open `%s':\n" + "Reason:%s\n", + dspname, + errstr ()); + return -1; + } + + freq = req->freq; + nchannels = req->nchannels; + fmt = req->fmt; + + if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) { + dolog ("Could not initialize audio hardware\n" + "Failed to set sample size\n" + "Reason: %s\n", + errstr ()); + goto err; + } + + if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) { + dolog ("Could not initialize audio hardware\n" + "Failed to set number of channels\n" + "Reason: %s\n", + errstr ()); + goto err; + } + + if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) { + dolog ("Could not initialize audio hardware\n" + "Failed to set frequency\n" + "Reason: %s\n", + errstr ()); + goto err; + } + + if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) { + dolog ("Could not initialize audio hardware\n" + "Failed to set non-blocking mode\n" + "Reason: %s\n", + errstr ()); + goto err; + } + + mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize); + if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) { + dolog ("Could not initialize audio hardware\n" + "Failed to set buffer length (%d, %d)\n" + "Reason:%s\n", + conf.nfrags, conf.fragsize, + errstr ()); + goto err; + } + + if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &abinfo)) { + dolog ("Could not initialize audio hardware\n" + "Failed to get buffer length\n" + "Reason:%s\n", + errstr ()); + goto err; + } + + obt->fmt = fmt; + obt->nchannels = nchannels; + obt->freq = freq; + obt->nfrags = abinfo.fragstotal; + obt->fragsize = abinfo.fragsize; + *pfd = fd; + + if ((req->fmt != obt->fmt) || + (req->nchannels != obt->nchannels) || + (req->freq != obt->freq) || + (req->fragsize != obt->fragsize) || + (req->nfrags != obt->nfrags)) { +#ifdef DEBUG_PCM + dolog ("Audio parameters mismatch\n"); + oss_dump_pcm_info (req, obt); +#endif + } + +#ifdef DEBUG_PCM + oss_dump_pcm_info (req, obt); +#endif + return 0; + +err: + close (fd); + return -1; +} + +static void oss_hw_run (HWVoice *hw) +{ + OSSVoice *oss = (OSSVoice *) hw; + int err, rpos, live, decr; + int samples; + uint8_t *dst; + st_sample_t *src; + struct audio_buf_info abinfo; + struct count_info cntinfo; + + live = pcm_hw_get_live (hw); + if (live <= 0) + return; + + if (oss->mmapped) { + int bytes; + + err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo); + if (err < 0) { + dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ()); + return; + } + + if (cntinfo.ptr == oss->old_optr) { + if (abs (hw->samples - live) < 64) + dolog ("overrun\n"); + return; + } + + if (cntinfo.ptr > oss->old_optr) { + bytes = cntinfo.ptr - oss->old_optr; + } + else { + bytes = hw->bufsize + cntinfo.ptr - oss->old_optr; + } + + decr = audio_MIN (bytes >> hw->shift, live); + } + else { + err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo); + if (err < 0) { + dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ()); + return; + } + + decr = audio_MIN (abinfo.bytes >> hw->shift, live); + if (decr <= 0) + return; + } + + samples = decr; + rpos = hw->rpos; + while (samples) { + int left_till_end_samples = hw->samples - rpos; + int convert_samples = audio_MIN (samples, left_till_end_samples); + + src = advance (hw->mix_buf, rpos * sizeof (st_sample_t)); + dst = advance (oss->pcm_buf, rpos << hw->shift); + + hw->clip (dst, src, convert_samples); + if (!oss->mmapped) { + int written; + + written = write (oss->fd, dst, convert_samples << hw->shift); + /* XXX: follow errno recommendations ? */ + if (written == -1) { + dolog ("Failed to write audio\nReason: %s\n", errstr ()); + continue; + } + + if (written != convert_samples << hw->shift) { + int wsamples = written >> hw->shift; + int wbytes = wsamples << hw->shift; + if (wbytes != written) { + dolog ("Unaligned write %d, %d\n", wbytes, written); + } + memset (src, 0, wbytes); + decr -= samples; + rpos = (rpos + wsamples) % hw->samples; + break; + } + } + memset (src, 0, convert_samples * sizeof (st_sample_t)); + + rpos = (rpos + convert_samples) % hw->samples; + samples -= convert_samples; + } + if (oss->mmapped) { + oss->old_optr = cntinfo.ptr; + } + + pcm_hw_dec_live (hw, decr); + hw->rpos = rpos; +} + +static void oss_hw_fini (HWVoice *hw) +{ + int err; + OSSVoice *oss = (OSSVoice *) hw; + + ldebug ("oss_hw_fini\n"); + err = close (oss->fd); + if (err) { + dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ()); + } + oss->fd = -1; + + if (oss->pcm_buf) { + if (oss->mmapped) { + err = munmap (oss->pcm_buf, hw->bufsize); + if (err) { + dolog ("Failed to unmap OSS buffer\nReason: %s\n", + errstr ()); + } + } + else { + qemu_free (oss->pcm_buf); + } + oss->pcm_buf = NULL; + } +} + +static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +{ + OSSVoice *oss = (OSSVoice *) hw; + struct oss_params req, obt; + + assert (!oss->fd); + req.fmt = AUD_to_ossfmt (fmt); + req.freq = freq; + req.nchannels = nchannels; + req.fragsize = conf.fragsize; + req.nfrags = conf.nfrags; + + if (oss_open (&req, &obt, &oss->fd)) + return -1; + + hw->freq = obt.freq; + hw->fmt = oss_to_audfmt (obt.fmt); + hw->nchannels = obt.nchannels; + + oss->nfrags = obt.nfrags; + oss->fragsize = obt.fragsize; + hw->bufsize = obt.nfrags * obt.fragsize; + + oss->mmapped = 0; + if (conf.try_mmap) { + oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE, + MAP_SHARED, oss->fd, 0); + if (oss->pcm_buf == MAP_FAILED) { + dolog ("Failed to mmap OSS device\nReason: %s\n", + errstr ()); + } else { + int err; + int trig = 0; + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { + dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n", + errstr ()); + } + else { + trig = PCM_ENABLE_OUTPUT; + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { + dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" + "Reason: %s\n", errstr ()); + } + else { + oss->mmapped = 1; + } + } + + if (!oss->mmapped) { + err = munmap (oss->pcm_buf, hw->bufsize); + if (err) { + dolog ("Failed to unmap OSS device\nReason: %s\n", + errstr ()); + } + } + } + } + + if (!oss->mmapped) { + oss->pcm_buf = qemu_mallocz (hw->bufsize); + if (!oss->pcm_buf) { + close (oss->fd); + oss->fd = -1; + return -1; + } + } + + return 0; +} + +static int oss_hw_ctl (HWVoice *hw, int cmd, ...) +{ + int trig; + OSSVoice *oss = (OSSVoice *) hw; + + if (!oss->mmapped) + return 0; + + switch (cmd) { + case VOICE_ENABLE: + ldebug ("enabling voice\n"); + pcm_hw_clear (hw, oss->pcm_buf, hw->samples); + trig = PCM_ENABLE_OUTPUT; + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { + dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" + "Reason: %s\n", errstr ()); + return -1; + } + break; + + case VOICE_DISABLE: + ldebug ("disabling voice\n"); + trig = 0; + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { + dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n", + errstr ()); + return -1; + } + break; + } + return 0; +} + +static void *oss_audio_init (void) +{ + conf.fragsize = audio_get_conf_int (QC_OSS_FRAGSIZE, conf.fragsize); + conf.nfrags = audio_get_conf_int (QC_OSS_NFRAGS, conf.nfrags); + conf.try_mmap = audio_get_conf_int (QC_OSS_MMAP, conf.try_mmap); + conf.dspname = audio_get_conf_str (QC_OSS_DEV, conf.dspname); + return &conf; +} + +static void oss_audio_fini (void *opaque) +{ +} + +struct pcm_ops oss_pcm_ops = { + oss_hw_init, + oss_hw_fini, + oss_hw_run, + oss_hw_write, + oss_hw_ctl +}; + +struct audio_output_driver oss_output_driver = { + "oss", + oss_audio_init, + oss_audio_fini, + &oss_pcm_ops, + 1, + INT_MAX, + sizeof (OSSVoice) +}; diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/audio/sdlaudio.c --- /dev/null Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/audio/sdlaudio.c Tue Dec 20 17:16:24 2005 @@ -0,0 +1,332 @@ +/* + * QEMU SDL audio output driver + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include <SDL.h> +#include <SDL_thread.h> +#include "vl.h" + +#include "audio/audio_int.h" + +typedef struct SDLVoice { + HWVoice hw; +} SDLVoice; + +#define dolog(...) AUD_log ("sdl", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif + +#define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES" + +#define errstr() SDL_GetError () + +static struct { + int nb_samples; +} conf = { + 1024 +}; + +struct SDLAudioState { + int exit; + SDL_mutex *mutex; + SDL_sem *sem; + int initialized; +} glob_sdl; +typedef struct SDLAudioState SDLAudioState; + +static void sdl_hw_run (HWVoice *hw) +{ + (void) hw; +} + +static int sdl_lock (SDLAudioState *s) +{ + if (SDL_LockMutex (s->mutex)) { + dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ()); + return -1; + } + return 0; +} + +static int sdl_unlock (SDLAudioState *s) +{ + if (SDL_UnlockMutex (s->mutex)) { + dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ()); + return -1; + } + return 0; +} + +static int sdl_post (SDLAudioState *s) +{ + if (SDL_SemPost (s->sem)) { + dolog ("SDL_SemPost failed\nReason: %s\n", errstr ()); + return -1; + } + return 0; +} + +static int sdl_wait (SDLAudioState *s) +{ + if (SDL_SemWait (s->sem)) { + dolog ("SDL_SemWait failed\nReason: %s\n", errstr ()); + return -1; + } + return 0; +} + +static int sdl_unlock_and_post (SDLAudioState *s) +{ + if (sdl_unlock (s)) + return -1; + + return sdl_post (s); +} + +static int sdl_hw_write (SWVoice *sw, void *buf, int len) +{ + int ret; + SDLAudioState *s = &glob_sdl; + sdl_lock (s); + ret = pcm_hw_write (sw, buf, len); + sdl_unlock_and_post (s); + return ret; +} + +static int AUD_to_sdlfmt (audfmt_e fmt, int *shift) +{ + *shift = 0; + switch (fmt) { + case AUD_FMT_S8: return AUDIO_S8; + case AUD_FMT_U8: return AUDIO_U8; + case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB; + case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB; + default: + dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt); + exit (EXIT_FAILURE); + } +} + +static int sdl_to_audfmt (int fmt) +{ + switch (fmt) { + case AUDIO_S8: return AUD_FMT_S8; + case AUDIO_U8: return AUD_FMT_U8; + case AUDIO_S16LSB: return AUD_FMT_S16; + case AUDIO_U16LSB: return AUD_FMT_U16; + default: + dolog ("Internal logic error: Unrecognized SDL audio format %d\n" + "Aborting\n", fmt); + exit (EXIT_FAILURE); + } +} + +static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt) +{ + int status; + + status = SDL_OpenAudio (req, obt); + if (status) { + dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ()); + } + return status; +} + +static void sdl_close (SDLAudioState *s) +{ + if (s->initialized) { + sdl_lock (s); + s->exit = 1; + sdl_unlock_and_post (s); + SDL_PauseAudio (1); + SDL_CloseAudio (); + s->initialized = 0; + } +} + +static void sdl_callback (void *opaque, Uint8 *buf, int len) +{ + SDLVoice *sdl = opaque; + SDLAudioState *s = &glob_sdl; + HWVoice *hw = &sdl->hw; + int samples = len >> hw->shift; + + if (s->exit) { + return; + } + + while (samples) { + int to_mix, live, decr; + + /* dolog ("in callback samples=%d\n", samples); */ + sdl_wait (s); + if (s->exit) { + return; + } + + sdl_lock (s); + live = pcm_hw_get_live (hw); + if (live <= 0) + goto again; + + /* dolog ("in callback live=%d\n", live); */ + to_mix = audio_MIN (samples, live); + decr = to_mix; + while (to_mix) { + int chunk = audio_MIN (to_mix, hw->samples - hw->rpos); + st_sample_t *src = hw->mix_buf + hw->rpos; + + /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ + hw->clip (buf, src, chunk); + memset (src, 0, chunk * sizeof (st_sample_t)); + hw->rpos = (hw->rpos + chunk) % hw->samples; + to_mix -= chunk; + buf += chunk << hw->shift; + } + samples -= decr; + pcm_hw_dec_live (hw, decr); + + again: + sdl_unlock (s); + } + /* dolog ("done len=%d\n", len); */ +} + +static void sdl_hw_fini (HWVoice *hw) +{ + ldebug ("sdl_hw_fini %d fixed=%d\n", + glob_sdl.initialized, audio_conf.fixed_format); + sdl_close (&glob_sdl); +} + +static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +{ + SDLVoice *sdl = (SDLVoice *) hw; + SDLAudioState *s = &glob_sdl; + SDL_AudioSpec req, obt; + int shift; + + ldebug ("sdl_hw_init %d freq=%d fixed=%d\n", + s->initialized, freq, audio_conf.fixed_format); + + if (nchannels != 2) { + dolog ("Bogus channel count %d\n", nchannels); + return -1; + } + + req.freq = freq; + req.format = AUD_to_sdlfmt (fmt, &shift); + req.channels = nchannels; + req.samples = conf.nb_samples; + shift <<= nchannels == 2; + + req.callback = sdl_callback; + req.userdata = sdl; + + if (sdl_open (&req, &obt)) + return -1; + + hw->freq = obt.freq; + hw->fmt = sdl_to_audfmt (obt.format); + hw->nchannels = obt.channels; + hw->bufsize = obt.samples << shift; + + s->initialized = 1; + s->exit = 0; + SDL_PauseAudio (0); + return 0; +} + +static int sdl_hw_ctl (HWVoice *hw, int cmd, ...) +{ + (void) hw; + + switch (cmd) { + case VOICE_ENABLE: + SDL_PauseAudio (0); + break; + + case VOICE_DISABLE: + SDL_PauseAudio (1); + break; + } + return 0; +} + +static void *sdl_audio_init (void) +{ + SDLAudioState *s = &glob_sdl; + conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples); + + if (SDL_InitSubSystem (SDL_INIT_AUDIO)) { + dolog ("SDL failed to initialize audio subsystem\nReason: %s\n", + errstr ()); + return NULL; + } + + s->mutex = SDL_CreateMutex (); + if (!s->mutex) { + dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ()); + SDL_QuitSubSystem (SDL_INIT_AUDIO); + return NULL; + } + + s->sem = SDL_CreateSemaphore (0); + if (!s->sem) { + dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ()); + SDL_DestroyMutex (s->mutex); + SDL_QuitSubSystem (SDL_INIT_AUDIO); + return NULL; + } + + return s; +} + +static void sdl_audio_fini (void *opaque) +{ + SDLAudioState *s = opaque; + sdl_close (s); + SDL_DestroySemaphore (s->sem); + SDL_DestroyMutex (s->mutex); + SDL_QuitSubSystem (SDL_INIT_AUDIO); +} + +struct pcm_ops sdl_pcm_ops = { + sdl_hw_init, + sdl_hw_fini, + sdl_hw_run, + sdl_hw_write, + sdl_hw_ctl +}; + +struct audio_output_driver sdl_output_driver = { + "sdl", + sdl_audio_init, + sdl_audio_fini, + &sdl_pcm_ops, + 1, + 1, + sizeof (SDLVoice) +}; diff -r 11cd619db035 -r d3b10a2a82d4 tools/ioemu/audio/wavaudio.c --- /dev/null Tue Dec 20 17:16:15 2005 +++ b/tools/ioemu/audio/wavaudio.c Tue Dec 20 17:16:24 2005 @@ -0,0 +1,217 @@ +/* + * QEMU WAV audio output driver + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#include "audio/audio_int.h" + +typedef struct WAVVoice { + HWVoice hw; + QEMUFile *f; + int64_t old_ticks; + void *pcm_buf; + int total_samples; +} WAVVoice; + +#define dolog(...) AUD_log ("wav", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif + +static struct { + const char *wav_path; +} conf = { + .wav_path = "qemu.wav" +}; + +static void wav_hw_run (HWVoice *hw) +{ + WAVVoice *wav = (WAVVoice *) hw; + int rpos, live, decr, samples; + uint8_t *dst; + st_sample_t *src; + int64_t now = qemu_get_clock (vm_clock); + int64_t ticks = now - wav->old_ticks; + int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec; + + if (bytes > INT_MAX) + samples = INT_MAX >> hw->shift; + else + samples = bytes >> hw->shift; + + live = pcm_hw_get_live (hw); + if (live <= 0) + return; + + wav->old_ticks = now; + decr = audio_MIN (live, samples); + samples = decr; + rpos = hw->rpos; + while (samples) { + int left_till_end_samples = hw->samples - rpos; + int convert_samples = audio_MIN (samples, left_till_end_samples); + + src = advance (hw->mix_buf, rpos * sizeof (st_sample_t)); + dst = advance (wav->pcm_buf, rpos << hw->shift); + + hw->clip (dst, src, convert_samples); + qemu_put_buffer (wav->f, dst, convert_samples << hw->shift); + memset (src, 0, convert_samples * sizeof (st_sample_t)); + + rpos = (rpos + convert_samples) % hw->samples; + samples -= convert_samples; + wav->total_samples += convert_samples; + } + + pcm_hw_dec_live (hw, decr); + hw->rpos = rpos; +} + +static int wav_hw_write (SWVoice *sw, void *buf, int len) +{ + return pcm_hw_write (sw, buf, len); +} + +/* VICE code: Store number as little endian. */ +static void le_store (uint8_t *buf, uint32_t val, int len) +{ + int i; + for (i = 0; i < len; i++) { + buf[i] = (uint8_t) (val & 0xff); + val >>= 8; + } +} + +static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +{ + WAVVoice *wav = (WAVVoice *) hw; + int bits16 = 0, stereo = audio_state.fixed_channels == 2; + uint8_t hdr[] = { + 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, + 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, + 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 + }; + + switch (audio_state.fixed_fmt) { + case AUD_FMT_S8: + case AUD_FMT_U8: + break; + + case AUD_FMT_S16: + case AUD_FMT_U16: + bits16 = 1; + break; + } + + hdr[34] = bits16 ? 0x10 : 0x08; + hw->freq = 44100; + hw->nchannels = stereo ? 2 : 1; + hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8; + hw->bufsize = 4096; + wav->pcm_buf = qemu_mallocz (hw->bufsize); + if (!wav->pcm_buf) + return -1; + + le_store (hdr + 22, hw->nchannels, 2); + le_store (hdr + 24, hw->freq, 4); + le_store (hdr + 28, hw->freq << (bits16 + stereo), 4); + le_store (hdr + 32, 1 << (bits16 + stereo), 2); + + wav->f = fopen (conf.wav_path, "wb"); + if (!wav->f) { + dolog ("failed to open wave file `%s'\nReason: %s\n", + conf.wav_path, strerror (errno)); + qemu_free (wav->pcm_buf); + wav->pcm_buf = NULL; + return -1; + } + + qemu_put_buffer (wav->f, hdr, sizeof (hdr)); + return 0; +} + +static void wav_hw_fini (HWVoice *hw) +{ + WAVVoice *wav = (WAVVoice *) hw; + int stereo = hw->nchannels == 2; + uint8_t rlen[4]; + uint8_t dlen[4]; + uint32_t rifflen = (wav->total_samples << stereo) + 36; + uint32_t datalen = wav->total_samples << stereo; + + if (!wav->f || !hw->active) + return; + + le_store (rlen, rifflen, 4); + le_store (dlen, datalen, 4); + + qemu_fseek (wav->f, 4, SEEK_SET); + qemu_put_buffer (wav->f, rlen, 4); + + qemu_fseek (wav->f, 32, SEEK_CUR); + qemu_put_buffer (wav->f, dlen, 4); + + fclose (wav->f); + wav->f = NULL; + + qemu_free (wav->pcm_buf); + wav->pcm_buf = NULL; +} + +static int wav_hw_ctl (HWVoice *hw, int cmd, ...) +{ + (void) hw; + (void) cmd; + return 0; +} + +static void *wav_audio_init (void) +{ + return &conf; +} + +static void wav_audio_fini (void *opaque) +{ + ldebug ("wav_fini"); +} + +struct pcm_ops wav_pcm_ops = { + wav_hw_init, + wav_hw_fini, + wav_hw_run, + wav_hw_write, + wav_hw_ctl +}; + +struct audio_output_driver wav_output_driver = { + "wav", + wav_audio_init, + wav_audio_fini, + &wav_pcm_ops, + 1, + 1, + sizeof (WAVVoice) +}; diff -r 11cd619db035 -r d3b10a2a82d4 tools/libxc/xc_ptrace.h --- /dev/null Tue Dec 20 17:16:15 2005 +++ b/tools/libxc/xc_ptrace.h Tue Dec 20 17:16:24 2005 @@ -0,0 +1,124 @@ +#ifndef XC_PTRACE_ +#define XC_PTRACE_ + +#ifdef XC_PTRACE_PRIVATE +#define X86_CR0_PE 0x00000001 /* Enable Protected Mode (RW) */ +#define X86_CR0_PG 0x80000000 /* Paging (RW) */ +#define BSD_PAGE_MASK (PAGE_SIZE-1) +#define PDRSHIFT 22 +#define PSL_T 0x00000100 /* trace enable bit */ + +char * ptrace_names[] = { + "PTRACE_TRACEME", + "PTRACE_PEEKTEXT", + "PTRACE_PEEKDATA", + "PTRACE_PEEKUSER", + "PTRACE_POKETEXT", + "PTRACE_POKEDATA", + "PTRACE_POKEUSER", + "PTRACE_CONT", + "PTRACE_KILL", + "PTRACE_SINGLESTEP", + "PTRACE_INVALID", + "PTRACE_INVALID", + "PTRACE_GETREGS", + "PTRACE_SETREGS", + "PTRACE_GETFPREGS", + "PTRACE_SETFPREGS", + "PTRACE_ATTACH", + "PTRACE_DETACH", + "PTRACE_GETFPXREGS", + "PTRACE_SETFPXREGS", + "PTRACE_INVALID", + "PTRACE_INVALID", + "PTRACE_INVALID", + "PTRACE_INVALID", + "PTRACE_SYSCALL", +}; + +struct gdb_regs { + long ebx; /* 0 */ + long ecx; /* 4 */ + long edx; /* 8 */ + long esi; /* 12 */ + long edi; /* 16 */ + long ebp; /* 20 */ + long eax; /* 24 */ + int xds; /* 28 */ + int xes; /* 32 */ + int xfs; /* 36 */ + int xgs; /* 40 */ + long orig_eax; /* 44 */ + long eip; /* 48 */ + int xcs; /* 52 */ + long eflags; /* 56 */ + long esp; /* 60 */ + int xss; /* 64 */ +}; + + +#define printval(x) printf("%s = %lx\n", #x, (long)x); +#define SET_PT_REGS(pt, xc) \ +{ \ + pt.ebx = xc.ebx; \ + pt.ecx = xc.ecx; \ + pt.edx = xc.edx; \ + pt.esi = xc.esi; \ + pt.edi = xc.edi; \ + pt.ebp = xc.ebp; \ + pt.eax = xc.eax; \ + pt.eip = xc.eip; \ + pt.xcs = xc.cs; \ + pt.eflags = xc.eflags; \ + pt.esp = xc.esp; \ + pt.xss = xc.ss; \ + pt.xes = xc.es; \ + pt.xds = xc.ds; \ + pt.xfs = xc.fs; \ + pt.xgs = xc.gs; \ +} + +#define SET_XC_REGS(pt, xc) \ +{ \ + xc.ebx = pt->ebx; \ + xc.ecx = pt->ecx; \ + xc.edx = pt->edx; \ + xc.esi = pt->esi; \ + xc.edi = pt->edi; \ + xc.ebp = pt->ebp; \ + xc.eax = pt->eax; \ + xc.eip = pt->eip; \ + xc.cs = pt->xcs; \ + xc.eflags = pt->eflags; \ + xc.esp = pt->esp; \ + xc.ss = pt->xss; \ + xc.es = pt->xes; \ + xc.ds = pt->xds; \ + xc.fs = pt->xfs; \ + xc.gs = pt->xgs; \ +} + +#define vtopdi(va) ((va) >> PDRSHIFT) +#define vtopti(va) (((va) >> PAGE_SHIFT) & 0x3ff) +#endif + +typedef void (*thr_ev_handler_t)(long); + +void xc_register_event_handler( + thr_ev_handler_t h, + td_event_e e); + +long xc_ptrace( + int xc_handle, + enum __ptrace_request request, + uint32_t domid, + long addr, + long data); + +int xc_waitdomain( + int xc_handle, + int domain, + int *status, + int options); + +#endif /* XC_PTRACE */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |