diff options
Diffstat (limited to 'tools')
0 files changed, 0 insertions, 0 deletions
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2007 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"
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/time.h>
#include <zlib.h>
#ifndef _WIN32
#include <sys/times.h>
#include <sys/wait.h>
#include <termios.h>
#include <sys/poll.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <netdb.h>
#ifdef _BSD
#include <sys/stat.h>
#ifndef __APPLE__
#include <libutil.h>
#endif
#else
#ifndef __sun__
#include <linux/if.h>
#include <linux/if_tun.h>
#include <pty.h>
#include <malloc.h>
#include <linux/rtc.h>
#include <linux/ppdev.h>
#endif
#endif
#endif
#if defined(CONFIG_SLIRP)
#include "libslirp.h"
#endif
#ifdef _WIN32
#include <malloc.h>
#include <sys/timeb.h>
#include <windows.h>
#define getopt_long_only getopt_long
#define memalign(align, size) malloc(size)
#endif
#include "qemu_socket.h"
#ifdef CONFIG_SDL
#ifdef __APPLE__
#include <SDL/SDL.h>
#endif
#endif /* CONFIG_SDL */
#ifdef CONFIG_COCOA
#undef main
#define main qemu_main
#endif /* CONFIG_COCOA */
#include "disas.h"
#include "exec-all.h"
#include <xen/hvm/params.h>
#define DEFAULT_NETWORK_SCRIPT "/etc/xen/qemu-ifup"
#define DEFAULT_BRIDGE "xenbr0"
#ifdef __sun__
#define SMBD_COMMAND "/usr/sfw/sbin/smbd"
#else
#define SMBD_COMMAND "/usr/sbin/smbd"
#endif
//#define DEBUG_UNUSED_IOPORT
//#define DEBUG_IOPORT
#define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024)
#ifdef TARGET_PPC
#define DEFAULT_RAM_SIZE 144
#else
#define DEFAULT_RAM_SIZE 128
#endif
/* 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
const char *bios_dir = CONFIG_QEMU_SHAREDIR;
char phys_ram_file[1024];
void *ioport_opaque[MAX_IOPORTS];
IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
/* Note: bs_table[MAX_DISKS] is a dummy block driver if none available
to store the VM snapshots */
BlockDriverState *bs_table[MAX_DISKS + MAX_SCSI_DISKS + 1], *fd_table[MAX_FD];
/* point to the block driver where the snapshots are managed */
BlockDriverState *bs_snapshots;
int vga_ram_size;
int bios_size;
static DisplayState display_state;
int nographic;
int vncviewer;
int vncunused;
const char* keyboard_layout = NULL;
int64_t ticks_per_sec;
char *boot_device = NULL;
uint64_t ram_size;
int pit_min_timer_count = 0;
int nb_nics;
NICInfo nd_table[MAX_NICS];
QEMUTimer *gui_timer;
int vm_running;
int rtc_utc = 1;
int cirrus_vga_enabled = 1;
#ifdef TARGET_SPARC
int graphic_width = 1024;
int graphic_height = 768;
#else
int graphic_width = 800;
int graphic_height = 600;
#endif
int graphic_depth = 15;
int full_screen = 0;
int no_quit = 0;
CharDriverState *serial_hds[MAX_SERIAL_PORTS];
CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
#ifdef TARGET_I386
int win2k_install_hack = 0;
#endif
int usb_enabled = 0;
static VLANState *first_vlan;
int smp_cpus = 1;
const char *vnc_display;
#if defined(TARGET_SPARC)
#define MAX_CPUS 16
#elif defined(TARGET_I386)
#define MAX_CPUS 255
#else
#define MAX_CPUS 1
#endif
int acpi_enabled = 0;
int fd_bootchk = 1;
int no_reboot = 0;
int daemonize = 0;
const char *option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
int semihosting_enabled = 0;
int autostart = 1;
extern int vcpus;
int xc_handle;
time_t timeoffset = 0;
char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'};
extern int domid;
char vncpasswd[64];
unsigned char challenge[AUTHCHALLENGESIZE];
/***********************************************************/
/* x86 ISA bus support */
target_phys_addr_t isa_mem_base = 0;
PicState2 *isa_pic;
uint32_t default_ioport_readb(void *opaque, uint32_t address)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "inb: port=0x%04x\n", address);
#endif
return 0xff;
}
void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "outb: port=0x%04x data=0x%02x\n", address, data);
#endif
}
/* default is to make two byte accesses */
uint32_t default_ioport_readw(void *opaque, uint32_t address)
{
uint32_t data;
data = ioport_read_table[0][address](ioport_opaque[address], address);
address = (address + 1) & (MAX_IOPORTS - 1);
data |= ioport_read_table[0][address](ioport_opaque[address], address) << 8;
return data;
}
void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
{
ioport_write_table[0][address](ioport_opaque[address], address, data & 0xff);
address = (address + 1) & (MAX_IOPORTS - 1);
ioport_write_table[0][address](ioport_opaque[address], address, (data >> 8) & 0xff);
}
uint32_t default_ioport_readl(void *opaque, uint32_t address)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "inl: port=0x%04x\n", address);
#endif
return 0xffffffff;
}
void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "outl: port=0x%04x data=0x%02x\n", address, data);
#endif
}
void init_ioports(void)
{
int i;
for(i = 0; i < MAX_IOPORTS; i++) {
ioport_read_table[0][i] = default_ioport_readb;
ioport_write_table[0][i] = default_ioport_writeb;
ioport_read_table[1][i] = default_ioport_readw;
ioport_write_table[1][i] = default_ioport_writew;
ioport_read_table[2][i] = default_ioport_readl;
ioport_write_table[2][i] = default_ioport_writel;
}
}
/* size is the word size in byte */
int register_ioport_read(int start, int length, int size,
IOPortReadFunc *func, void *opaque)
{
int i, bsize;
if (size == 1) {
bsize = 0;
} else if (size == 2) {
bsize = 1;
} else if (size == 4) {
bsize = 2;
} else {
hw_error("register_ioport_read: invalid size");
return -1;
}
for(i = start; i < start + length; i += size) {
ioport_read_table[bsize][i] = func;
if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
hw_error("register_ioport_write: invalid opaque");
ioport_opaque[i] = opaque;
}
return 0;
}
/* size is the word size in byte */
int register_ioport_write(int start, int length, int size,
IOPortWriteFunc *func, void *opaque)
{
int i, bsize;
if (size == 1) {
bsize = 0;
} else if (size == 2) {
bsize = 1;
} else if (size == 4) {
bsize = 2;
} else {
hw_error("register_ioport_write: invalid size");
return -1;
}
for(i = start; i < start + length; i += size) {
ioport_write_table[bsize][i] = func;
if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
hw_error("register_ioport_write: invalid opaque");
ioport_opaque[i] = opaque;
}
return 0;
}
void isa_unassign_ioport(int start, int length)
{
int i;
for(i = start; i < start + length; i++) {
ioport_read_table[0][i] = default_ioport_readb;
ioport_read_table[1][i] = default_ioport_readw;
ioport_read_table[2][i] = default_ioport_readl;
ioport_write_table[0][i] = default_ioport_writeb;
ioport_write_table[1][i] = default_ioport_writew;
ioport_write_table[2][i] = default_ioport_writel;
}
}
/***********************************************************/
void cpu_outb(CPUState *env, int addr, int val)
{
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "outb: %04x %02x\n", addr, val);
#endif
ioport_write_table[0][addr](ioport_opaque[addr], addr, val);
#ifdef USE_KQEMU
if (env)
env->last_io_time = cpu_get_time_fast();
#endif
}
void cpu_outw(CPUState *env, int addr, int val)
{
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "outw: %04x %04x\n", addr, val);
#endif
ioport_write_table[1][addr](ioport_opaque[addr], addr, val);
#ifdef USE_KQEMU
if (env)
env->last_io_time = cpu_get_time_fast();
#endif
}
void cpu_outl(CPUState *env, int addr, int val)
{
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "outl: %04x %08x\n", addr, val);
#endif
ioport_write_table[2][addr](ioport_opaque[addr], addr, val);
#ifdef USE_KQEMU
if (env)
env->last_io_time = cpu_get_time_fast();
#endif
}
int cpu_inb(CPUState *env, int addr)
{
int val;
val = ioport_read_table[0][addr](ioport_opaque[addr], addr);
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "inb : %04x %02x\n", addr, val);
#endif
#ifdef USE_KQEMU
if (env)
env->last_io_time = cpu_get_time_fast();
#endif
return val;
}
int cpu_inw(CPUState *env, int addr)
{
int val;
val = ioport_read_table[1][addr](ioport_opaque[addr], addr);
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "inw : %04x %04x\n", addr, val);
#endif
#ifdef USE_KQEMU
if (env)
env->last_io_time = cpu_get_time_fast();
#endif
return val;
}
int cpu_inl(CPUState *env, int addr)
{
int val;
val = ioport_read_table[2][addr](ioport_opaque[addr], addr);
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "inl : %04x %08x\n", addr, val);
#endif
#ifdef USE_KQEMU
if (env)
env->last_io_time = cpu_get_time_fast();
#endif
return val;
}
/***********************************************************/
void hw_error(const char *fmt, ...)
{
va_list ap;
#ifndef CONFIG_DM
CPUState *env;
#endif /* !CONFIG_DM */
va_start(ap, fmt);
fprintf(stderr, "qemu: hardware error: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
#ifndef CONFIG_DM
for(env = first_cpu; env != NULL; env = env->next_cpu) {
fprintf(stderr, "CPU #%d:\n", env->cpu_index);
#ifdef TARGET_I386
cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU);
#else
cpu_dump_state(env, stderr, fprintf, 0);
#endif
}
#endif /* !CONFIG_DM */
va_end(ap);
abort();
}
/***********************************************************/
/* keyboard/mouse */
static QEMUPutKBDEvent *qemu_put_kbd_event;
static void *qemu_put_kbd_event_opaque;
static QEMUPutMouseEntry *qemu_put_mouse_event_head;
static QEMUPutMouseEntry *qemu_put_mouse_event_current;
void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
{
qemu_put_kbd_event_opaque = opaque;
qemu_put_kbd_event = func;
}
QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
void *opaque, int absolute,
const char *name)
{
QEMUPutMouseEntry *s, *cursor;
s = qemu_mallocz(sizeof(QEMUPutMouseEntry));
if (!s)
return NULL;
s->qemu_put_mouse_event = func;
s->qemu_put_mouse_event_opaque = opaque;
s->qemu_put_mouse_event_absolute = absolute;
s->qemu_put_mouse_event_name = qemu_strdup(name);
s->next = NULL;
if (!qemu_put_mouse_event_head) {
qemu_put_mouse_event_head = qemu_put_mouse_event_current = s;
return s;
}
cursor = qemu_put_mouse_event_head;
while (cursor->next != NULL)
cursor = cursor->next;
cursor->next = s;
qemu_put_mouse_event_current = s;
return s;
}
void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry)
{
QEMUPutMouseEntry *prev = NULL, *cursor;
if (!qemu_put_mouse_event_head || entry == NULL)
return;
cursor = qemu_put_mouse_event_head;
while (cursor != NULL && cursor != entry) {
prev = cursor;
cursor = cursor->next;
}
if (cursor == NULL) // does not exist or list empty
return;
else if (prev == NULL) { // entry is head
qemu_put_mouse_event_head = cursor->next;
if (qemu_put_mouse_event_current == entry)
qemu_put_mouse_event_current = cursor->next;
qemu_free(entry->qemu_put_mouse_event_name);
qemu_free(entry);
return;
}
prev->next = entry->next;
if (qemu_put_mouse_event_current == entry)
qemu_put_mouse_event_current = prev;
qemu_free(entry->qemu_put_mouse_event_name);
qemu_free(entry);
}
void kbd_put_keycode(int keycode)
{
if (qemu_put_kbd_event) {
qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode);
}
}
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
{
QEMUPutMouseEvent *mouse_event;
void *mouse_event_opaque;
if (!qemu_put_mouse_event_current) {
return;
}
mouse_event =
qemu_put_mouse_event_current->qemu_put_mouse_event;
mouse_event_opaque =
qemu_put_mouse_event_current->qemu_put_mouse_event_opaque;
if (mouse_event) {
mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state);
}
}
int kbd_mouse_is_absolute(void)
{
if (!qemu_put_mouse_event_current)
return 0;
return qemu_put_mouse_event_current->qemu_put_mouse_event_absolute;
}
void do_info_mice(void)
{
QEMUPutMouseEntry *cursor;
int index = 0;
if (!qemu_put_mouse_event_head) {
term_printf("No mouse devices connected\n");
return;
}
term_printf("Mouse devices available:\n");
cursor = qemu_put_mouse_event_head;
while (cursor != NULL) {
term_printf("%c Mouse #%d: %s\n",
(cursor == qemu_put_mouse_event_current ? '*' : ' '),
index, cursor->qemu_put_mouse_event_name);
index++;
cursor = cursor->next;
}
}
void do_mouse_set(int index)
{
QEMUPutMouseEntry *cursor;
int i = 0;
if (!qemu_put_mouse_event_head) {
term_printf("No mouse devices connected\n");
return;
}
cursor = qemu_put_mouse_event_head;
while (cursor != NULL && index != i) {
i++;
cursor = cursor->next;
}
if (cursor != NULL)
qemu_put_mouse_event_current = cursor;
else
term_printf("Mouse at given index not found\n");
}
/* compute with 96 bit intermediate result: (a*b)/c */
uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
{
union {
uint64_t ll;
struct {
#ifdef WORDS_BIGENDIAN
uint32_t high, low;
#else
uint32_t low, high;
#endif
} l;
} u, res;
uint64_t rl, rh;
u.ll = a;
rl = (uint64_t)u.l.low * (uint64_t)b;
rh = (uint64_t)u.l.high * (uint64_t)b;
rh += (rl >> 32);
res.l.high = rh / c;
res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
return res.ll;
}
/***********************************************************/
/* real time host monotonic timer */
#define QEMU_TIMER_BASE 1000000000LL
#ifdef WIN32
static int64_t clock_freq;
static void init_get_clock(void)
{
LARGE_INTEGER freq;
int ret;
ret = QueryPerformanceFrequency(&freq);
if (ret == 0) {
fprintf(stderr, "Could not calibrate ticks\n");
exit(1);
}
clock_freq = freq.QuadPart;
}
static int64_t get_clock(void)
{
LARGE_INTEGER ti;
QueryPerformanceCounter(&ti);
return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq);
}
#else
static int use_rt_clock;
static void init_get_clock(void)
{
use_rt_clock = 0;
#if defined(__linux__)
{
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
use_rt_clock = 1;
}
}
#endif
}
static int64_t get_clock(void)
{
#if defined(__linux__)
if (use_rt_clock) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000000LL + ts.tv_nsec;
} else
#endif
{
/* XXX: using gettimeofday leads to problems if the date
changes, so it should be avoided. */
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
}
}
#endif
/***********************************************************/
/* guest cycle counter */
static int64_t cpu_ticks_prev;
static int64_t cpu_ticks_offset;
static int64_t cpu_clock_offset;
static int cpu_ticks_enabled;
/* return the host CPU cycle counter and handle stop/restart */
int64_t cpu_get_ticks(void)
{
if (!cpu_ticks_enabled) {
return cpu_ticks_offset;
} else {
int64_t ticks;
ticks = cpu_get_real_ticks();
if (cpu_ticks_prev > ticks) {
/* Note: non increasing ticks may happen if the host uses
software suspend */
cpu_ticks_offset += cpu_ticks_prev - ticks;
}
cpu_ticks_prev = ticks;
return ticks + cpu_ticks_offset;
}
}
/* return the host CPU monotonic timer and handle stop/restart */
static int64_t cpu_get_clock(void)
{
int64_t ti;
if (!cpu_ticks_enabled) {
return cpu_clock_offset;
} else {
ti = get_clock();
return ti + cpu_clock_offset;
}
}
/* enable cpu_get_ticks() */
void cpu_enable_ticks(void)
{
if (!cpu_ticks_enabled) {
cpu_ticks_offset -= cpu_get_real_ticks();
cpu_clock_offset -= get_clock();
cpu_ticks_enabled = 1;
}
}
/* disable cpu_get_ticks() : the clock is stopped. You must not call
cpu_get_ticks() after that. */
void cpu_disable_ticks(void)
{
if (cpu_ticks_enabled) {
cpu_ticks_offset = cpu_get_ticks();
cpu_clock_offset = cpu_get_clock();
cpu_ticks_enabled = 0;
}
}
/***********************************************************/
/* timers */
#define QEMU_TIMER_REALTIME 0
#define QEMU_TIMER_VIRTUAL 1
struct QEMUClock {
int type;
/* XXX: add frequency */
};
struct QEMUTimer {
QEMUClock *clock;
int64_t expire_time;
QEMUTimerCB *cb;
void *opaque;
struct QEMUTimer *next;
};
QEMUClock *rt_clock;
QEMUClock *vm_clock;
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;
#endif
QEMUClock *qemu_new_clock(int type)
{
QEMUClock *clock;
clock = qemu_mallocz(sizeof(QEMUClock));
if (!clock)
return NULL;
clock->type = type;
return clock;
}
QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque)
{
QEMUTimer *ts;
ts = qemu_mallocz(sizeof(QEMUTimer));
ts->clock = clock;
ts->cb = cb;
ts->opaque = opaque;
return ts;
}
void qemu_free_timer(QEMUTimer *ts)
{
qemu_free(ts);
}
/* stop a timer, but do not dealloc it */
void qemu_del_timer(QEMUTimer *ts)
{
QEMUTimer **pt, *t;
/* NOTE: this code must be signal safe because
qemu_timer_expired() can be called from a signal. */
pt = &active_timers[ts->clock->type];
for(;;) {
t = *pt;
if (!t)
break;
if (t == ts) {
*pt = t->next;
break;
}
pt = &t->next;
}
}
void qemu_advance_timer(QEMUTimer *ts, int64_t expire_time)
{
if (ts->expire_time > expire_time || !qemu_timer_pending(ts))
qemu_mod_timer(ts, expire_time);
}
/* modify the current timer so that it will be fired when current_time
>= expire_time. The corresponding callback will be called. */
void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
{
QEMUTimer **pt, *t;
qemu_del_timer(ts);
/* add the timer in the sorted list */
/* NOTE: this code must be signal safe because
qemu_timer_expired() can be called from a signal. */
pt = &active_timers[ts->clock->type];
for(;;) {
t = *pt;
if (!t)
break;
if (t->expire_time > expire_time)
break;
pt = &t->next;
}
ts->expire_time = expire_time;
ts->next = *pt;
*pt = ts;
}
int qemu_timer_pending(QEMUTimer *ts)
{
QEMUTimer *t;
for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) {
if (t == ts)
return 1;
}
return 0;
}
static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
{
if (!timer_head)
return 0;
return (timer_head->expire_time <= current_time);
}
static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time)
{
QEMUTimer *ts;
for(;;) {
ts = *ptimer_head;
if (!ts || ts->expire_time > current_time)
break;
/* remove timer from the list before calling the callback */
*ptimer_head = ts->next;
ts->next = NULL;
/* run the callback (the timer list can be modified) */
ts->cb(ts->opaque);
}
}
int64_t qemu_get_clock(QEMUClock *clock)
{
switch(clock->type) {
case QEMU_TIMER_REALTIME:
return get_clock() / 1000000;
default:
case QEMU_TIMER_VIRTUAL:
return cpu_get_clock();
}
}
static void init_timers(void)
{
init_get_clock();
ticks_per_sec = QEMU_TIMER_BASE;
rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
}
/* save a timer */
void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
{
uint64_t expire_time;
if (qemu_timer_pending(ts)) {
expire_time = ts->expire_time;
} else {
expire_time = -1;
}
qemu_put_be64(f, expire_time);
}
void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
{
uint64_t expire_time;
expire_time = qemu_get_be64(f);
if (expire_time != -1) {
qemu_mod_timer(ts, expire_time);
} else {
qemu_del_timer(ts);
}
}
#ifdef CONFIG_DM
static void timer_save(QEMUFile *f, void *opaque)
{
/* need timer for save/restoe qemu_timer in usb_uhci */
if (cpu_ticks_enabled) {
hw_error("cannot save state if virtual timers are running");
}
qemu_put_be64s(f, &cpu_clock_offset);
}
static int timer_load(QEMUFile *f, void *opaque, int version_id)
{
if (version_id != 1)
return -EINVAL;
if (cpu_ticks_enabled) {
return -EINVAL;
}
qemu_get_be64s(f, &cpu_clock_offset);
return 0;
}
#else /* !CONFIG_DM */
static void timer_save(QEMUFile *f, void *opaque)
{
if (cpu_ticks_enabled) {
hw_error("cannot save state if virtual timers are running");
}
qemu_put_be64s(f, &cpu_ticks_offset);
qemu_put_be64s(f, &ticks_per_sec);
qemu_put_be64s(f, &cpu_clock_offset);
}
static int timer_load(QEMUFile *f, void *opaque, int version_id)
{
if (version_id != 1 && version_id != 2)
return -EINVAL;
if (cpu_ticks_enabled) {
return -EINVAL;
}
qemu_get_be64s(f, &cpu_ticks_offset);
qemu_get_be64s(f, &ticks_per_sec);
if (version_id == 2) {
qemu_get_be64s(f, &cpu_clock_offset);
}
return 0;
}
#ifdef _WIN32
void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
#else
static void host_alarm_handler(int host_signum)
#endif
{
#if 0
#define DISP_FREQ 1000
{
static int64_t delta_min = INT64_MAX;
static int64_t delta_max, delta_cum, last_clock, delta, ti;
static int count;
ti = qemu_get_clock(vm_clock);
if (last_clock != 0) {
delta = ti - last_clock;
if (delta < delta_min)
delta_min = delta;
if (delta > delta_max)
delta_max = delta;
delta_cum += delta;
if (++count == DISP_FREQ) {
printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n",
muldiv64(delta_min, 1000000, ticks_per_sec),
muldiv64(delta_max, 1000000, ticks_per_sec),
muldiv64(delta_cum, 1000000 / DISP_FREQ, ticks_per_sec),
(double)ticks_per_sec / ((double)delta_cum / DISP_FREQ));
count = 0;
delta_min = INT64_MAX;
delta_max = 0;
delta_cum = 0;
}
}
last_clock = ti;
}
#endif
if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
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 */
cpu_interrupt(env, CPU_INTERRUPT_EXIT);
#ifdef USE_KQEMU
if (env->kqemu_enabled) {
kqemu_cpu_interrupt(env);
}
#endif
}
}
}
#ifndef _WIN32
#if defined(__linux__)
#define RTC_FREQ 1024
static int rtc_fd;
static int start_rtc_timer(void)
{
rtc_fd = open("/dev/rtc", O_RDONLY);
if (rtc_fd < 0)
return -1;
if (ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {
fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n"
"error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n"
"type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n");
goto fail;
}
if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) {
fail:
close(rtc_fd);
return -1;
}
pit_min_timer_count = PIT_FREQ / RTC_FREQ;
return 0;
}
#else
static int start_rtc_timer(void)
{
return -1;
}
#endif /* !defined(__linux__) */
#endif /* !defined(_WIN32) */
#endif /* !CONFIG_DM */
static void init_timer_alarm(void)
{
#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)
period, // resolution
host_alarm_handler, // function
(DWORD)&count, // user parameter
TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
if( !timerID ) {
perror("failed timer alarm");
exit(1);
}
host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!host_alarm) {
perror("failed CreateEvent");
exit(1);
}
qemu_add_wait_object(host_alarm, NULL, NULL);
}
pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000;
#else
{
#ifndef CONFIG_DM
struct sigaction act;
struct itimerval itv;
#endif
/* get times() syscall frequency */
timer_freq = sysconf(_SC_CLK_TCK);
#ifndef CONFIG_DM
/* timer signal */
sigfillset(&act.sa_mask);
act.sa_flags = 0;
#if defined (TARGET_I386) && defined(USE_CODE_COPY)
act.sa_flags |= SA_ONSTACK;
#endif
act.sa_handler = host_alarm_handler;
sigaction(SIGALRM, &act, NULL);
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 10 * 1000;
setitimer(ITIMER_REAL, &itv, NULL);
/* we probe the tick duration of the kernel to inform the user if
the emulated kernel requested a too high timer frequency */
getitimer(ITIMER_REAL, &itv);
#if defined(__linux__)
/* 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;
/* disable itimer */
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itv, NULL);
/* use the RTC */
sigaction(SIGIO, &act, NULL);
fcntl(rtc_fd, F_SETFL, O_ASYNC);
fcntl(rtc_fd, F_SETOWN, getpid());
} else
#endif /* defined(__linux__) */
{
use_itimer:
pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec *
PIT_FREQ) / 1000000;
}
#endif /* CONFIG_DM */
}
#endif
}
void quit_timers(void)
{
#ifdef _WIN32
timeKillEvent(timerID);
timeEndPeriod(period);
if (host_alarm) {
CloseHandle(host_alarm);
host_alarm = NULL;
}
#endif
}
/***********************************************************/
/* character device */
static void qemu_chr_event(CharDriverState *s, int event)
{
if (!s->chr_event)
return;
s->chr_event(s->handler_opaque, event);
}
static void qemu_chr_reset_bh(void *opaque)
{
CharDriverState *s = opaque;
qemu_chr_event(s, CHR_EVENT_RESET);
qemu_bh_delete(s->bh);
s->bh = NULL;
}
void qemu_chr_reset(CharDriverState *s)
{
if (s->bh == NULL) {
s->bh = qemu_bh_new(qemu_chr_reset_bh, s);
qemu_bh_schedule(s->bh);
}
}
int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
{
return s->chr_write(s, buf, len);
}
int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)
{
if (!s->chr_ioctl)
return -ENOTSUP;
return s->chr_ioctl(s, cmd, arg);
}
int qemu_chr_can_read(CharDriverState *s)
{
if (!s->chr_can_read)
return 0;
return s->chr_can_read(s->handler_opaque);
}
void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
{
s->chr_read(s->handler_opaque, buf, len);
}
void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
{
char buf[4096];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
qemu_chr_write(s, buf, strlen(buf));
va_end(ap);
}
void qemu_chr_send_event(CharDriverState *s, int event)
{
if (s->chr_send_event)
s->chr_send_event(s, event);
}
void qemu_chr_add_handlers(CharDriverState *s,
IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read,
IOEventHandler *fd_event,
void *opaque)
{
s->chr_can_read = fd_can_read;
s->chr_read = fd_read;
s->chr_event = fd_event;
s->handler_opaque = opaque;
if (s->chr_update_read_handler)
s->chr_update_read_handler(s);
}
static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
return len;
}
static CharDriverState *qemu_chr_open_null(void)
{
CharDriverState *chr;
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
chr->chr_write = null_chr_write;
return chr;
}
#ifdef _WIN32
static void socket_cleanup(void)
{
WSACleanup();
}
static int socket_init(void)
{
WSADATA Data;
int ret, err;
ret = WSAStartup(MAKEWORD(2,2), &Data);
if (ret != 0) {
err = WSAGetLastError();
fprintf(stderr, "WSAStartup: %d\n", err);
return -1;
}
atexit(socket_cleanup);
return 0;
}
static int send_all(int fd, const uint8_t *buf, int len1)
{
int ret, len;
len = len1;
while (len > 0) {
ret = send(fd, buf, len, 0);
if (ret < 0) {
int errno;
errno = WSAGetLastError();
if (errno != WSAEWOULDBLOCK) {
return -1;
}
} else if (ret == 0) {
break;
} else {
buf += ret;
len -= ret;
}
}
return len1 - len;
}
void socket_set_nonblock(int fd)
{
unsigned long opt = 1;
ioctlsocket(fd, FIONBIO, &opt);
}
#else
static int unix_write(int fd, const uint8_t *buf, int len1)
{
int ret, sel_ret, len;
int max_fd;
fd_set writefds;
struct timeval timeout;
max_fd = fd;
len = len1;
while (len > 0) {
FD_ZERO(&writefds);
FD_SET(fd, &writefds);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
sel_ret = select(max_fd + 1, NULL, &writefds, 0, &timeout);
if (sel_ret <= 0) {
/* Timeout or select error */
return -1;
} else {
ret = write(fd, buf, len);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return -1;
} else if (ret == 0) {
break;
} else {
buf += ret;
len -= ret;
}
}
}
return len1 - len;
}
static inline int send_all(int fd, const uint8_t *buf, int len1)
{
return unix_write(fd, buf, len1);
}
void socket_set_nonblock(int fd)
{
fcntl(fd, F_SETFL, O_NONBLOCK);
}
#endif /* !_WIN32 */
#ifndef _WIN32
typedef struct {
int fd_in, fd_out;
int max_size;
} FDCharDriver;
#define STDIO_MAX_CLIENTS 2
static int stdio_nb_clients;
static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
FDCharDriver *s = chr->opaque;
return unix_write(s->fd_out, buf, len);
}
static int fd_chr_read_poll(void *opaque)
{
CharDriverState *chr = opaque;
FDCharDriver *s = chr->opaque;
s->max_size = qemu_chr_can_read(chr);
return s->max_size;
}
static void fd_chr_read(void *opaque)
{
CharDriverState *chr = opaque;
FDCharDriver *s = chr->opaque;
int size, len;
uint8_t buf[1024];
len = sizeof(buf);
if (len > s->max_size)
len = s->max_size;
if (len == 0)
return;
size = read(s->fd_in, buf, len);
if (size == 0) {
/* FD has been closed. Remove it from the active list. */
qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
return;
}
if (size > 0) {
qemu_chr_read(chr, buf, size);
}
}
static void fd_chr_update_read_handler(CharDriverState *chr)
{
FDCharDriver *s = chr->opaque;
if (s->fd_in >= 0) {
if (nographic && s->fd_in == 0) {
} else {
qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
fd_chr_read, NULL, chr);
}
}
}
/* open a character device to a unix fd */
static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
{
CharDriverState *chr;
FDCharDriver *s;
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
s = qemu_mallocz(sizeof(FDCharDriver));
if (!s) {
free(chr);
return NULL;
}
s->fd_in = fd_in;
s->fd_out = fd_out;
chr->opaque = s;
chr->chr_write = fd_chr_write;
chr->chr_update_read_handler = fd_chr_update_read_handler;
qemu_chr_reset(chr);
return chr;
}
static CharDriverState *qemu_chr_open_file_out(const char *file_out)
{
int fd_out;
fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666);
if (fd_out < 0)
return NULL;
return qemu_chr_open_fd(-1, fd_out);
}
static CharDriverState *qemu_chr_open_pipe(const char *filename)
{
int fd_in, fd_out;
char filename_in[256], filename_out[256];
snprintf(filename_in, 256, "%s.in", filename);
snprintf(filename_out, 256, "%s.out", filename);
fd_in = open(filename_in, O_RDWR | O_BINARY);
fd_out = open(filename_out, O_RDWR | O_BINARY);
if (fd_in < 0 || fd_out < 0) {
if (fd_in >= 0)
close(fd_in);
if (fd_out >= 0)
close(fd_out);
fd_in = fd_out = open(filename, O_RDWR | O_BINARY);
if (fd_in < 0)
return NULL;
}
return qemu_chr_open_fd(fd_in, fd_out);
}
/* for STDIO, we handle the case where several clients use it
(nographic mode) */
#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
#define TERM_FIFO_MAX_SIZE 1
static int term_got_escape, client_index;
static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
static int term_fifo_size;
static int term_timestamps;
static int64_t term_timestamps_start;
void term_print_help(void)
{
printf("\n"
"C-a h print this help\n"
"C-a x exit emulator\n"
"C-a s save disk data back to file (if -snapshot)\n"
"C-a b send break (magic sysrq)\n"
"C-a t toggle console timestamps\n"
"C-a c switch between console and monitor\n"
"C-a C-a send C-a\n"
);
}
/* called when a char is received */
static void stdio_received_byte(int ch)
{
if (term_got_escape) {
term_got_escape = 0;
switch(ch) {
case 'h':
term_print_help();
break;
case 'x':
exit(0);
break;
case 's':
{
int i;
for (i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++) {
if (bs_table[i])
bdrv_commit(bs_table[i]);
}
}
break;
case 'b':
if (client_index < stdio_nb_clients) {
CharDriverState *chr;
FDCharDriver *s;
chr = stdio_clients[client_index];
s = chr->opaque;
qemu_chr_event(chr, CHR_EVENT_BREAK);
}
break;
case 'c':
client_index++;
if (client_index >= stdio_nb_clients)
client_index = 0;
if (client_index == 0) {
/* send a new line in the monitor to get the prompt */
ch = '\r';
goto send_char;
}
break;
case 't':
term_timestamps = !term_timestamps;
term_timestamps_start = -1;
break;
case TERM_ESCAPE:
goto send_char;
}
} else if (ch == TERM_ESCAPE) {
term_got_escape = 1;
} else {
send_char:
if (client_index < stdio_nb_clients) {
uint8_t buf[1];
CharDriverState *chr;
chr = stdio_clients[client_index];
if (qemu_chr_can_read(chr) > 0) {
buf[0] = ch;
qemu_chr_read(chr, buf, 1);
} else if (term_fifo_size == 0) {
term_fifo[term_fifo_size++] = ch;
}
}
}
}
static int stdio_read_poll(void *opaque)
{
CharDriverState *chr;
if (client_index < stdio_nb_clients) {
chr = stdio_clients[client_index];
/* try to flush the queue if needed */
if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
qemu_chr_read(chr, term_fifo, 1);
term_fifo_size = 0;
}
/* see if we can absorb more chars */
if (term_fifo_size == 0)
return 1;
else
return 0;
} else {
return 1;
}
}
static void stdio_read(void *opaque)
{
int size;
uint8_t buf[1];
size = read(0, buf, 1);
if (size == 0) {
/* stdin has been closed. Remove it from the active list. */
qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
return;
}
if (size > 0)
stdio_received_byte(buf[0]);
}
static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
{
FDCharDriver *s = chr->opaque;
if (!term_timestamps) {
return unix_write(s->fd_out, buf, len);
} else {
int i;
char buf1[64];
for(i = 0; i < len; i++) {
unix_write(s->fd_out, buf + i, 1);
if (buf[i] == '\n') {
int64_t ti;
int secs;
ti = get_clock();
if (term_timestamps_start == -1)
term_timestamps_start = ti;
ti -= term_timestamps_start;
secs = ti / 1000000000;
snprintf(buf1, sizeof(buf1),
"[%02d:%02d:%02d.%03d] ",
secs / 3600,
(secs / 60) % 60,
secs % 60,
(int)((ti / 1000000) % 1000));
unix_write(s->fd_out, buf1, strlen(buf1));
}
}
return len;
}
}
/* init terminal so that we can grab keys */
static struct termios oldtty;
static int old_fd0_flags;
static void term_exit(void)
{
tcsetattr (0, TCSANOW, &oldtty);
fcntl(0, F_SETFL, old_fd0_flags);
}
static void term_init(void)
{
struct termios tty;
tcgetattr (0, &tty);
oldtty = tty;
old_fd0_flags = fcntl(0, F_GETFL);
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|INLCR|IGNCR|ICRNL|IXON);
tty.c_oflag |= OPOST;
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
/* if graphical mode, we allow Ctrl-C handling */
if (nographic)
tty.c_lflag &= ~ISIG;
tty.c_cflag &= ~(CSIZE|PARENB);
tty.c_cflag |= CS8;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
tcsetattr (0, TCSANOW, &tty);
atexit(term_exit);
fcntl(0, F_SETFL, O_NONBLOCK);
}
static CharDriverState *qemu_chr_open_stdio(void)
{
CharDriverState *chr;
if (nographic) {
if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
return NULL;
chr = qemu_chr_open_fd(0, 1);
chr->chr_write = stdio_write;
if (stdio_nb_clients == 0)
qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL);
client_index = stdio_nb_clients;
} else {
if (stdio_nb_clients != 0)
return NULL;
chr = qemu_chr_open_fd(0, 1);
}
stdio_clients[stdio_nb_clients++] = chr;
if (stdio_nb_clients == 1) {
/* set the terminal in raw mode */
term_init();
}
return chr;
}
/*
* Create a store entry for a device (e.g., monitor, serial/parallel lines).
* The entry is <domain-path><storeString>/tty and the value is the name
* of the pty associated with the device.
*/
static int store_dev_info(char *devName, int domid,
CharDriverState *cState, char *storeString)
{
int xc_handle;
struct xs_handle *xs;
char *path;
char *newpath;
FDCharDriver *s;
char *pts;
/* Check for valid arguments (at least, prevent segfaults). */
if ((devName == NULL) || (cState == NULL) || (storeString == NULL)) {
fprintf(logfile, "%s - invalid arguments\n", __FUNCTION__);
return EINVAL;
}
/*
* Only continue if we're talking to a pty
* Actually, the following code works for any CharDriverState using
* FDCharDriver, but we really only care about pty's here
*/
if (strcmp(devName, "pty"))
return 0;
s = cState->opaque;
if (s == NULL) {
fprintf(logfile, "%s - unable to retrieve fd for '%s'/'%s'\n",
__FUNCTION__, storeString, devName);
return EBADF;
}
pts = ptsname(s->fd_in);
if (pts == NULL) {
fprintf(logfile, "%s - unable to determine ptsname '%s'/'%s', "
"error %d (%s)\n",
__FUNCTION__, storeString, devName, errno, strerror(errno));
return errno;
}
/* We now have everything we need to set the xenstore entry. */
xs = xs_daemon_open();
if (xs == NULL) {
fprintf(logfile, "Could not contact XenStore\n");
return -1;
}
xc_handle = xc_interface_open();
if (xc_handle == -1) {
fprintf(logfile, "xc_interface_open() error\n");
return -1;
}
path = xs_get_domain_path(xs, domid);
if (path == NULL) {
fprintf(logfile, "xs_get_domain_path() error\n");
return -1;
}
newpath = realloc(path, (strlen(path) + strlen(storeString) +
strlen("/tty") + 1));
if (newpath == NULL) {
free(path); /* realloc errors leave old block */
fprintf(logfile, "realloc error\n");
return -1;
}
path = newpath;
strcat(path, storeString);
strcat(path, "/tty");
if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) {
fprintf(logfile, "xs_write for '%s' fail", storeString);
return -1;
}
free(path);
xs_daemon_close(xs);
close(xc_handle);
return 0;
}
#if defined(__linux__)
static CharDriverState *qemu_chr_open_pty(void)
{
struct termios tty;
int master_fd, slave_fd;
/* Not satisfying */
if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) < 0) {
return NULL;
}
/* Set raw attributes on the pty. */
cfmakeraw(&tty);
tcsetattr(slave_fd, TCSAFLUSH, &tty);
fprintf(stderr, "char device redirected to %s\n", ptsname(master_fd));
return qemu_chr_open_fd(master_fd, master_fd);
}
static void tty_serial_init(int fd, int speed,
int parity, int data_bits, int stop_bits)
{
struct termios tty;
speed_t spd;
#if 0
printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
speed, parity, data_bits, stop_bits);
#endif
tcgetattr (fd, &tty);
switch(speed) {
case 50:
spd = B50;
break;
case 75:
spd = B75;
break;
case 300:
spd = B300;
break;
case 600:
spd = B600;
break;
case 1200:
spd = B1200;
break;
case 2400:
spd = B2400;
break;
case 4800:
spd = B4800;
break;
case 9600:
spd = B9600;
break;
case 19200:
spd = B19200;
break;
case 38400:
spd = B38400;
break;
case 57600:
spd = B57600;
break;
default:
case 115200:
spd = B115200;
break;
}
cfsetispeed(&tty, spd);
cfsetospeed(&tty, spd);
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|INLCR|IGNCR|ICRNL|IXON);
tty.c_oflag &= ~OPOST; /* no output mangling of raw serial stream */
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB);
switch(data_bits) {
default:
case 8:
tty.c_cflag |= CS8;
break;
case 7:
tty.c_cflag |= CS7;
break;
case 6:
tty.c_cflag |= CS6;
break;
case 5:
tty.c_cflag |= CS5;
break;
}
switch(parity) {
default:
case 'N':
break;
case 'E':
tty.c_cflag |= PARENB;
break;
case 'O':
tty.c_cflag |= PARENB | PARODD;
break;
}
if (stop_bits == 2)
tty.c_cflag |= CSTOPB;
tcsetattr (fd, TCSANOW, &tty);
}
static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
{
FDCharDriver *s = chr->opaque;
switch(cmd) {
case CHR_IOCTL_SERIAL_SET_PARAMS:
{
QEMUSerialSetParams *ssp = arg;
tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
ssp->data_bits, ssp->stop_bits);
}
break;
case CHR_IOCTL_SERIAL_SET_BREAK:
{
int enable = *(int *)arg;
if (enable)
tcsendbreak(s->fd_in, 1);
}
break;
default:
return -ENOTSUP;
}
return 0;
}
static CharDriverState *qemu_chr_open_tty(const char *filename)
{
CharDriverState *chr;
int fd;
fd = open(filename, O_RDWR | O_NONBLOCK);
if (fd < 0)
return NULL;
fcntl(fd, F_SETFL, O_NONBLOCK);
tty_serial_init(fd, 115200, 'N', 8, 1);
chr = qemu_chr_open_fd(fd, fd);
if (!chr)
return NULL;
chr->chr_ioctl = tty_serial_ioctl;
qemu_chr_reset(chr);
return chr;
}
static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
{
int fd = (int)chr->opaque;
uint8_t b;
switch(cmd) {
case CHR_IOCTL_PP_READ_DATA:
if (ioctl(fd, PPRDATA, &b) < 0)
return -ENOTSUP;
*(uint8_t *)arg = b;
break;
case CHR_IOCTL_PP_WRITE_DATA:
b = *(uint8_t *)arg;
if (ioctl(fd, PPWDATA, &b) < 0)
return -ENOTSUP;
break;
case CHR_IOCTL_PP_READ_CONTROL:
if (ioctl(fd, PPRCONTROL, &b) < 0)
return -ENOTSUP;
*(uint8_t *)arg = b;
break;
case CHR_IOCTL_PP_WRITE_CONTROL:
b = *(uint8_t *)arg;
if (ioctl(fd, PPWCONTROL, &b) < 0)
return -ENOTSUP;
break;
case CHR_IOCTL_PP_READ_STATUS:
if (ioctl(fd, PPRSTATUS, &b) < 0)
return -ENOTSUP;
*(uint8_t *)arg = b;
break;
default:
return -ENOTSUP;
}
return 0;
}
static CharDriverState *qemu_chr_open_pp(const char *filename)
{
CharDriverState *chr;
int fd;
fd = open(filename, O_RDWR);
if (fd < 0)
return NULL;
if (ioctl(fd, PPCLAIM) < 0) {
close(fd);
return NULL;
}
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr) {
close(fd);
return NULL;
}
chr->opaque = (void *)fd;
chr->chr_write = null_chr_write;
chr->chr_ioctl = pp_ioctl;
qemu_chr_reset(chr);
return chr;
}
#else
static CharDriverState *qemu_chr_open_pty(void)
{
return NULL;
}
#endif
#endif /* !defined(_WIN32) */
#ifdef _WIN32
typedef struct {
CharDriverState *chr;
int max_size;
HANDLE hcom, hrecv, hsend;
OVERLAPPED orecv, osend;
BOOL fpipe;
DWORD len;
} WinCharState;
#define NSENDBUF 2048
#define NRECVBUF 2048
#define MAXCONNECT 1
#define NTIMEOUT 5000
static int win_chr_poll(void *opaque);
static int win_chr_pipe_poll(void *opaque);
static void win_chr_close2(WinCharState *s)
{
if (s->hsend) {
CloseHandle(s->hsend);
s->hsend = NULL;
}
if (s->hrecv) {