blob: e6a0305c65d975554caee4b8ec065aeda2118e45 [file] [log] [blame]
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 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.
*/
/* the following is needed on Linux to define ptsname() in stdlib.h */
#if defined(__linux__)
#define _GNU_SOURCE 1
#endif
#include "qemu-common.h"
#include "hw/hw.h"
#include "hw/boards.h"
#include "hw/usb.h"
#include "hw/pcmcia.h"
#include "hw/pc.h"
#include "hw/audiodev.h"
#include "hw/isa.h"
#include "hw/baum.h"
#include "net.h"
#include "console.h"
#include "sysemu.h"
#include "gdbstub.h"
#include "qemu-timer.h"
#include "qemu-char.h"
#include "block.h"
#include "audio/audio.h"
#include "qemu_file.h"
#include "android/android.h"
#include "charpipe.h"
#include "shaper.h"
#include "modem_driver.h"
#include "android/gps.h"
#include "android/hw-qemud.h"
#include "android/hw-kmsg.h"
#include "tcpdump.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 <dirent.h>
#include <netdb.h>
#include <sys/select.h>
#include <arpa/inet.h>
#ifdef _BSD
#include <sys/stat.h>
#if !defined(__APPLE__) && !defined(__OpenBSD__)
#include <libutil.h>
#endif
#ifdef __OpenBSD__
#include <net/if.h>
#endif
#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
#include <freebsd/stdlib.h>
#else
#ifndef __sun__
#include <linux/if.h>
#include <linux/if_tun.h>
#include <pty.h>
#include <malloc.h>
#include <linux/rtc.h>
/* For the benefit of older linux systems which don't supply it,
we use a local copy of hpet.h. */
/* #include <linux/hpet.h> */
#include "hpet.h"
#include <linux/ppdev.h>
#include <linux/parport.h>
#else
#include <sys/stat.h>
#include <sys/ethernet.h>
#include <sys/sockio.h>
#include <netinet/arp.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h> // must come after ip.h
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <syslog.h>
#include <stropts.h>
#endif
#endif
#endif
#include "qemu_socket.h"
#if defined(CONFIG_SLIRP)
#include "libslirp.h"
#endif
#if defined(__OpenBSD__)
#include <util.h>
#endif
#if defined(CONFIG_VDE)
#include <libvdeplug.h>
#endif
#ifdef _WIN32
#include <malloc.h>
#include <sys/timeb.h>
#include <mmsystem.h>
#define getopt_long_only getopt_long
#define memalign(align, size) malloc(size)
#endif
#ifdef CONFIG_COCOA
#undef main
#define main qemu_main
#endif /* CONFIG_COCOA */
#ifdef CONFIG_SKINS
#undef main
#define main qemu_main
#endif
#include "disas.h"
#include "exec-all.h"
#ifdef CONFIG_TRACE
#include "trace.h"
#include "dcache.h"
#endif
#ifdef CONFIG_NAND
#include "hw/goldfish_nand.h"
#endif
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
#ifdef __sun__
#define SMBD_COMMAND "/usr/sfw/sbin/smbd"
#else
#define SMBD_COMMAND "/usr/sbin/smbd"
#endif
//#define DEBUG_UNUSED_IOPORT
//#define DEBUG_IOPORT
#ifdef TARGET_PPC
#define DEFAULT_RAM_SIZE 144
#else
#define DEFAULT_RAM_SIZE 128
#endif
/* 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;
const char *bios_name = NULL;
void *ioport_opaque[MAX_IOPORTS];
IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
/* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
to store the VM snapshots */
DriveInfo drives_table[MAX_DRIVES+1];
int nb_drives;
/* point to the block driver where the snapshots are managed */
BlockDriverState *bs_snapshots;
int vga_ram_size;
static DisplayState display_state;
int nographic;
int curses;
const char* keyboard_layout = NULL;
int64_t ticks_per_sec;
ram_addr_t ram_size;
int pit_min_timer_count = 0;
int nb_nics;
NICInfo nd_table[MAX_NICS];
int vm_running;
static int rtc_utc = 1;
static int rtc_date_offset = -1; /* -1 means no change */
int cirrus_vga_enabled = 1;
int vmsvga_enabled = 0;
#ifdef TARGET_SPARC
int graphic_width = 1024;
int graphic_height = 768;
int graphic_depth = 8;
#else
int graphic_width = 800;
int graphic_height = 600;
int graphic_depth = 15;
#endif
int full_screen = 0;
int no_frame = 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 = 1;
int fd_bootchk = 1;
int no_reboot = 0;
int no_shutdown = 0;
int cursor_hide = 1;
int graphic_rotate = 0;
int daemonize = 0;
const char *option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
int semihosting_enabled = 0;
int autostart = 1;
#ifdef TARGET_ARM
int old_param = 0;
#endif
const char *qemu_name;
int alt_grab = 0;
#ifdef TARGET_SPARC
unsigned int nb_prom_envs = 0;
const char *prom_envs[MAX_PROM_ENVS];
#endif
int nb_drives_opt;
struct drive_opt {
const char *file;
char opt[1024];
} drives_opt[MAX_DRIVES];
static CPUState *cur_cpu;
static CPUState *next_cpu;
static int event_pending = 1;
/* Conversion factor from emulated instructions to virtual clock ticks. */
static int icount_time_shift;
/* Arbitrarily pick 1MIPS as the minimum allowable speed. */
#define MAX_ICOUNT_SHIFT 10
/* Compensate for varying guest execution speed. */
static int64_t qemu_icount_bias;
QEMUTimer *icount_rt_timer;
QEMUTimer *icount_vm_timer;
extern int qemu_cpu_delay;
extern char* audio_input_source;
extern void dprint( const char* format, ... );
#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
/***********************************************************/
/* x86 ISA bus support */
target_phys_addr_t isa_mem_base = 0;
PicState2 *isa_pic;
static IOPortReadFunc default_ioport_readb, default_ioport_readw, default_ioport_readl;
static IOPortWriteFunc default_ioport_writeb, default_ioport_writew, default_ioport_writel;
static uint32_t ioport_read(int index, uint32_t address)
{
static IOPortReadFunc *default_func[3] = {
default_ioport_readb,
default_ioport_readw,
default_ioport_readl
};
IOPortReadFunc *func = ioport_read_table[index][address];
if (!func)
func = default_func[index];
return func(ioport_opaque[address], address);
}
static void ioport_write(int index, uint32_t address, uint32_t data)
{
static IOPortWriteFunc *default_func[3] = {
default_ioport_writeb,
default_ioport_writew,
default_ioport_writel
};
IOPortWriteFunc *func = ioport_write_table[index][address];
if (!func)
func = default_func[index];
func(ioport_opaque[address], address, data);
}
static uint32_t default_ioport_readb(void *opaque, uint32_t address)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "unused inb: port=0x%04x\n", address);
#endif
return 0xff;
}
static void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "unused outb: port=0x%04x data=0x%02x\n", address, data);
#endif
}
/* default is to make two byte accesses */
static uint32_t default_ioport_readw(void *opaque, uint32_t address)
{
uint32_t data;
data = ioport_read(0, address);
address = (address + 1) & (MAX_IOPORTS - 1);
data |= ioport_read(0, address) << 8;
return data;
}
static void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
{
ioport_write(0, address, data & 0xff);
address = (address + 1) & (MAX_IOPORTS - 1);
ioport_write(0, address, (data >> 8) & 0xff);
}
static uint32_t default_ioport_readl(void *opaque, uint32_t address)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "unused inl: port=0x%04x\n", address);
#endif
return 0xffffffff;
}
static void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "unused outl: port=0x%04x data=0x%02x\n", address, data);
#endif
}
/* 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_read: 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(0, 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(1, 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(2, 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(0, 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(1, 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(2, 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;
CPUState *env;
va_start(ap, fmt);
fprintf(stderr, "qemu: hardware error: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
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
}
va_end(ap);
abort();
}
/***********************************************************/
/* keyboard/mouse */
static QEMUPutKBDEvent* qemu_put_kbd_event;
static void* qemu_put_kbd_event_opaque;
static QEMUPutKBDEventN* qemu_put_kbd_event_n;
static void* qemu_put_kbd_event_n_opaque;
static QEMUPutGenericEvent* qemu_put_generic_event;
static void* qemu_put_generic_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;
}
void qemu_add_kbd_event_n_handler(QEMUPutKBDEventN *func, void *opaque)
{
qemu_put_kbd_event_n_opaque = opaque;
qemu_put_kbd_event_n = func;
}
#if 0
void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute)
{
qemu_put_mouse_event_opaque = opaque;
qemu_put_mouse_event = func;
qemu_put_mouse_event_absolute = absolute;
}
#else
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);
}
#endif
void qemu_add_generic_event_handler(QEMUPutGenericEvent *func, void* opaque)
{
qemu_put_generic_event = func;
qemu_put_generic_event_opaque = opaque;
}
void kbd_put_keycode(int keycode)
{
if (qemu_put_kbd_event) {
qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode);
}
}
void kbd_put_keycodes(int* keycodes, int count)
{
if (qemu_put_kbd_event_n)
{
qemu_put_kbd_event_n(qemu_put_kbd_event_n_opaque, keycodes, count);
}
else if (qemu_put_kbd_event)
{
int nn;
for (nn = 0; nn < count; nn++)
qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycodes[nn]);
}
}
void kbd_generic_event(int type, int code, int value)
{
if (qemu_put_generic_event)
qemu_put_generic_event(qemu_put_generic_event_opaque, type, code, value);
}
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
{
QEMUPutMouseEvent *mouse_event;
void *mouse_event_opaque;
int width;
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) {
if (graphic_rotate) {
if (qemu_put_mouse_event_current->qemu_put_mouse_event_absolute)
width = 0x7fff;
else
width = graphic_width - 1;
mouse_event(mouse_event_opaque,
width - dy, dx, dz, buttons_state);
} else
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
/* Return the virtual CPU time, based on the instruction counter. */
static int64_t cpu_get_icount(void)
{
int64_t icount;
CPUState *env = cpu_single_env;;
icount = qemu_icount;
if (env) {
if (!can_do_io(env))
fprintf(stderr, "Bad clock read\n");
icount -= (env->icount_decr.u16.low + env->icount_extra);
}
return qemu_icount_bias + (icount << icount_time_shift);
}
/***********************************************************/
/* 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 (use_icount) {
return cpu_get_icount();
}
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;
};
struct qemu_alarm_timer {
char const *name;
unsigned int flags;
int (*start)(struct qemu_alarm_timer *t);
void (*stop)(struct qemu_alarm_timer *t);
void (*rearm)(struct qemu_alarm_timer *t);
void *priv;
};
#define ALARM_FLAG_DYNTICKS 0x1
#define ALARM_FLAG_EXPIRED 0x2
static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
{
return t->flags & ALARM_FLAG_DYNTICKS;
}
static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
{
if (!alarm_has_dynticks(t))
return;
t->rearm(t);
}
/* TODO: MIN_TIMER_REARM_US should be optimized */
#define MIN_TIMER_REARM_US 250
static struct qemu_alarm_timer *alarm_timer;
#ifdef _WIN32
struct qemu_alarm_win32 {
MMRESULT timerId;
HANDLE host_alarm;
unsigned int period;
} alarm_win32_data = {0, NULL, -1};
static int win32_start_timer(struct qemu_alarm_timer *t);
static void win32_stop_timer(struct qemu_alarm_timer *t);
static void win32_rearm_timer(struct qemu_alarm_timer *t);
#else
static int unix_start_timer(struct qemu_alarm_timer *t);
static void unix_stop_timer(struct qemu_alarm_timer *t);
#ifdef __linux__
static int dynticks_start_timer(struct qemu_alarm_timer *t);
static void dynticks_stop_timer(struct qemu_alarm_timer *t);
static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
static int hpet_start_timer(struct qemu_alarm_timer *t);
static void hpet_stop_timer(struct qemu_alarm_timer *t);
static int rtc_start_timer(struct qemu_alarm_timer *t);
static void rtc_stop_timer(struct qemu_alarm_timer *t);
#endif /* __linux__ */
#endif /* _WIN32 */
/* Correlation between real and virtual time is always going to be
fairly approximate, so ignore small variation.
When the guest is idle real and virtual time will be aligned in
the IO wait loop. */
#define ICOUNT_WOBBLE (QEMU_TIMER_BASE / 10)
static void icount_adjust(void)
{
int64_t cur_time;
int64_t cur_icount;
int64_t delta;
static int64_t last_delta;
/* If the VM is not running, then do nothing. */
if (!vm_running)
return;
cur_time = cpu_get_clock();
cur_icount = qemu_get_clock(vm_clock);
delta = cur_icount - cur_time;
/* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */
if (delta > 0
&& last_delta + ICOUNT_WOBBLE < delta * 2
&& icount_time_shift > 0) {
/* The guest is getting too far ahead. Slow time down. */
icount_time_shift--;
}
if (delta < 0
&& last_delta - ICOUNT_WOBBLE > delta * 2
&& icount_time_shift < MAX_ICOUNT_SHIFT) {
/* The guest is getting too far behind. Speed time up. */
icount_time_shift++;
}
last_delta = delta;
qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
}
static void icount_adjust_rt(void * opaque)
{
qemu_mod_timer(icount_rt_timer,
qemu_get_clock(rt_clock) + 1000);
icount_adjust();
}
static void icount_adjust_vm(void * opaque)
{
qemu_mod_timer(icount_vm_timer,
qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10);
icount_adjust();
}
static void init_icount_adjust(void)
{
/* Have both realtime and virtual time triggers for speed adjustment.
The realtime trigger catches emulated time passing too slowly,
the virtual time trigger catches emulated time passing too fast.
Realtime triggers occur even when idle, so use them less frequently
than VM triggers. */
icount_rt_timer = qemu_new_timer(rt_clock, icount_adjust_rt, NULL);
qemu_mod_timer(icount_rt_timer,
qemu_get_clock(rt_clock) + 1000);
icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL);
qemu_mod_timer(icount_vm_timer,
qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10);
}
static struct qemu_alarm_timer alarm_timers[] = {
#ifndef _WIN32
#ifdef __linux__
{"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer,
dynticks_stop_timer, dynticks_rearm_timer, NULL},
/* HPET - if available - is preferred */
{"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL},
/* ...otherwise try RTC */
{"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL},
#endif
{"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL},
#else
{"dynticks", ALARM_FLAG_DYNTICKS, win32_start_timer,
win32_stop_timer, win32_rearm_timer, &alarm_win32_data},
{"win32", 0, win32_start_timer,
win32_stop_timer, NULL, &alarm_win32_data},
#endif
{NULL, 0, NULL, NULL, NULL, NULL}
};
static void show_available_alarms(void)
{
int i;
printf("Available alarm timers, in order of precedence:\n");
for (i = 0; alarm_timers[i].name; i++)
printf("%s\n", alarm_timers[i].name);
}
static void configure_alarms(char const *opt)
{
int i;
int cur = 0;
int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1;
char *arg;
char *name;
struct qemu_alarm_timer tmp;
if (!strcmp(opt, "?")) {
show_available_alarms();
exit(0);
}
arg = strdup(opt);
/* Reorder the array */
name = strtok(arg, ",");
while (name) {
for (i = 0; i < count && alarm_timers[i].name; i++) {
if (!strcmp(alarm_timers[i].name, name))
break;
}
if (i == count) {
fprintf(stderr, "Unknown clock %s\n", name);
goto next;
}
if (i < cur)
/* Ignore */
goto next;
/* Swap */
tmp = alarm_timers[i];
alarm_timers[i] = alarm_timers[cur];
alarm_timers[cur] = tmp;
cur++;
next:
name = strtok(NULL, ",");
}
free(arg);
if (cur) {
/* Disable remaining timers */
for (i = cur; i < count; i++)
alarm_timers[i].name = NULL;
} else {
show_available_alarms();
exit(1);
}
}
QEMUClock *rt_clock;
QEMUClock *vm_clock;
static QEMUTimer *active_timers[2];
static 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;
}
}
/* 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;
/* Rearm if necessary */
if (pt == &active_timers[ts->clock->type]) {
if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0) {
qemu_rearm_alarm_timer(alarm_timer);
}
/* Interrupt execution to force deadline recalculation. */
if (use_icount && cpu_single_env) {
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
}
}
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:
if (use_icount) {
return cpu_get_icount();
} else {
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);
}
}
static void timer_save(QEMUFile *f, void *opaque)
{
if (cpu_ticks_enabled) {
hw_error("cannot save state if virtual timers are running");
}
qemu_put_be64(f, cpu_ticks_offset);
qemu_put_be64(f, ticks_per_sec);
qemu_put_be64(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;
}
cpu_ticks_offset=qemu_get_be64(f);
ticks_per_sec=qemu_get_be64(f);
if (version_id == 2) {
cpu_clock_offset=qemu_get_be64(f);
}
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 (alarm_has_dynticks(alarm_timer) ||
(!use_icount &&
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
struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv;
SetEvent(data->host_alarm);
#endif
CPUState *env = next_cpu;
alarm_timer->flags |= ALARM_FLAG_EXPIRED;
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
}
event_pending = 1;
}
}
static int64_t qemu_next_deadline(void)
{
int64_t delta;
if (active_timers[QEMU_TIMER_VIRTUAL]) {
delta = active_timers[QEMU_TIMER_VIRTUAL]->expire_time -
qemu_get_clock(vm_clock);
} else {
/* To avoid problems with overflow limit this to 2^32. */
delta = INT32_MAX;
}
if (delta < 0)
delta = 0;
return delta;
}
#if defined(__linux__) || defined(_WIN32)
static uint64_t qemu_next_deadline_dyntick(void)
{
int64_t delta;
int64_t rtdelta;
if (use_icount)
delta = INT32_MAX;
else
delta = (qemu_next_deadline() + 999) / 1000;
if (active_timers[QEMU_TIMER_REALTIME]) {
rtdelta = (active_timers[QEMU_TIMER_REALTIME]->expire_time -
qemu_get_clock(rt_clock))*1000;
if (rtdelta < delta)
delta = rtdelta;
}
if (delta < MIN_TIMER_REARM_US)
delta = MIN_TIMER_REARM_US;
return delta;
}
#endif
#ifndef _WIN32
#if defined(__linux__)
#define RTC_FREQ 1024
static void enable_sigio_timer(int fd)
{
struct sigaction act;
/* timer signal */
sigfillset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = host_alarm_handler;
sigaction(SIGIO, &act, NULL);
fcntl(fd, F_SETFL, O_ASYNC);
fcntl(fd, F_SETOWN, getpid());
}
static int hpet_start_timer(struct qemu_alarm_timer *t)
{
struct hpet_info info;
int r, fd;
fd = open("/dev/hpet", O_RDONLY);
if (fd < 0)
return -1;
/* Set frequency */
r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ);
if (r < 0) {
fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n"
"error, but for better emulation accuracy type:\n"
"'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n");
goto fail;
}
/* Check capabilities */
r = ioctl(fd, HPET_INFO, &info);
if (r < 0)
goto fail;
/* Enable periodic mode */
r = ioctl(fd, HPET_EPI, 0);
if (info.hi_flags && (r < 0))
goto fail;
/* Enable interrupt */
r = ioctl(fd, HPET_IE_ON, 0);
if (r < 0)
goto fail;
enable_sigio_timer(fd);
t->priv = (void *)(long)fd;
return 0;
fail:
close(fd);
return -1;
}
static void hpet_stop_timer(struct qemu_alarm_timer *t)
{
int fd = (long)t->priv;
close(fd);
}
static int rtc_start_timer(struct qemu_alarm_timer *t)
{
int rtc_fd;
unsigned long current_rtc_freq = 0;
TFR(rtc_fd = open("/dev/rtc", O_RDONLY));
if (rtc_fd < 0)
return -1;
ioctl(rtc_fd, RTC_IRQP_READ, &current_rtc_freq);
if (current_rtc_freq != RTC_FREQ &&
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;
}
enable_sigio_timer(rtc_fd);
t->priv = (void *)(long)rtc_fd;
return 0;
}
static void rtc_stop_timer(struct qemu_alarm_timer *t)
{
int rtc_fd = (long)t->priv;
close(rtc_fd);
}
static int dynticks_start_timer(struct qemu_alarm_timer *t)
{
struct sigevent ev;
timer_t host_timer;
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = host_alarm_handler;
sigaction(SIGALRM, &act, NULL);
ev.sigev_value.sival_int = 0;
ev.sigev_notify = SIGEV_SIGNAL;
ev.sigev_signo = SIGALRM;
if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
perror("timer_create");
/* disable dynticks */
fprintf(stderr, "Dynamic Ticks disabled\n");
return -1;
}
t->priv = (void *)host_timer;
return 0;
}
static void dynticks_stop_timer(struct qemu_alarm_timer *t)
{
timer_t host_timer = (timer_t)t->priv;
timer_delete(host_timer);
}
static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
{
timer_t host_timer = (timer_t)t->priv;
struct itimerspec timeout;
int64_t nearest_delta_us = INT64_MAX;
int64_t current_us;
if (!active_timers[QEMU_TIMER_REALTIME] &&
!active_timers[QEMU_TIMER_VIRTUAL])
return;
nearest_delta_us = qemu_next_deadline_dyntick();
/* check whether a timer is already running */
if (timer_gettime(host_timer, &timeout)) {
perror("gettime");
fprintf(stderr, "Internal timer error: aborting\n");
exit(1);
}
current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000;
if (current_us && current_us <= nearest_delta_us)
return;
timeout.it_interval.tv_sec = 0;
timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
timeout.it_value.tv_sec = nearest_delta_us / 1000000;
timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000;
if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) {
perror("settime");
fprintf(stderr, "Internal timer error: aborting\n");
exit(1);
}
}
#endif /* defined(__linux__) */
static int unix_start_timer(struct qemu_alarm_timer *t)
{
struct sigaction act;
struct itimerval itv;
int err;
/* timer signal */
sigfillset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = host_alarm_handler;
sigaction(SIGALRM, &act, NULL);
itv.it_interval.tv_sec = 0;
/* for i386 kernel 2.6 to get 1 ms */
itv.it_interval.tv_usec = 999;
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 10 * 1000;
err = setitimer(ITIMER_REAL, &itv, NULL);
if (err)
return -1;
return 0;
}
static void unix_stop_timer(struct qemu_alarm_timer *t)
{
struct itimerval itv;
memset(&itv, 0, sizeof(itv));
setitimer(ITIMER_REAL, &itv, NULL);
}
#endif /* !defined(_WIN32) */
#ifdef _WIN32
static int win32_start_timer(struct qemu_alarm_timer *t)
{
TIMECAPS tc;
struct qemu_alarm_win32 *data = t->priv;
UINT flags;
data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!data->host_alarm) {
perror("Failed CreateEvent");
return -1;
}
memset(&tc, 0, sizeof(tc));
timeGetDevCaps(&tc, sizeof(tc));
if (data->period < tc.wPeriodMin)
data->period = tc.wPeriodMin;
timeBeginPeriod(data->period);
flags = TIME_CALLBACK_FUNCTION;
if (alarm_has_dynticks(t))
flags |= TIME_ONESHOT;
else
flags |= TIME_PERIODIC;
data->timerId = timeSetEvent(1, // interval (ms)
data->period, // resolution
host_alarm_handler, // function
(DWORD)t, // parameter
flags);
if (!data->timerId) {
perror("Failed to initialize win32 alarm timer");
timeEndPeriod(data->period);
CloseHandle(data->host_alarm);
return -1;
}
qemu_add_wait_object(data->host_alarm, NULL, NULL);
return 0;
}
static void win32_stop_timer(struct qemu_alarm_timer *t)
{
struct qemu_alarm_win32 *data = t->priv;
timeKillEvent(data->timerId);
timeEndPeriod(data->period);
CloseHandle(data->host_alarm);
}
static void win32_rearm_timer(struct qemu_alarm_timer *t)
{
struct qemu_alarm_win32 *data = t->priv;
uint64_t nearest_delta_us;
if (!active_timers[QEMU_TIMER_REALTIME] &&
!active_timers[QEMU_TIMER_VIRTUAL])
return;
nearest_delta_us = qemu_next_deadline_dyntick();
nearest_delta_us /= 1000;
timeKillEvent(data->timerId);
data->timerId = timeSetEvent(1,
data->period,
host_alarm_handler,
(DWORD)t,
TIME_ONESHOT | TIME_PERIODIC);
if (!data->timerId) {
perror("Failed to re-arm win32 alarm timer");
timeEndPeriod(data->period);
CloseHandle(data->host_alarm);
exit(1);
}
}
#endif /* _WIN32 */
static void init_timer_alarm(void)
{
struct qemu_alarm_timer *t;
int i, err = -1;
for (i = 0; alarm_timers[i].name; i++) {
t = &alarm_timers[i];
err = t->start(t);
if (!err)
break;
}
if (err) {
fprintf(stderr, "Unable to find any suitable alarm timer.\n");
fprintf(stderr, "Terminating\n");
exit(1);
}
alarm_timer = t;
}
static void quit_timers(void)
{
alarm_timer->stop(alarm_timer);
alarm_timer = NULL;
}
/***********************************************************/
/* host time/date access */
void qemu_get_timedate(struct tm *tm, int offset)
{
time_t ti;
struct tm *ret;
time(&ti);
ti += offset;
if (rtc_date_offset == -1) {
if (rtc_utc)
ret = gmtime(&ti);
else
ret = localtime(&ti);
} else {
ti -= rtc_date_offset;
ret = gmtime(&ti);
}
memcpy(tm, ret, sizeof(struct tm));
}
int qemu_timedate_diff(struct tm *tm)
{
time_t seconds;
if (rtc_date_offset == -1)
if (rtc_utc)
seconds = mktimegm(tm);
else
seconds = mktime(tm);
else
seconds = mktimegm(tm) + rtc_date_offset;
return seconds - time(NULL);
}
#ifdef CONFIG_TRACE
static int tbflush_requested;
static int exit_requested;
void start_tracing()
{
if (trace_filename == NULL)
return;
if (!tracing) {
fprintf(stderr,"-- start tracing --\n");
start_time = Now();
}
tracing = 1;
tbflush_requested = 1;
if (cpu_single_env)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
void stop_tracing()
{
if (trace_filename == NULL)
return;
if (tracing) {
end_time = Now();
elapsed_usecs += end_time - start_time;
fprintf(stderr,"-- stop tracing --\n");
}
tracing = 0;
tbflush_requested = 1;
if (cpu_single_env)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
#ifndef _WIN32
/* This is the handler for the SIGUSR1 and SIGUSR2 signals.
* SIGUSR1 turns tracing on. SIGUSR2 turns tracing off.
*/
void sigusr_handler(int sig)
{
if (sig == SIGUSR1)
start_tracing();
else
stop_tracing();
}
#endif
/* This is the handler to catch control-C so that we can exit cleanly.
* This is needed when tracing to flush the buffers to disk.
*/
void sigint_handler(int sig)
{
exit_requested = 1;
if (cpu_single_env)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
#endif /* CONFIG_TRACE */
/***********************************************************/
/* 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_accept_input(CharDriverState *s)
{
if (s->chr_accept_input)
s->chr_accept_input(s);
}
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, (uint8_t *)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;
}
/* MUX driver for serial I/O splitting */
static int term_timestamps;
static int64_t term_timestamps_start;
#define MAX_MUX 4
#define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */
#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
typedef struct {
IOCanRWHandler *chr_can_read[MAX_MUX];
IOReadHandler *chr_read[MAX_MUX];
IOEventHandler *chr_event[MAX_MUX];
void *ext_opaque[MAX_MUX];
CharDriverState *drv;
unsigned char buffer[MUX_BUFFER_SIZE];
int prod;
int cons;
int mux_cnt;
int term_got_escape;
int max_size;
} MuxDriver;
static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
MuxDriver *d = chr->opaque;
int ret;
if (!term_timestamps) {
ret = d->drv->chr_write(d->drv, buf, len);
} else {
int i;
ret = 0;
for(i = 0; i < len; i++) {
ret += d->drv->chr_write(d->drv, buf+i, 1);
if (buf[i] == '\n') {
char buf1[64];
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));
d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
}
}
}
return ret;
}
static const char * const mux_help[] = {
"% h print this help\n\r",
"% x exit emulator\n\r",
"% s save disk data back to file (if -snapshot)\n\r",
"% t toggle console timestamps\n\r"
"% b send break (magic sysrq)\n\r",
"% c switch between console and monitor\n\r",
"% % sends %\n\r",
NULL
};
static int term_escape_char = 0x01; /* ctrl-a is used for escape */
static void mux_print_help(CharDriverState *chr)
{
int i, j;
char ebuf[15] = "Escape-Char";
char cbuf[50] = "\n\r";
if (term_escape_char > 0 && term_escape_char < 26) {
snprintf(cbuf, sizeof(cbuf), "\n\r");
snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
} else {
snprintf(cbuf, sizeof(cbuf),
"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
term_escape_char);
}
chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf));
for (i = 0; mux_help[i] != NULL; i++) {
for (j=0; mux_help[i][j] != '\0'; j++) {
if (mux_help[i][j] == '%')
chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf));
else
chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1);
}
}
}
static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
{
if (d->term_got_escape) {
d->term_got_escape = 0;
if (ch == term_escape_char)
goto send_char;
switch(ch) {
case '?':
case 'h':
mux_print_help(chr);
break;
case 'x':
{
const char *term = "QEMU: Terminated\n\r";
chr->chr_write(chr,(uint8_t *)term,strlen(term));
exit(0);
break;
}
case 's':
{
int i;
for (i = 0; i < nb_drives; i++) {
bdrv_commit(drives_table[i].bdrv);
}
}
break;
case 'b':
qemu_chr_event(chr, CHR_EVENT_BREAK);
break;
case 'c':
/* Switch to the next registered device */
chr->focus++;
if (chr->focus >= d->mux_cnt)
chr->focus = 0;
break;
case 't':
term_timestamps = !term_timestamps;
term_timestamps_start = -1;
break;
}
} else if (ch == term_escape_char) {
d->term_got_escape = 1;
} else {
send_char:
return 1;
}
return 0;
}
static void mux_chr_accept_input(CharDriverState *chr)
{
int m = chr->focus;
MuxDriver *d = chr->opaque;
while (d->prod != d->cons &&
d->chr_can_read[m] &&
d->chr_can_read[m](d->ext_opaque[m])) {
d->chr_read[m](d->ext_opaque[m],
&d->buffer[d->cons++ & MUX_BUFFER_MASK], 1);
}
}
static int mux_chr_can_read(void *opaque)
{
CharDriverState *chr = opaque;
MuxDriver *d = chr->opaque;
if ((d->prod - d->cons) < MUX_BUFFER_SIZE)
return 1;
if (d->chr_can_read[chr->focus])
return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]);
return 0;
}
static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
{
CharDriverState *chr = opaque;
MuxDriver *d = chr->opaque;
int m = chr->focus;
int i;
mux_chr_accept_input (opaque);
for(i = 0; i < size; i++)
if (mux_proc_byte(chr, d, buf[i])) {
if (d->prod == d->cons &&
d->chr_can_read[m] &&
d->chr_can_read[m](d->ext_opaque[m]))
d->chr_read[m](d->ext_opaque[m], &buf[i], 1);
else
d->buffer[d->prod++ & MUX_BUFFER_MASK] = buf[i];
}
}
static void mux_chr_event(void *opaque, int event)
{
CharDriverState *chr = opaque;
MuxDriver *d = chr->opaque;
int i;
/* Send the event to all registered listeners */
for (i = 0; i < d->mux_cnt; i++)
if (d->chr_event[i])
d->chr_event[i](d->ext_opaque[i], event);
}
static void mux_chr_update_read_handler(CharDriverState *chr)
{
MuxDriver *d = chr->opaque;
if (d->mux_cnt >= MAX_MUX) {
fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
return;
}
d->ext_opaque[d->mux_cnt] = chr->handler_opaque;
d->chr_can_read[d->mux_cnt] = chr->chr_can_read;
d->chr_read[d->mux_cnt] = chr->chr_read;
d->chr_event[d->mux_cnt] = chr->chr_event;
/* Fix up the real driver with mux routines */
if (d->mux_cnt == 0) {
qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
mux_chr_event, chr);
}
chr->focus = d->mux_cnt;
d->mux_cnt++;
}
static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
{
CharDriverState *chr;
MuxDriver *d;
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
d = qemu_mallocz(sizeof(MuxDriver));
if (!d) {
free(chr);
return NULL;
}
chr->opaque = d;
d->drv = drv;
chr->focus = -1;
chr->chr_write = mux_chr_write;
chr->chr_update_read_handler = mux_chr_update_read_handler;
chr->chr_accept_input = mux_chr_accept_input;
return chr;
}
#ifdef _WIN32
static int send_all(int fd, const uint8_t *buf, int len1)
{
int ret, len;
len = len1;
while (len > 0) {
ret = socket_send(fd, buf, len);
if (ret < 0) {
if (errno != EWOULDBLOCK) {
return -1;
}
} else if (ret == 0) {
break;
} else {
buf += ret;
len -= ret;
}
}
return len1 - len;
}
#else
static int unix_write(int fd, const uint8_t *buf, int len1)
{
int ret, len;
len = len1;
while (len > 0) {
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);
}
#endif /* !_WIN32 */
#ifndef _WIN32
typedef struct {
int fd_in, fd_out;
int max_size;
} FDCharDriver;
#define STDIO_MAX_CLIENTS 1
static int stdio_nb_clients = 0;
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);
}
}
}
static void fd_chr_close(struct 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, NULL, NULL, NULL, NULL);
}
}
qemu_free(s);
}
/* 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;
chr->chr_close = fd_chr_close;
qemu_chr_reset(chr);
return chr;
}
static CharDriverState *qemu_chr_open_file_out(const char *file_out)
{
int fd_out;
TFR(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);
TFR(fd_in = open(filename_in, O_RDWR | O_BINARY));
TFR(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);
TFR(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);
}
CharDriverState *qemu_chr_open_fdpair(const char *fd_pair)
{
int fd_in, fd_out;
char *endptr;
/* fd_pair should contain two decimal fd values, separated by
* a colon. */
endptr = NULL;
fd_in = strtol(fd_pair, &endptr, 10);
if (endptr == NULL || endptr == fd_pair || *endptr != ':')
return NULL;
endptr++; // skip colon
fd_pair = endptr;
endptr = NULL;
fd_out = strtol(fd_pair, &endptr, 10);
if (endptr == NULL || endptr == fd_pair || *endptr != '\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_FIFO_MAX_SIZE 1
static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
static int term_fifo_size;
static int stdio_read_poll(void *opaque)
{
CharDriverState *chr = opaque;
/* 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;
}
static void stdio_read(void *opaque)
{
int size;
uint8_t buf[1];
CharDriverState *chr = opaque;
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) {
if (qemu_chr_can_read(chr) > 0) {
qemu_chr_read(chr, buf, 1);
} else if (term_fifo_size == 0) {
term_fifo[term_fifo_size++] = buf[0];
}
}
}
/* init terminal so that we can grab keys */
static struct termios oldtty;
static int old_fd0_flags;
static int term_atexit_done;
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);
if (!term_atexit_done++)
atexit(term_exit);
fcntl(0, F_SETFL, O_NONBLOCK);
}
static void qemu_chr_close_stdio(struct CharDriverState *chr)
{
term_exit();
stdio_nb_clients--;
qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
fd_chr_close(chr);
}
static CharDriverState *qemu_chr_open_stdio(void)
{
CharDriverState *chr;
if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
return NULL;
chr = qemu_chr_open_fd(0, 1);
chr->chr_close = qemu_chr_close_stdio;
qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
stdio_nb_clients++;
term_init();
return chr;
}
#ifdef __sun__
/* Once Solaris has openpty(), this is going to be removed. */
int openpty(int *amaster, int *aslave, char *name,
struct termios *termp, struct winsize *winp)
{
const char *slave;
int mfd = -1, sfd = -1;
*amaster = *aslave = -1;
mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
if (mfd < 0)
goto err;
if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)
goto err;
if ((slave = ptsname(mfd)) == NULL)
goto err;
if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1)
goto err;
if (ioctl(sfd, I_PUSH, "ptem") == -1 ||
(termp != NULL && tcgetattr(sfd, termp) < 0))
goto err;
if (amaster)
*amaster = mfd;
if (aslave)
*aslave = sfd;
if (winp)
ioctl(sfd, TIOCSWINSZ, winp);
return 0;
err:
if (sfd != -1)
close(sfd);
close(mfd);
return -1;
}
void cfmakeraw (struct termios *termios_p)
{
termios_p->c_iflag &=
~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
termios_p->c_cflag &= ~(CSIZE|PARENB);
termios_p->c_cflag |= CS8;
termios_p->c_cc[VMIN] = 0;
termios_p->c_cc[VTIME] = 0;
}
#endif /* __sun__ */
#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
|| defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
typedef struct {
int fd;
int connected;
int polling;
int read_bytes;
QEMUTimer *timer;
} PtyCharDriver;
static void pty_chr_update_read_handler(CharDriverState *chr);
static void pty_chr_state(CharDriverState *chr, int connected);
static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
PtyCharDriver *s = chr->opaque;
if (!s->connected) {
/* guest sends data, check for (re-)connect */
pty_chr_update_read_handler(chr);
return 0;
}
return unix_write(s->fd, buf, len);
}
static int pty_chr_read_poll(void *opaque)
{
CharDriverState *chr = opaque;
PtyCharDriver *s = chr->opaque;
s->read_bytes = qemu_chr_can_read(chr);
return s->read_bytes;
}
static void pty_chr_read(void *opaque)
{
CharDriverState *chr = opaque;
PtyCharDriver *s = chr->opaque;
int size, len;
uint8_t buf[1024];
len = sizeof(buf);
if (len > s->read_bytes)
len = s->read_bytes;
if (len == 0)
return;
size = read(s->fd, buf, len);
if ((size == -1 && errno == EIO) ||
(size == 0)) {
pty_chr_state(chr, 0);
return;
}
if (size > 0) {
pty_chr_state(chr, 1);
qemu_chr_read(chr, buf, size);
}
}
static void pty_chr_update_read_handler(CharDriverState *chr)
{
PtyCharDriver *s = chr->opaque;
qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
pty_chr_read, NULL, chr);
s->polling = 1;
/*
* Short timeout here: just need wait long enougth that qemu makes
* it through the poll loop once. When reconnected we want a
* short timeout so we notice it almost instantly. Otherwise
* read() gives us -EIO instantly, making pty_chr_state() reset the
* timeout to the normal (much longer) poll interval before the
* timer triggers.
*/
qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10);
}
static void pty_chr_state(CharDriverState *chr, int connected)
{
PtyCharDriver *s = chr->opaque;
if (!connected) {
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
s->connected = 0;
s->polling = 0;
/* (re-)connect poll interval for idle guests: once per second.
* We check more frequently in case the guests sends data to
* the virtual device linked to our pty. */
qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
} else {
if (!s->connected)
qemu_chr_reset(chr);
s->connected = 1;
}
}
static void pty_chr_timer(void *opaque)
{
struct CharDriverState *chr = opaque;
PtyCharDriver *s = chr->opaque;
if (s->connected)
return;
if (s->polling) {
/* If we arrive here without polling being cleared due
* read returning -EIO, then we are (re-)connected */
pty_chr_state(chr, 1);
return;
}
/* Next poll ... */
pty_chr_update_read_handler(chr);
}
static void pty_chr_close(struct CharDriverState *chr)
{
PtyCharDriver *s = chr->opaque;
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
close(s->fd);
qemu_free(s);
}
static CharDriverState *qemu_chr_open_pty(void)
{
CharDriverState *chr;
PtyCharDriver *s;
struct termios tty;
int slave_fd;
#if defined(__OpenBSD__)
char pty_name[PATH_MAX];
#define q_ptsname(x) pty_name
#else
char *pty_name = NULL;
#define q_ptsname(x) ptsname(x)
#endif
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
s = qemu_mallocz(sizeof(PtyCharDriver));
if (!s) {
qemu_free(chr);
return NULL;
}
if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
return NULL;
}
/* Set raw attributes on the pty. */
cfmakeraw(&tty);
tcsetattr(slave_fd, TCSAFLUSH, &tty);
close(slave_fd);
fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
chr->opaque = s;
chr->chr_write = pty_chr_write;
chr->chr_update_read_handler = pty_chr_update_read_handler;
chr->chr_close = pty_chr_close;
s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
return chr;
}
#endif /* __linux__ || __sun__ || __xxxBSD__ */
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);
#define MARGIN 1.1
if (speed <= 50 * MARGIN)
spd = B50;
else if (speed <= 75 * MARGIN)
spd = B75;
else if (speed <= 300 * MARGIN)
spd = B300;
else if (speed <= 600 * MARGIN)
spd = B600;
else if (speed <= 1200 * MARGIN)
spd = B1200;
else if (speed <= 2400 * MARGIN)
spd = B2400;
else if (speed <= 4800 * MARGIN)
spd = B4800;
else if (speed <= 9600 * MARGIN)
spd = B9600;
else if (speed <= 19200 * MARGIN)
spd = B19200;
else if (speed <= 38400 * MARGIN)
spd = B38400;
else if (speed <= 57600 * MARGIN)
spd = B57600;
else if (speed <= 115200 * MARGIN)
spd = B115200;
else
spd = B115200;
cfsetispeed(&tty, spd);
cfsetospeed(&tty, spd);