/* in ms */
#define GUI_REFRESH_INTERVAL 30
+/* Max number of USB devices that can be specified on the commandline. */
+#define MAX_USB_CMDLINE 8
+
/* XXX: use a two level table to limit memory usage */
#define MAX_IOPORTS 65536
int win2k_install_hack = 0;
#endif
int usb_enabled = 0;
-USBPort *vm_usb_ports[MAX_VM_USB_PORTS];
-USBDevice *vm_usb_hub;
static VLANState *first_vlan;
int smp_cpus = 1;
int vnc_display = -1;
#else
#define MAX_CPUS 1
#endif
+int acpi_enabled = 1;
+int fd_bootchk = 1;
/***********************************************************/
/* x86 ISA bus support */
int64_t cpu_get_real_ticks(void)
{
+#ifdef _WIN32
+ LARGE_INTEGER ti;
+ QueryPerformanceCounter(&ti);
+ return ti.QuadPart;
+#else
int64_t val;
asm volatile ("rdtsc" : "=A" (val));
return val;
+#endif
}
#elif defined(__x86_64__)
return val;
}
+#elif defined(__sparc__) && defined(HOST_SOLARIS)
+
+uint64_t cpu_get_real_ticks (void)
+{
+#if defined(_LP64)
+ uint64_t rval;
+ asm volatile("rd %%tick,%0" : "=r"(rval));
+ return rval;
+#else
+ union {
+ uint64_t i64;
+ struct {
+ uint32_t high;
+ uint32_t low;
+ } i32;
+ } rval;
+ asm volatile("rd %%tick,%1; srlx %1,32,%0"
+ : "=r"(rval.i32.high), "=r"(rval.i32.low));
+ return rval.i64;
+#endif
+}
+
#else
#error unsupported CPU
#endif
}
}
-static int64_t get_clock(void)
-{
#ifdef _WIN32
- struct _timeb tb;
- _ftime(&tb);
- return ((int64_t)tb.time * 1000 + (int64_t)tb.millitm) * 1000;
+void cpu_calibrate_ticks(void)
+{
+ LARGE_INTEGER freq;
+ int ret;
+
+ ret = QueryPerformanceFrequency(&freq);
+ if (ret == 0) {
+ fprintf(stderr, "Could not calibrate ticks\n");
+ exit(1);
+ }
+ ticks_per_sec = freq.QuadPart;
+}
+
#else
+static int64_t get_clock(void)
+{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000LL + tv.tv_usec;
-#endif
}
void cpu_calibrate_ticks(void)
usec = get_clock();
ticks = cpu_get_real_ticks();
-#ifdef _WIN32
- Sleep(50);
-#else
usleep(50 * 1000);
-#endif
usec = get_clock() - usec;
ticks = cpu_get_real_ticks() - ticks;
ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec;
}
+#endif /* !_WIN32 */
/* compute with 96 bit intermediate result: (a*b)/c */
uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
static QEMUTimer *active_timers[2];
#ifdef _WIN32
static MMRESULT timerID;
+static HANDLE host_alarm = NULL;
+static unsigned int period = 1;
#else
/* frequency of the times() clock tick */
static int timer_freq;
qemu_get_clock(vm_clock)) ||
qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
qemu_get_clock(rt_clock))) {
+#ifdef _WIN32
+ SetEvent(host_alarm);
+#endif
CPUState *env = cpu_single_env;
if (env) {
/* stop the currently executing cpu because a timer occured */
#ifdef _WIN32
{
int count=0;
+ TIMECAPS tc;
+
+ ZeroMemory(&tc, sizeof(TIMECAPS));
+ timeGetDevCaps(&tc, sizeof(TIMECAPS));
+ if (period < tc.wPeriodMin)
+ period = tc.wPeriodMin;
+ timeBeginPeriod(period);
timerID = timeSetEvent(1, // interval (ms)
- 0, // resolution
+ period, // resolution
host_alarm_handler, // function
(DWORD)&count, // user parameter
TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
perror("failed timer alarm");
exit(1);
}
+ host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!host_alarm) {
+ perror("failed CreateEvent");
+ exit(1);
+ }
+ ResetEvent(host_alarm);
}
pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000;
#else
getitimer(ITIMER_REAL, &itv);
#if defined(__linux__)
- if (itv.it_interval.tv_usec > 1000) {
+ /* XXX: force /dev/rtc usage because even 2.6 kernels may not
+ have timers with 1 ms resolution. The correct solution will
+ be to use the POSIX real time timers available in recent
+ 2.6 kernels */
+ if (itv.it_interval.tv_usec > 1000 || 1) {
/* try to use /dev/rtc to have a faster timer */
if (start_rtc_timer() < 0)
goto use_itimer;
{
#ifdef _WIN32
timeKillEvent(timerID);
+ timeEndPeriod(period);
+ if (host_alarm) {
+ CloseHandle(host_alarm);
+ host_alarm = NULL;
+ }
#endif
}
/***********************************************************/
/* USB devices */
+static USBPort *used_usb_ports;
+static USBPort *free_usb_ports;
+
+/* ??? Maybe change this to register a hub to keep track of the topology. */
+void qemu_register_usb_port(USBPort *port, void *opaque, int index,
+ usb_attachfn attach)
+{
+ port->opaque = opaque;
+ port->index = index;
+ port->attach = attach;
+ port->next = free_usb_ports;
+ free_usb_ports = port;
+}
+
static int usb_device_add(const char *devname)
{
const char *p;
USBDevice *dev;
- int i;
+ USBPort *port;
- if (!vm_usb_hub)
- return -1;
- for(i = 0;i < MAX_VM_USB_PORTS; i++) {
- if (!vm_usb_ports[i]->dev)
- break;
- }
- if (i == MAX_VM_USB_PORTS)
+ if (!free_usb_ports)
return -1;
if (strstart(devname, "host:", &p)) {
dev = usb_host_device_open(p);
- if (!dev)
- return -1;
} else if (!strcmp(devname, "mouse")) {
dev = usb_mouse_init();
- if (!dev)
- return -1;
} else if (!strcmp(devname, "tablet")) {
dev = usb_tablet_init();
- if (!dev)
- return -1;
+ } else if (strstart(devname, "disk:", &p)) {
+ dev = usb_msd_init(p);
} else {
return -1;
}
- usb_attach(vm_usb_ports[i], dev);
+ if (!dev)
+ return -1;
+
+ /* Find a USB port to add the device to. */
+ port = free_usb_ports;
+ if (!port->next) {
+ USBDevice *hub;
+
+ /* Create a new hub and chain it on. */
+ free_usb_ports = NULL;
+ port->next = used_usb_ports;
+ used_usb_ports = port;
+
+ hub = usb_hub_init(VM_USB_HUB_SIZE);
+ usb_attach(port, hub);
+ port = free_usb_ports;
+ }
+
+ free_usb_ports = port->next;
+ port->next = used_usb_ports;
+ used_usb_ports = port;
+ usb_attach(port, dev);
return 0;
}
static int usb_device_del(const char *devname)
{
- USBDevice *dev;
- int bus_num, addr, i;
+ USBPort *port;
+ USBPort **lastp;
+ int bus_num, addr;
const char *p;
- if (!vm_usb_hub)
+ if (!used_usb_ports)
return -1;
p = strchr(devname, '.');
addr = strtoul(p + 1, NULL, 0);
if (bus_num != 0)
return -1;
- for(i = 0;i < MAX_VM_USB_PORTS; i++) {
- dev = vm_usb_ports[i]->dev;
- if (dev && dev->addr == addr)
- break;
+
+ lastp = &used_usb_ports;
+ port = used_usb_ports;
+ while (port && port->dev->addr != addr) {
+ lastp = &port->next;
+ port = port->next;
}
- if (i == MAX_VM_USB_PORTS)
+
+ if (!port)
return -1;
- usb_attach(vm_usb_ports[i], NULL);
+
+ *lastp = port->next;
+ usb_attach(port, NULL);
+ port->next = free_usb_ports;
+ free_usb_ports = port;
return 0;
}
void usb_info(void)
{
USBDevice *dev;
- int i;
+ USBPort *port;
const char *speed_str;
- if (!vm_usb_hub) {
+ if (!usb_enabled) {
term_printf("USB support not enabled\n");
return;
}
- for(i = 0; i < MAX_VM_USB_PORTS; i++) {
- dev = vm_usb_ports[i]->dev;
- if (dev) {
- term_printf("Hub port %d:\n", i);
- switch(dev->speed) {
- case USB_SPEED_LOW:
- speed_str = "1.5";
- break;
- case USB_SPEED_FULL:
- speed_str = "12";
- break;
- case USB_SPEED_HIGH:
- speed_str = "480";
- break;
- default:
- speed_str = "?";
- break;
- }
- term_printf(" Device %d.%d, speed %s Mb/s\n",
- 0, dev->addr, speed_str);
+ for (port = used_usb_ports; port; port = port->next) {
+ dev = port->dev;
+ if (!dev)
+ continue;
+ switch(dev->speed) {
+ case USB_SPEED_LOW:
+ speed_str = "1.5";
+ break;
+ case USB_SPEED_FULL:
+ speed_str = "12";
+ break;
+ case USB_SPEED_HIGH:
+ speed_str = "480";
+ break;
+ default:
+ speed_str = "?";
+ break;
}
+ term_printf(" Device %d.%d, speed %s Mb/s\n",
+ 0, dev->addr, speed_str);
}
}
void main_loop_wait(int timeout)
{
IOHandlerRecord *ioh, *ioh_next;
- fd_set rfds, wfds;
+ fd_set rfds, wfds, xfds;
int ret, nfds;
struct timeval tv;
PollingEntry *pe;
}
#ifdef _WIN32
if (ret == 0 && timeout > 0) {
- Sleep(timeout);
+ int err;
+ HANDLE hEvents[1];
+
+ hEvents[0] = host_alarm;
+ ret = WaitForMultipleObjects(1, hEvents, FALSE, timeout);
+ switch(ret) {
+ case WAIT_OBJECT_0 + 0:
+ break;
+ case WAIT_TIMEOUT:
+ break;
+ default:
+ err = GetLastError();
+ fprintf(stderr, "Wait error %d %d\n", ret, err);
+ break;
+ }
}
#endif
/* poll any events */
nfds = -1;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
+ FD_ZERO(&xfds);
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
if (ioh->fd_read &&
(!ioh->fd_read_poll ||
#else
tv.tv_usec = timeout * 1000;
#endif
- ret = select(nfds + 1, &rfds, &wfds, NULL, &tv);
+#if defined(CONFIG_SLIRP)
+ if (slirp_inited) {
+ slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+ }
+#endif
+ ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
if (ret > 0) {
/* XXX: better handling of removal */
for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
}
}
}
-#ifdef _WIN32
- tap_win32_poll();
-#endif
-
#if defined(CONFIG_SLIRP)
- /* XXX: merge with the previous select() */
if (slirp_inited) {
- fd_set rfds, wfds, xfds;
- int nfds;
- struct timeval tv;
-
- nfds = -1;
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_ZERO(&xfds);
- slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
- if (ret >= 0) {
- slirp_select_poll(&rfds, &wfds, &xfds);
+ if (ret < 0) {
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&xfds);
}
+ slirp_select_poll(&rfds, &wfds, &xfds);
}
#endif
+#ifdef _WIN32
+ tap_win32_poll();
+#endif
if (vm_running) {
qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
"-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n"
"-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n"
"-snapshot write to temporary files instead of disk image files\n"
+#ifdef TARGET_I386
+ "-no-fd-bootchk disable boot signature checking for floppy disks\n"
+#endif
"-m megs set virtual RAM size to megs MB [default=%d]\n"
"-smp n set the number of CPUs to 'n' [default=1]\n"
"-nographic disable graphical output and redirect serial I/Os to console\n"
" translation (t=none or lba) (usually qemu can guess them)\n"
"-L path set the directory for the BIOS and VGA BIOS\n"
#ifdef USE_KQEMU
+ "-kernel-kqemu enable KQEMU full virtualization (default is user mode only)\n"
"-no-kqemu disable KQEMU kernel module usage\n"
#endif
#ifdef USE_CODE_COPY
#ifdef TARGET_I386
"-std-vga simulate a standard VGA card with VESA Bochs Extensions\n"
" (default is CL-GD5446 PCI VGA)\n"
+ "-no-acpi disable ACPI\n"
#endif
"-loadvm file start right away with a saved state (loadvm in monitor)\n"
"-vnc display start a VNC server on display\n"
QEMU_OPTION_cdrom,
QEMU_OPTION_boot,
QEMU_OPTION_snapshot,
+#ifdef TARGET_I386
+ QEMU_OPTION_no_fd_bootchk,
+#endif
QEMU_OPTION_m,
QEMU_OPTION_nographic,
#ifdef HAS_AUDIO
QEMU_OPTION_usbdevice,
QEMU_OPTION_smp,
QEMU_OPTION_vnc,
+ QEMU_OPTION_no_acpi,
};
typedef struct QEMUOption {
{ "cdrom", HAS_ARG, QEMU_OPTION_cdrom },
{ "boot", HAS_ARG, QEMU_OPTION_boot },
{ "snapshot", 0, QEMU_OPTION_snapshot },
+#ifdef TARGET_I386
+ { "no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk },
+#endif
{ "m", HAS_ARG, QEMU_OPTION_m },
{ "nographic", 0, QEMU_OPTION_nographic },
{ "k", HAS_ARG, QEMU_OPTION_k },
/* temporary options */
{ "usb", 0, QEMU_OPTION_usb },
{ "cirrusvga", 0, QEMU_OPTION_cirrusvga },
+ { "no-acpi", 0, QEMU_OPTION_no_acpi },
{ NULL },
};
int parallel_device_index;
const char *loadvm = NULL;
QEMUMachine *machine;
- char usb_devices[MAX_VM_USB_PORTS][128];
+ char usb_devices[MAX_USB_CMDLINE][128];
int usb_devices_index;
LIST_INIT (&vm_change_state_head);
case QEMU_OPTION_fdb:
fd_filename[1] = optarg;
break;
+#ifdef TARGET_I386
+ case QEMU_OPTION_no_fd_bootchk:
+ fd_bootchk = 0;
+ break;
+#endif
case QEMU_OPTION_no_code_copy:
code_copy_enabled = 0;
break;
break;
case QEMU_OPTION_usbdevice:
usb_enabled = 1;
- if (usb_devices_index >= MAX_VM_USB_PORTS) {
+ if (usb_devices_index >= MAX_USB_CMDLINE) {
fprintf(stderr, "Too many USB devices\n");
exit(1);
}
exit(1);
}
break;
+ case QEMU_OPTION_no_acpi:
+ acpi_enabled = 0;
+ break;
}
}
}
}
}
- /* init USB devices */
- if (usb_enabled) {
- vm_usb_hub = usb_hub_init(vm_usb_ports, MAX_VM_USB_PORTS);
- for(i = 0; i < usb_devices_index; i++) {
- if (usb_device_add(usb_devices[i]) < 0) {
- fprintf(stderr, "Warning: could not add USB device %s\n",
- usb_devices[i]);
- }
- }
- }
-
register_savevm("timer", 0, 1, timer_save, timer_load, NULL);
register_savevm("ram", 0, 1, ram_save, ram_load, NULL);
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline, initrd_filename);
+ /* init USB devices */
+ if (usb_enabled) {
+ for(i = 0; i < usb_devices_index; i++) {
+ if (usb_device_add(usb_devices[i]) < 0) {
+ fprintf(stderr, "Warning: could not add USB device %s\n",
+ usb_devices[i]);
+ }
+ }
+ }
+
gui_timer = qemu_new_timer(rt_clock, gui_update, NULL);
qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock));