* [Qemu-devel] Arm system emulation
@ 2005-11-22 2:31 Paul Brook
2005-11-25 22:45 ` [Qemu-devel] " Antti P Miettinen
0 siblings, 1 reply; 3+ messages in thread
From: Paul Brook @ 2005-11-22 2:31 UTC (permalink / raw)
To: qemu-devel, Fabrice Bellard
[-- Attachment #1: Type: text/plain, Size: 1195 bytes --]
The attached patch implements Arm system emulation.
Also attached is the prerequisite PS/2 emulation separation patch.
The emulated hardware is based on an Arm Integrator/CP board with an
arm1026ej-s cpu. This is an embedded development board that supports a
variety of core modules and peripherals. Currently timers, interrupt
controller and UART(x2) are implemented. Network should follow shortly.
In the medium term I plan to extend this to also emulate an Integrator/AP
board. This is similar but includes which includes a PCI bus, so existing PCI
peripherals can be used.
Longer term these boards can be used as a base for future ARM cpus, including
SMP support.
Generally speaking Arm boards don't have a BIOS.The kernel/bootloader is
loaded directly from flash. The -kernel option can be used to load linux
kernels (and probably any other image).
For anyone wanting to try this, there's a kernel image and small initrd
filesystem at:
https://nowt.dyndns.org/integratorcp.zImage
https://nowt.dyndns.org/arm_root.img
There's nothing special about these. Just a vanilla 2.6.14 kernel configured
with a serial console and busybox+bash from a Debian arm-linux install.
Paul
[-- Attachment #2: patch.qemu_arm_system.bz2 --]
[-- Type: application/x-bzip2, Size: 20650 bytes --]
[-- Attachment #3: patch.qemu_ps2 --]
[-- Type: text/x-diff, Size: 33748 bytes --]
Index: Makefile.target
===================================================================
RCS file: /cvsroot/qemu/qemu/Makefile.target,v
retrieving revision 1.86
diff -u -p -r1.86 Makefile.target
--- Makefile.target 6 Nov 2005 16:52:11 -0000 1.86
+++ Makefile.target 20 Nov 2005 15:13:51 -0000
@@ -298,13 +298,13 @@ VL_OBJS+= usb.o usb-uhci.o usb-linux.o u
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
-VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
+VL_OBJS+= ide.o ne2000.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
DEFINES += -DHAS_AUDIO
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
-VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
+VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
DEFINES += -DHAS_AUDIO
@@ -315,7 +315,7 @@ VL_OBJS+= mips_r4k.o dma.o vga.o serial.
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
ifeq ($(TARGET_ARCH), sparc64)
-VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o vga.o
+VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o ps2.o vga.o
VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
VL_OBJS+= cirrus_vga.o parallel.o
VL_OBJS+= magic-load.o
Index: vl.h
===================================================================
RCS file: /cvsroot/qemu/qemu/vl.h,v
retrieving revision 1.91
diff -u -p -r1.91 vl.h
--- vl.h 15 Nov 2005 22:16:05 -0000 1.91
+++ vl.h 20 Nov 2005 15:13:55 -0000
@@ -916,6 +916,14 @@ void do_usb_add(const char *devname);
void do_usb_del(const char *devname);
void usb_info(void);
+/* ps2.c */
+void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
+void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
+void ps2_write_mouse(void *, int val);
+void ps2_write_keyboard(void *, int val);
+uint32_t ps2_read_data(void *);
+void ps2_queue(void *, int b);
+
#endif /* defined(QEMU_TOOL) */
/* monitor.c */
Index: hw/pckbd.c
===================================================================
RCS file: /cvsroot/qemu/qemu/hw/pckbd.c,v
retrieving revision 1.11
diff -u -p -r1.11 pckbd.c
--- hw/pckbd.c 27 Jan 2005 22:32:51 -0000 1.11
+++ hw/pckbd.c 20 Nov 2005 15:13:55 -0000
@@ -110,32 +110,17 @@
#define KBD_QUEUE_SIZE 256
-typedef struct {
- uint8_t aux[KBD_QUEUE_SIZE];
- uint8_t data[KBD_QUEUE_SIZE];
- int rptr, wptr, count;
-} KBDQueue;
+#define KBD_PENDING_KBD 1
+#define KBD_PENDING_AUX 2
typedef struct KBDState {
- KBDQueue queue;
uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
uint8_t status;
uint8_t mode;
- /* keyboard state */
- int kbd_write_cmd;
- int scan_enabled;
- /* mouse state */
- int mouse_write_cmd;
- uint8_t mouse_status;
- uint8_t mouse_resolution;
- uint8_t mouse_sample_rate;
- uint8_t mouse_wrap;
- uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
- uint8_t mouse_detect_state;
- int mouse_dx; /* current values, needed for 'poll' mode */
- int mouse_dy;
- int mouse_dz;
- uint8_t mouse_buttons;
+ /* Bitmask of devices with data available. */
+ int pending;
+ void *kbd;
+ void *mouse;
} KBDState;
KBDState kbd_state;
@@ -145,15 +130,15 @@ KBDState kbd_state;
incorrect, but it avoids having to simulate exact delays */
static void kbd_update_irq(KBDState *s)
{
- KBDQueue *q = &s->queue;
int irq12_level, irq1_level;
irq1_level = 0;
irq12_level = 0;
s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
- if (q->count != 0) {
+ if (s->pending) {
s->status |= KBD_STAT_OBF;
- if (q->aux[q->rptr]) {
+ /* kdb data takes priority over aux data. */
+ if (s->pending == KBD_PENDING_AUX) {
s->status |= KBD_STAT_MOUSE_OBF;
if (s->mode & KBD_MODE_MOUSE_INT)
irq12_level = 1;
@@ -167,32 +152,26 @@ static void kbd_update_irq(KBDState *s)
pic_set_irq(12, irq12_level);
}
-static void kbd_queue(KBDState *s, int b, int aux)
+static void kbd_update_kbd_irq(void *opaque, int level)
{
- KBDQueue *q = &s->queue;
+ KBDState *s = (KBDState *)opaque;
-#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
- if (aux)
- printf("mouse event: 0x%02x\n", b);
-#ifdef DEBUG_KBD
+ if (level)
+ s->pending |= KBD_PENDING_KBD;
else
- printf("kbd event: 0x%02x\n", b);
-#endif
-#endif
- if (q->count >= KBD_QUEUE_SIZE)
- return;
- q->aux[q->wptr] = aux;
- q->data[q->wptr] = b;
- if (++q->wptr == KBD_QUEUE_SIZE)
- q->wptr = 0;
- q->count++;
+ s->pending &= ~KBD_PENDING_KBD;
kbd_update_irq(s);
}
-static void pc_kbd_put_keycode(void *opaque, int keycode)
+static void kbd_update_aux_irq(void *opaque, int level)
{
- KBDState *s = opaque;
- kbd_queue(s, keycode, 0);
+ KBDState *s = (KBDState *)opaque;
+
+ if (level)
+ s->pending |= KBD_PENDING_AUX;
+ else
+ s->pending &= ~KBD_PENDING_AUX;
+ kbd_update_irq(s);
}
static uint32_t kbd_read_status(void *opaque, uint32_t addr)
@@ -206,6 +185,14 @@ static uint32_t kbd_read_status(void *op
return val;
}
+static void kbd_queue(KBDState *s, int b, int aux)
+{
+ if (aux)
+ ps2_queue(s->mouse, b);
+ else
+ ps2_queue(s->kbd, b);
+}
+
static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
{
KBDState *s = opaque;
@@ -287,304 +274,11 @@ static void kbd_write_command(void *opaq
static uint32_t kbd_read_data(void *opaque, uint32_t addr)
{
KBDState *s = opaque;
- KBDQueue *q;
- int val, index, aux;
-
- q = &s->queue;
- if (q->count == 0) {
- /* NOTE: if no data left, we return the last keyboard one
- (needed for EMM386) */
- /* XXX: need a timer to do things correctly */
- index = q->rptr - 1;
- if (index < 0)
- index = KBD_QUEUE_SIZE - 1;
- val = q->data[index];
- } else {
- aux = q->aux[q->rptr];
- val = q->data[q->rptr];
- if (++q->rptr == KBD_QUEUE_SIZE)
- q->rptr = 0;
- q->count--;
- /* reading deasserts IRQ */
- if (aux)
- pic_set_irq(12, 0);
- else
- pic_set_irq(1, 0);
- }
- /* reassert IRQs if data left */
- kbd_update_irq(s);
-#ifdef DEBUG_KBD
- printf("kbd: read data=0x%02x\n", val);
-#endif
- return val;
-}
-static void kbd_reset_keyboard(KBDState *s)
-{
- s->scan_enabled = 1;
-}
+ if (s->pending == KBD_PENDING_AUX)
+ return ps2_read_data(s->mouse);
-static void kbd_write_keyboard(KBDState *s, int val)
-{
- switch(s->kbd_write_cmd) {
- default:
- case -1:
- switch(val) {
- case 0x00:
- kbd_queue(s, KBD_REPLY_ACK, 0);
- break;
- case 0x05:
- kbd_queue(s, KBD_REPLY_RESEND, 0);
- break;
- case KBD_CMD_GET_ID:
- kbd_queue(s, KBD_REPLY_ACK, 0);
- kbd_queue(s, 0xab, 0);
- kbd_queue(s, 0x83, 0);
- break;
- case KBD_CMD_ECHO:
- kbd_queue(s, KBD_CMD_ECHO, 0);
- break;
- case KBD_CMD_ENABLE:
- s->scan_enabled = 1;
- kbd_queue(s, KBD_REPLY_ACK, 0);
- break;
- case KBD_CMD_SET_LEDS:
- case KBD_CMD_SET_RATE:
- s->kbd_write_cmd = val;
- kbd_queue(s, KBD_REPLY_ACK, 0);
- break;
- case KBD_CMD_RESET_DISABLE:
- kbd_reset_keyboard(s);
- s->scan_enabled = 0;
- kbd_queue(s, KBD_REPLY_ACK, 0);
- break;
- case KBD_CMD_RESET_ENABLE:
- kbd_reset_keyboard(s);
- s->scan_enabled = 1;
- kbd_queue(s, KBD_REPLY_ACK, 0);
- break;
- case KBD_CMD_RESET:
- kbd_reset_keyboard(s);
- kbd_queue(s, KBD_REPLY_ACK, 0);
- kbd_queue(s, KBD_REPLY_POR, 0);
- break;
- default:
- kbd_queue(s, KBD_REPLY_ACK, 0);
- break;
- }
- break;
- case KBD_CMD_SET_LEDS:
- kbd_queue(s, KBD_REPLY_ACK, 0);
- s->kbd_write_cmd = -1;
- break;
- case KBD_CMD_SET_RATE:
- kbd_queue(s, KBD_REPLY_ACK, 0);
- s->kbd_write_cmd = -1;
- break;
- }
-}
-
-static void kbd_mouse_send_packet(KBDState *s)
-{
- unsigned int b;
- int dx1, dy1, dz1;
-
- dx1 = s->mouse_dx;
- dy1 = s->mouse_dy;
- dz1 = s->mouse_dz;
- /* XXX: increase range to 8 bits ? */
- if (dx1 > 127)
- dx1 = 127;
- else if (dx1 < -127)
- dx1 = -127;
- if (dy1 > 127)
- dy1 = 127;
- else if (dy1 < -127)
- dy1 = -127;
- b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
- kbd_queue(s, b, 1);
- kbd_queue(s, dx1 & 0xff, 1);
- kbd_queue(s, dy1 & 0xff, 1);
- /* extra byte for IMPS/2 or IMEX */
- switch(s->mouse_type) {
- default:
- break;
- case 3:
- if (dz1 > 127)
- dz1 = 127;
- else if (dz1 < -127)
- dz1 = -127;
- kbd_queue(s, dz1 & 0xff, 1);
- break;
- case 4:
- if (dz1 > 7)
- dz1 = 7;
- else if (dz1 < -7)
- dz1 = -7;
- b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
- kbd_queue(s, b, 1);
- break;
- }
-
- /* update deltas */
- s->mouse_dx -= dx1;
- s->mouse_dy -= dy1;
- s->mouse_dz -= dz1;
-}
-
-static void pc_kbd_mouse_event(void *opaque,
- int dx, int dy, int dz, int buttons_state)
-{
- KBDState *s = opaque;
-
- /* check if deltas are recorded when disabled */
- if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
- return;
-
- s->mouse_dx += dx;
- s->mouse_dy -= dy;
- s->mouse_dz += dz;
- /* XXX: SDL sometimes generates nul events: we delete them */
- if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
- s->mouse_buttons == buttons_state)
- return;
- s->mouse_buttons = buttons_state;
-
- if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
- (s->queue.count < (KBD_QUEUE_SIZE - 16))) {
- for(;;) {
- /* if not remote, send event. Multiple events are sent if
- too big deltas */
- kbd_mouse_send_packet(s);
- if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
- break;
- }
- }
-}
-
-static void kbd_write_mouse(KBDState *s, int val)
-{
-#ifdef DEBUG_MOUSE
- printf("kbd: write mouse 0x%02x\n", val);
-#endif
- switch(s->mouse_write_cmd) {
- default:
- case -1:
- /* mouse command */
- if (s->mouse_wrap) {
- if (val == AUX_RESET_WRAP) {
- s->mouse_wrap = 0;
- kbd_queue(s, AUX_ACK, 1);
- return;
- } else if (val != AUX_RESET) {
- kbd_queue(s, val, 1);
- return;
- }
- }
- switch(val) {
- case AUX_SET_SCALE11:
- s->mouse_status &= ~MOUSE_STATUS_SCALE21;
- kbd_queue(s, AUX_ACK, 1);
- break;
- case AUX_SET_SCALE21:
- s->mouse_status |= MOUSE_STATUS_SCALE21;
- kbd_queue(s, AUX_ACK, 1);
- break;
- case AUX_SET_STREAM:
- s->mouse_status &= ~MOUSE_STATUS_REMOTE;
- kbd_queue(s, AUX_ACK, 1);
- break;
- case AUX_SET_WRAP:
- s->mouse_wrap = 1;
- kbd_queue(s, AUX_ACK, 1);
- break;
- case AUX_SET_REMOTE:
- s->mouse_status |= MOUSE_STATUS_REMOTE;
- kbd_queue(s, AUX_ACK, 1);
- break;
- case AUX_GET_TYPE:
- kbd_queue(s, AUX_ACK, 1);
- kbd_queue(s, s->mouse_type, 1);
- break;
- case AUX_SET_RES:
- case AUX_SET_SAMPLE:
- s->mouse_write_cmd = val;
- kbd_queue(s, AUX_ACK, 1);
- break;
- case AUX_GET_SCALE:
- kbd_queue(s, AUX_ACK, 1);
- kbd_queue(s, s->mouse_status, 1);
- kbd_queue(s, s->mouse_resolution, 1);
- kbd_queue(s, s->mouse_sample_rate, 1);
- break;
- case AUX_POLL:
- kbd_queue(s, AUX_ACK, 1);
- kbd_mouse_send_packet(s);
- break;
- case AUX_ENABLE_DEV:
- s->mouse_status |= MOUSE_STATUS_ENABLED;
- kbd_queue(s, AUX_ACK, 1);
- break;
- case AUX_DISABLE_DEV:
- s->mouse_status &= ~MOUSE_STATUS_ENABLED;
- kbd_queue(s, AUX_ACK, 1);
- break;
- case AUX_SET_DEFAULT:
- s->mouse_sample_rate = 100;
- s->mouse_resolution = 2;
- s->mouse_status = 0;
- kbd_queue(s, AUX_ACK, 1);
- break;
- case AUX_RESET:
- s->mouse_sample_rate = 100;
- s->mouse_resolution = 2;
- s->mouse_status = 0;
- s->mouse_type = 0;
- kbd_queue(s, AUX_ACK, 1);
- kbd_queue(s, 0xaa, 1);
- kbd_queue(s, s->mouse_type, 1);
- break;
- default:
- break;
- }
- break;
- case AUX_SET_SAMPLE:
- s->mouse_sample_rate = val;
- /* detect IMPS/2 or IMEX */
- switch(s->mouse_detect_state) {
- default:
- case 0:
- if (val == 200)
- s->mouse_detect_state = 1;
- break;
- case 1:
- if (val == 100)
- s->mouse_detect_state = 2;
- else if (val == 200)
- s->mouse_detect_state = 3;
- else
- s->mouse_detect_state = 0;
- break;
- case 2:
- if (val == 80)
- s->mouse_type = 3; /* IMPS/2 */
- s->mouse_detect_state = 0;
- break;
- case 3:
- if (val == 80)
- s->mouse_type = 4; /* IMEX */
- s->mouse_detect_state = 0;
- break;
- }
- kbd_queue(s, AUX_ACK, 1);
- s->mouse_write_cmd = -1;
- break;
- case AUX_SET_RES:
- s->mouse_resolution = val;
- kbd_queue(s, AUX_ACK, 1);
- s->mouse_write_cmd = -1;
- break;
- }
+ return ps2_read_data(s->kbd);
}
void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
@@ -597,10 +291,11 @@ void kbd_write_data(void *opaque, uint32
switch(s->write_cmd) {
case 0:
- kbd_write_keyboard(s, val);
+ ps2_write_keyboard(s->kbd, val);
break;
case KBD_CCMD_WRITE_MODE:
s->mode = val;
+ /* ??? */
kbd_update_irq(s);
break;
case KBD_CCMD_WRITE_OBUF:
@@ -618,7 +313,7 @@ void kbd_write_data(void *opaque, uint32
}
break;
case KBD_CCMD_WRITE_MOUSE:
- kbd_write_mouse(s, val);
+ ps2_write_mouse(s->mouse, val);
break;
default:
break;
@@ -629,16 +324,9 @@ void kbd_write_data(void *opaque, uint32
static void kbd_reset(void *opaque)
{
KBDState *s = opaque;
- KBDQueue *q;
- s->kbd_write_cmd = -1;
- s->mouse_write_cmd = -1;
s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
- q = &s->queue;
- q->rptr = 0;
- q->wptr = 0;
- q->count = 0;
}
static void kbd_save(QEMUFile* f, void* opaque)
@@ -648,6 +336,7 @@ static void kbd_save(QEMUFile* f, void*
qemu_put_8s(f, &s->write_cmd);
qemu_put_8s(f, &s->status);
qemu_put_8s(f, &s->mode);
+ /*
qemu_put_be32s(f, &s->kbd_write_cmd);
qemu_put_be32s(f, &s->scan_enabled);
qemu_put_be32s(f, &s->mouse_write_cmd);
@@ -661,30 +350,18 @@ static void kbd_save(QEMUFile* f, void*
qemu_put_be32s(f, &s->mouse_dy);
qemu_put_be32s(f, &s->mouse_dz);
qemu_put_8s(f, &s->mouse_buttons);
+ */
}
static int kbd_load(QEMUFile* f, void* opaque, int version_id)
{
KBDState *s = (KBDState*)opaque;
- if (version_id != 1)
+ if (version_id != 2)
return -EINVAL;
qemu_get_8s(f, &s->write_cmd);
qemu_get_8s(f, &s->status);
qemu_get_8s(f, &s->mode);
- qemu_get_be32s(f, &s->kbd_write_cmd);
- qemu_get_be32s(f, &s->scan_enabled);
- qemu_get_be32s(f, &s->mouse_write_cmd);
- qemu_get_8s(f, &s->mouse_status);
- qemu_get_8s(f, &s->mouse_resolution);
- qemu_get_8s(f, &s->mouse_sample_rate);
- qemu_get_8s(f, &s->mouse_wrap);
- qemu_get_8s(f, &s->mouse_type);
- qemu_get_8s(f, &s->mouse_detect_state);
- qemu_get_be32s(f, &s->mouse_dx);
- qemu_get_be32s(f, &s->mouse_dy);
- qemu_get_be32s(f, &s->mouse_dz);
- qemu_get_8s(f, &s->mouse_buttons);
return 0;
}
@@ -693,13 +370,13 @@ void kbd_init(void)
KBDState *s = &kbd_state;
kbd_reset(s);
- register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s);
+ register_savevm("pckbd", 0, 2, kbd_save, kbd_load, s);
register_ioport_read(0x60, 1, 1, kbd_read_data, s);
register_ioport_write(0x60, 1, 1, kbd_write_data, s);
register_ioport_read(0x64, 1, 1, kbd_read_status, s);
register_ioport_write(0x64, 1, 1, kbd_write_command, s);
- qemu_add_kbd_event_handler(pc_kbd_put_keycode, s);
- qemu_add_mouse_event_handler(pc_kbd_mouse_event, s);
+ s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
+ s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
qemu_register_reset(kbd_reset, s);
}
Index: hw/ps2.c
===================================================================
RCS file: hw/ps2.c
diff -N hw/ps2.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ hw/ps2.c 20 Nov 2005 15:13:55 -0000
@@ -0,0 +1,512 @@
+/*
+ * QEMU PS/2 keyboard/mouse emulation
+ *
+ * Copyright (c) 2003 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"
+
+/* debug PC keyboard */
+//#define DEBUG_KBD
+
+/* debug PC keyboard : only mouse */
+//#define DEBUG_MOUSE
+
+/* Keyboard Commands */
+#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
+#define KBD_CMD_ECHO 0xEE
+#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
+#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
+#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
+#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
+#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
+#define KBD_CMD_RESET 0xFF /* Reset */
+
+/* Keyboard Replies */
+#define KBD_REPLY_POR 0xAA /* Power on reset */
+#define KBD_REPLY_ACK 0xFA /* Command ACK */
+#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
+
+/* Mouse Commands */
+#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
+#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
+#define AUX_SET_RES 0xE8 /* Set resolution */
+#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
+#define AUX_SET_STREAM 0xEA /* Set stream mode */
+#define AUX_POLL 0xEB /* Poll */
+#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
+#define AUX_SET_WRAP 0xEE /* Set wrap mode */
+#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
+#define AUX_GET_TYPE 0xF2 /* Get type */
+#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
+#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
+#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
+#define AUX_SET_DEFAULT 0xF6
+#define AUX_RESET 0xFF /* Reset aux device */
+#define AUX_ACK 0xFA /* Command byte ACK. */
+
+#define MOUSE_STATUS_REMOTE 0x40
+#define MOUSE_STATUS_ENABLED 0x20
+#define MOUSE_STATUS_SCALE21 0x10
+
+#define PS2_QUEUE_SIZE 256
+
+typedef struct {
+ uint8_t data[PS2_QUEUE_SIZE];
+ int rptr, wptr, count;
+} PS2Queue;
+
+typedef struct {
+ PS2Queue queue;
+ int32_t write_cmd;
+ void (*update_irq)(void *, int);
+ void *update_arg;
+} PS2State;
+
+typedef struct {
+ PS2State common;
+ int scan_enabled;
+} PS2KbdState;
+
+typedef struct {
+ PS2State common;
+ uint8_t mouse_status;
+ uint8_t mouse_resolution;
+ uint8_t mouse_sample_rate;
+ uint8_t mouse_wrap;
+ uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
+ uint8_t mouse_detect_state;
+ int mouse_dx; /* current values, needed for 'poll' mode */
+ int mouse_dy;
+ int mouse_dz;
+ uint8_t mouse_buttons;
+} PS2MouseState;
+
+void ps2_queue(void *opaque, int b)
+{
+ PS2State *s = (PS2State *)opaque;
+ PS2Queue *q = &s->queue;
+
+ if (q->count >= PS2_QUEUE_SIZE)
+ return;
+ q->data[q->wptr] = b;
+ if (++q->wptr == PS2_QUEUE_SIZE)
+ q->wptr = 0;
+ q->count++;
+ s->update_irq(s->update_arg, 1);
+}
+
+static void ps2_put_keycode(void *opaque, int keycode)
+{
+ PS2MouseState *s = opaque;
+ ps2_queue(&s->common, keycode);
+}
+
+uint32_t ps2_read_data(void *opaque)
+{
+ PS2State *s = (PS2State *)opaque;
+ PS2Queue *q;
+ int val, index;
+
+ q = &s->queue;
+ if (q->count == 0) {
+ /* NOTE: if no data left, we return the last keyboard one
+ (needed for EMM386) */
+ /* XXX: need a timer to do things correctly */
+ index = q->rptr - 1;
+ if (index < 0)
+ index = PS2_QUEUE_SIZE - 1;
+ val = q->data[index];
+ } else {
+ val = q->data[q->rptr];
+ if (++q->rptr == PS2_QUEUE_SIZE)
+ q->rptr = 0;
+ q->count--;
+ /* reading deasserts IRQ */
+ s->update_irq(s->update_arg, 0);
+ /* reassert IRQs if data left */
+ s->update_irq(s->update_arg, q->count != 0);
+ }
+ return val;
+}
+
+static void ps2_reset_keyboard(PS2KbdState *s)
+{
+ s->scan_enabled = 1;
+}
+
+void ps2_write_keyboard(void *opaque, int val)
+{
+ PS2KbdState *s = (PS2KbdState *)opaque;
+
+ switch(s->common.write_cmd) {
+ default:
+ case -1:
+ switch(val) {
+ case 0x00:
+ ps2_queue(&s->common, KBD_REPLY_ACK);
+ break;
+ case 0x05:
+ ps2_queue(&s->common, KBD_REPLY_RESEND);
+ break;
+ case KBD_CMD_GET_ID:
+ ps2_queue(&s->common, KBD_REPLY_ACK);
+ ps2_queue(&s->common, 0xab);
+ ps2_queue(&s->common, 0x83);
+ break;
+ case KBD_CMD_ECHO:
+ ps2_queue(&s->common, KBD_CMD_ECHO);
+ break;
+ case KBD_CMD_ENABLE:
+ s->scan_enabled = 1;
+ ps2_queue(&s->common, KBD_REPLY_ACK);
+ break;
+ case KBD_CMD_SET_LEDS:
+ case KBD_CMD_SET_RATE:
+ s->common.write_cmd = val;
+ ps2_queue(&s->common, KBD_REPLY_ACK);
+ break;
+ case KBD_CMD_RESET_DISABLE:
+ ps2_reset_keyboard(s);
+ s->scan_enabled = 0;
+ ps2_queue(&s->common, KBD_REPLY_ACK);
+ break;
+ case KBD_CMD_RESET_ENABLE:
+ ps2_reset_keyboard(s);
+ s->scan_enabled = 1;
+ ps2_queue(&s->common, KBD_REPLY_ACK);
+ break;
+ case KBD_CMD_RESET:
+ ps2_reset_keyboard(s);
+ ps2_queue(&s->common, KBD_REPLY_ACK);
+ ps2_queue(&s->common, KBD_REPLY_POR);
+ break;
+ default:
+ ps2_queue(&s->common, KBD_REPLY_ACK);
+ break;
+ }
+ break;
+ case KBD_CMD_SET_LEDS:
+ ps2_queue(&s->common, KBD_REPLY_ACK);
+ s->common.write_cmd = -1;
+ break;
+ case KBD_CMD_SET_RATE:
+ ps2_queue(&s->common, KBD_REPLY_ACK);
+ s->common.write_cmd = -1;
+ break;
+ }
+}
+
+static void ps2_mouse_send_packet(PS2MouseState *s)
+{
+ unsigned int b;
+ int dx1, dy1, dz1;
+
+ dx1 = s->mouse_dx;
+ dy1 = s->mouse_dy;
+ dz1 = s->mouse_dz;
+ /* XXX: increase range to 8 bits ? */
+ if (dx1 > 127)
+ dx1 = 127;
+ else if (dx1 < -127)
+ dx1 = -127;
+ if (dy1 > 127)
+ dy1 = 127;
+ else if (dy1 < -127)
+ dy1 = -127;
+ b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
+ ps2_queue(&s->common, b);
+ ps2_queue(&s->common, dx1 & 0xff);
+ ps2_queue(&s->common, dy1 & 0xff);
+ /* extra byte for IMPS/2 or IMEX */
+ switch(s->mouse_type) {
+ default:
+ break;
+ case 3:
+ if (dz1 > 127)
+ dz1 = 127;
+ else if (dz1 < -127)
+ dz1 = -127;
+ ps2_queue(&s->common, dz1 & 0xff);
+ break;
+ case 4:
+ if (dz1 > 7)
+ dz1 = 7;
+ else if (dz1 < -7)
+ dz1 = -7;
+ b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
+ ps2_queue(&s->common, b);
+ break;
+ }
+
+ /* update deltas */
+ s->mouse_dx -= dx1;
+ s->mouse_dy -= dy1;
+ s->mouse_dz -= dz1;
+}
+
+static void ps2_mouse_event(void *opaque,
+ int dx, int dy, int dz, int buttons_state)
+{
+ PS2MouseState *s = opaque;
+
+ /* check if deltas are recorded when disabled */
+ if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
+ return;
+
+ s->mouse_dx += dx;
+ s->mouse_dy -= dy;
+ s->mouse_dz += dz;
+ /* XXX: SDL sometimes generates nul events: we delete them */
+ if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
+ s->mouse_buttons == buttons_state)
+ return;
+ s->mouse_buttons = buttons_state;
+
+ if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
+ (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
+ for(;;) {
+ /* if not remote, send event. Multiple events are sent if
+ too big deltas */
+ ps2_mouse_send_packet(s);
+ if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
+ break;
+ }
+ }
+}
+
+void ps2_write_mouse(void *opaque, int val)
+{
+ PS2MouseState *s = (PS2MouseState *)opaque;
+#ifdef DEBUG_MOUSE
+ printf("kbd: write mouse 0x%02x\n", val);
+#endif
+ switch(s->common.write_cmd) {
+ default:
+ case -1:
+ /* mouse command */
+ if (s->mouse_wrap) {
+ if (val == AUX_RESET_WRAP) {
+ s->mouse_wrap = 0;
+ ps2_queue(&s->common, AUX_ACK);
+ return;
+ } else if (val != AUX_RESET) {
+ ps2_queue(&s->common, val);
+ return;
+ }
+ }
+ switch(val) {
+ case AUX_SET_SCALE11:
+ s->mouse_status &= ~MOUSE_STATUS_SCALE21;
+ ps2_queue(&s->common, AUX_ACK);
+ break;
+ case AUX_SET_SCALE21:
+ s->mouse_status |= MOUSE_STATUS_SCALE21;
+ ps2_queue(&s->common, AUX_ACK);
+ break;
+ case AUX_SET_STREAM:
+ s->mouse_status &= ~MOUSE_STATUS_REMOTE;
+ ps2_queue(&s->common, AUX_ACK);
+ break;
+ case AUX_SET_WRAP:
+ s->mouse_wrap = 1;
+ ps2_queue(&s->common, AUX_ACK);
+ break;
+ case AUX_SET_REMOTE:
+ s->mouse_status |= MOUSE_STATUS_REMOTE;
+ ps2_queue(&s->common, AUX_ACK);
+ break;
+ case AUX_GET_TYPE:
+ ps2_queue(&s->common, AUX_ACK);
+ ps2_queue(&s->common, s->mouse_type);
+ break;
+ case AUX_SET_RES:
+ case AUX_SET_SAMPLE:
+ s->common.write_cmd = val;
+ ps2_queue(&s->common, AUX_ACK);
+ break;
+ case AUX_GET_SCALE:
+ ps2_queue(&s->common, AUX_ACK);
+ ps2_queue(&s->common, s->mouse_status);
+ ps2_queue(&s->common, s->mouse_resolution);
+ ps2_queue(&s->common, s->mouse_sample_rate);
+ break;
+ case AUX_POLL:
+ ps2_queue(&s->common, AUX_ACK);
+ ps2_mouse_send_packet(s);
+ break;
+ case AUX_ENABLE_DEV:
+ s->mouse_status |= MOUSE_STATUS_ENABLED;
+ ps2_queue(&s->common, AUX_ACK);
+ break;
+ case AUX_DISABLE_DEV:
+ s->mouse_status &= ~MOUSE_STATUS_ENABLED;
+ ps2_queue(&s->common, AUX_ACK);
+ break;
+ case AUX_SET_DEFAULT:
+ s->mouse_sample_rate = 100;
+ s->mouse_resolution = 2;
+ s->mouse_status = 0;
+ ps2_queue(&s->common, AUX_ACK);
+ break;
+ case AUX_RESET:
+ s->mouse_sample_rate = 100;
+ s->mouse_resolution = 2;
+ s->mouse_status = 0;
+ s->mouse_type = 0;
+ ps2_queue(&s->common, AUX_ACK);
+ ps2_queue(&s->common, 0xaa);
+ ps2_queue(&s->common, s->mouse_type);
+ break;
+ default:
+ break;
+ }
+ break;
+ case AUX_SET_SAMPLE:
+ s->mouse_sample_rate = val;
+ /* detect IMPS/2 or IMEX */
+ switch(s->mouse_detect_state) {
+ default:
+ case 0:
+ if (val == 200)
+ s->mouse_detect_state = 1;
+ break;
+ case 1:
+ if (val == 100)
+ s->mouse_detect_state = 2;
+ else if (val == 200)
+ s->mouse_detect_state = 3;
+ else
+ s->mouse_detect_state = 0;
+ break;
+ case 2:
+ if (val == 80)
+ s->mouse_type = 3; /* IMPS/2 */
+ s->mouse_detect_state = 0;
+ break;
+ case 3:
+ if (val == 80)
+ s->mouse_type = 4; /* IMEX */
+ s->mouse_detect_state = 0;
+ break;
+ }
+ ps2_queue(&s->common, AUX_ACK);
+ s->common.write_cmd = -1;
+ break;
+ case AUX_SET_RES:
+ s->mouse_resolution = val;
+ ps2_queue(&s->common, AUX_ACK);
+ s->common.write_cmd = -1;
+ break;
+ }
+}
+
+static void ps2_reset(void *opaque)
+{
+ PS2State *s = (PS2State *)opaque;
+ PS2Queue *q;
+ s->write_cmd = -1;
+ q = &s->queue;
+ q->rptr = 0;
+ q->wptr = 0;
+ q->count = 0;
+}
+
+static void ps2_kbd_save(QEMUFile* f, void* opaque)
+{
+ PS2KbdState *s = (PS2KbdState*)opaque;
+
+ qemu_put_be32s(f, &s->common.write_cmd);
+ qemu_put_be32s(f, &s->scan_enabled);
+}
+
+static void ps2_mouse_save(QEMUFile* f, void* opaque)
+{
+ PS2MouseState *s = (PS2MouseState*)opaque;
+
+ qemu_put_be32s(f, &s->common.write_cmd);
+ qemu_put_8s(f, &s->mouse_status);
+ qemu_put_8s(f, &s->mouse_resolution);
+ qemu_put_8s(f, &s->mouse_sample_rate);
+ qemu_put_8s(f, &s->mouse_wrap);
+ qemu_put_8s(f, &s->mouse_type);
+ qemu_put_8s(f, &s->mouse_detect_state);
+ qemu_put_be32s(f, &s->mouse_dx);
+ qemu_put_be32s(f, &s->mouse_dy);
+ qemu_put_be32s(f, &s->mouse_dz);
+ qemu_put_8s(f, &s->mouse_buttons);
+}
+
+static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id)
+{
+ PS2KbdState *s = (PS2KbdState*)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+ qemu_get_be32s(f, &s->common.write_cmd);
+ qemu_get_be32s(f, &s->scan_enabled);
+ return 0;
+}
+
+static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id)
+{
+ PS2MouseState *s = (PS2MouseState*)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+ qemu_get_be32s(f, &s->common.write_cmd);
+ qemu_get_8s(f, &s->mouse_status);
+ qemu_get_8s(f, &s->mouse_resolution);
+ qemu_get_8s(f, &s->mouse_sample_rate);
+ qemu_get_8s(f, &s->mouse_wrap);
+ qemu_get_8s(f, &s->mouse_type);
+ qemu_get_8s(f, &s->mouse_detect_state);
+ qemu_get_be32s(f, &s->mouse_dx);
+ qemu_get_be32s(f, &s->mouse_dy);
+ qemu_get_be32s(f, &s->mouse_dz);
+ qemu_get_8s(f, &s->mouse_buttons);
+ return 0;
+}
+
+void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
+{
+ PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
+
+ s->common.update_irq = update_irq;
+ s->common.update_arg = update_arg;
+ ps2_reset(&s->common);
+ register_savevm("ps2kbd", 0, 1, ps2_kbd_save, ps2_kbd_load, s);
+ qemu_add_kbd_event_handler(ps2_put_keycode, s);
+ qemu_register_reset(ps2_reset, &s->common);
+ return s;
+}
+
+void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
+{
+ PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
+
+ s->common.update_irq = update_irq;
+ s->common.update_arg = update_arg;
+ ps2_reset(&s->common);
+ register_savevm("ps2mouse", 0, 1, ps2_mouse_save, ps2_mouse_load, s);
+ qemu_add_mouse_event_handler(ps2_mouse_event, s);
+ qemu_register_reset(ps2_reset, &s->common);
+ return s;
+}
^ permalink raw reply [flat|nested] 3+ messages in thread
* [Qemu-devel] Re: Arm system emulation
2005-11-22 2:31 [Qemu-devel] Arm system emulation Paul Brook
@ 2005-11-25 22:45 ` Antti P Miettinen
2005-11-25 23:13 ` Paul Brook
0 siblings, 1 reply; 3+ messages in thread
From: Antti P Miettinen @ 2005-11-25 22:45 UTC (permalink / raw)
To: qemu-devel
Paul Brook <paul@codesourcery.com> writes:
> The attached patch implements Arm system emulation.
Cool :-)
> There's nothing special about these. Just a vanilla 2.6.14 kernel configured
> with a serial console and busybox+bash from a Debian arm-linux install.
I checked out qemu from CVS, applied your patches and I can confirm
that after some tweaks with configuring qemu and getting the right
command line arguments I can indeed boot the sample kernel and image.
I also compiled linux 2.6.14.3 with a .config from the /proc/config.gz
of the sample kernel and the compiled kernel boots also fine.
While trying out gdb I ran into the same issue as reported by Johannes
Schindelin that cpu_single_env is cleared upon exiting cpu_exec(), but
e.g. breakpoint insertion ends up into tb_invalidate_phys_page_range()
which seems to assume that cpu_single_env is valid. Just commenting
out the clearing of cpu_single_env makes kernel debugging possible,
but I suppose that's not the right fix.
It seems that the sysemu is busylooping - is that currently to be
expected or do I have something misconfigured?
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Qemu-devel] Re: Arm system emulation
2005-11-25 22:45 ` [Qemu-devel] " Antti P Miettinen
@ 2005-11-25 23:13 ` Paul Brook
0 siblings, 0 replies; 3+ messages in thread
From: Paul Brook @ 2005-11-25 23:13 UTC (permalink / raw)
To: qemu-devel, ananaza
> It seems that the sysemu is busylooping - is that currently to be
> expected or do I have something misconfigured?
Yes. The Wait For Interrupt instruction (aka halt/suspend) is currently
implemented as a Nop. I have a followup patch to fix that.
Paul
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2005-11-25 23:21 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-11-22 2:31 [Qemu-devel] Arm system emulation Paul Brook
2005-11-25 22:45 ` [Qemu-devel] " Antti P Miettinen
2005-11-25 23:13 ` Paul Brook
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).